Check that ed25519 and ed448 are allowed by the security level

Signature algorithms not using an MD weren't checked that they're
allowed by the security level.

Reviewed-by: Matt Caswell <matt@openssl.org>
GH: #10785
This commit is contained in:
Kurt Roeckx 2020-02-09 19:28:15 +01:00
parent 77c4d39724
commit 620c97b671
3 changed files with 146 additions and 50 deletions

View File

@ -1075,6 +1075,31 @@ int tls_check_sigalg_curve(const SSL *s, int curve)
} }
#endif #endif
/*
* Return the number of security bits for the signature algorithm, or 0 on
* error.
*/
static int sigalg_security_bits(SSL_CTX *ctx, const SIGALG_LOOKUP *lu)
{
const EVP_MD *md = NULL;
int secbits = 0;
if (!tls1_lookup_md(ctx, lu, &md))
return 0;
if (md != NULL)
{
/* Security bits: half digest bits */
secbits = EVP_MD_size(md) * 4;
} else {
/* Values from https://tools.ietf.org/html/rfc8032#section-8.5 */
if (lu->sigalg == TLSEXT_SIGALG_ed25519)
secbits = 128;
else if (lu->sigalg == TLSEXT_SIGALG_ed448)
secbits = 224;
}
return secbits;
}
/* /*
* Check signature algorithm is consistent with sent supported signature * Check signature algorithm is consistent with sent supported signature
* algorithms and if so set relevant digest and signature scheme in * algorithms and if so set relevant digest and signature scheme in
@ -1088,6 +1113,7 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey)
size_t sent_sigslen, i, cidx; size_t sent_sigslen, i, cidx;
int pkeyid = EVP_PKEY_id(pkey); int pkeyid = EVP_PKEY_id(pkey);
const SIGALG_LOOKUP *lu; const SIGALG_LOOKUP *lu;
int secbits = 0;
/* Should never happen */ /* Should never happen */
if (pkeyid == -1) if (pkeyid == -1)
@ -1189,20 +1215,20 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey)
SSL_R_UNKNOWN_DIGEST); SSL_R_UNKNOWN_DIGEST);
return 0; return 0;
} }
if (md != NULL) { /*
/* * Make sure security callback allows algorithm. For historical
* Make sure security callback allows algorithm. For historical * reasons we have to pass the sigalg as a two byte char array.
* reasons we have to pass the sigalg as a two byte char array. */
*/ sigalgstr[0] = (sig >> 8) & 0xff;
sigalgstr[0] = (sig >> 8) & 0xff; sigalgstr[1] = sig & 0xff;
sigalgstr[1] = sig & 0xff; secbits = sigalg_security_bits(s->ctx, lu);
if (!ssl_security(s, SSL_SECOP_SIGALG_CHECK, if (secbits == 0 ||
EVP_MD_size(md) * 4, EVP_MD_type(md), !ssl_security(s, SSL_SECOP_SIGALG_CHECK, secbits,
(void *)sigalgstr)) { md != NULL ? EVP_MD_type(md) : NID_undef,
SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS12_CHECK_PEER_SIGALG, (void *)sigalgstr)) {
SSL_R_WRONG_SIGNATURE_TYPE); SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS12_CHECK_PEER_SIGALG,
return 0; SSL_R_WRONG_SIGNATURE_TYPE);
} return 0;
} }
/* Store the sigalg the peer uses */ /* Store the sigalg the peer uses */
s->s3.tmp.peer_sigalg = lu; s->s3.tmp.peer_sigalg = lu;
@ -1726,11 +1752,8 @@ static int tls12_sigalg_allowed(const SSL *s, int op, const SIGALG_LOOKUP *lu)
} }
} }
if (lu->hash == NID_undef)
return 1;
/* Security bits: half digest bits */
secbits = EVP_MD_size(ssl_md(s->ctx, lu->hash_idx)) * 4;
/* Finally see if security callback allows it */ /* Finally see if security callback allows it */
secbits = sigalg_security_bits(s->ctx, lu);
sigalgstr[0] = (lu->sigalg >> 8) & 0xff; sigalgstr[0] = (lu->sigalg >> 8) & 0xff;
sigalgstr[1] = lu->sigalg & 0xff; sigalgstr[1] = lu->sigalg & 0xff;
return ssl_security(s, op, secbits, lu->hash, (void *)sigalgstr); return ssl_security(s, op, secbits, lu->hash, (void *)sigalgstr);

View File

@ -1,11 +1,13 @@
# Generated with generate_ssl_tests.pl # Generated with generate_ssl_tests.pl
num_tests = 4 num_tests = 6
test-0 = 0-SECLEVEL 3 with default key test-0 = 0-SECLEVEL 3 with default key
test-1 = 1-SECLEVEL 3 with ED448 key test-1 = 1-SECLEVEL 4 with ED448 key
test-2 = 2-SECLEVEL 3 with P-384 key, X25519 ECDHE test-2 = 2-SECLEVEL 5 server with ED448 key
test-3 = 3-SECLEVEL 3 with ED448 key, TLSv1.2 test-3 = 3-SECLEVEL 5 client with ED448 key
test-4 = 4-SECLEVEL 3 with P-384 key, X25519 ECDHE
test-5 = 5-SECLEVEL 3 with ED448 key, TLSv1.2
# =========================================================== # ===========================================================
[0-SECLEVEL 3 with default key] [0-SECLEVEL 3 with default key]
@ -31,20 +33,20 @@ ExpectedResult = ServerFail
# =========================================================== # ===========================================================
[1-SECLEVEL 3 with ED448 key] [1-SECLEVEL 4 with ED448 key]
ssl_conf = 1-SECLEVEL 3 with ED448 key-ssl ssl_conf = 1-SECLEVEL 4 with ED448 key-ssl
[1-SECLEVEL 3 with ED448 key-ssl] [1-SECLEVEL 4 with ED448 key-ssl]
server = 1-SECLEVEL 3 with ED448 key-server server = 1-SECLEVEL 4 with ED448 key-server
client = 1-SECLEVEL 3 with ED448 key-client client = 1-SECLEVEL 4 with ED448 key-client
[1-SECLEVEL 3 with ED448 key-server] [1-SECLEVEL 4 with ED448 key-server]
Certificate = ${ENV::TEST_CERTS_DIR}/server-ed448-cert.pem Certificate = ${ENV::TEST_CERTS_DIR}/server-ed448-cert.pem
CipherString = DEFAULT:@SECLEVEL=3 CipherString = DEFAULT:@SECLEVEL=4
PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed448-key.pem PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed448-key.pem
[1-SECLEVEL 3 with ED448 key-client] [1-SECLEVEL 4 with ED448 key-client]
CipherString = DEFAULT CipherString = DEFAULT:@SECLEVEL=4
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-ed448-cert.pem VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-ed448-cert.pem
VerifyMode = Peer VerifyMode = Peer
@ -54,49 +56,95 @@ ExpectedResult = Success
# =========================================================== # ===========================================================
[2-SECLEVEL 3 with P-384 key, X25519 ECDHE] [2-SECLEVEL 5 server with ED448 key]
ssl_conf = 2-SECLEVEL 3 with P-384 key, X25519 ECDHE-ssl ssl_conf = 2-SECLEVEL 5 server with ED448 key-ssl
[2-SECLEVEL 3 with P-384 key, X25519 ECDHE-ssl] [2-SECLEVEL 5 server with ED448 key-ssl]
server = 2-SECLEVEL 3 with P-384 key, X25519 ECDHE-server server = 2-SECLEVEL 5 server with ED448 key-server
client = 2-SECLEVEL 3 with P-384 key, X25519 ECDHE-client client = 2-SECLEVEL 5 server with ED448 key-client
[2-SECLEVEL 3 with P-384 key, X25519 ECDHE-server] [2-SECLEVEL 5 server with ED448 key-server]
Certificate = ${ENV::TEST_CERTS_DIR}/server-ed448-cert.pem
CipherString = DEFAULT:@SECLEVEL=5
PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed448-key.pem
[2-SECLEVEL 5 server with ED448 key-client]
CipherString = DEFAULT:@SECLEVEL=4
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-ed448-cert.pem
VerifyMode = Peer
[test-2]
ExpectedResult = ServerFail
# ===========================================================
[3-SECLEVEL 5 client with ED448 key]
ssl_conf = 3-SECLEVEL 5 client with ED448 key-ssl
[3-SECLEVEL 5 client with ED448 key-ssl]
server = 3-SECLEVEL 5 client with ED448 key-server
client = 3-SECLEVEL 5 client with ED448 key-client
[3-SECLEVEL 5 client with ED448 key-server]
Certificate = ${ENV::TEST_CERTS_DIR}/server-ed448-cert.pem
CipherString = DEFAULT:@SECLEVEL=4
PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed448-key.pem
[3-SECLEVEL 5 client with ED448 key-client]
CipherString = DEFAULT:@SECLEVEL=5
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-ed448-cert.pem
VerifyMode = Peer
[test-3]
ExpectedResult = ServerFail
# ===========================================================
[4-SECLEVEL 3 with P-384 key, X25519 ECDHE]
ssl_conf = 4-SECLEVEL 3 with P-384 key, X25519 ECDHE-ssl
[4-SECLEVEL 3 with P-384 key, X25519 ECDHE-ssl]
server = 4-SECLEVEL 3 with P-384 key, X25519 ECDHE-server
client = 4-SECLEVEL 3 with P-384 key, X25519 ECDHE-client
[4-SECLEVEL 3 with P-384 key, X25519 ECDHE-server]
Certificate = ${ENV::TEST_CERTS_DIR}/p384-server-cert.pem Certificate = ${ENV::TEST_CERTS_DIR}/p384-server-cert.pem
CipherString = DEFAULT:@SECLEVEL=3 CipherString = DEFAULT:@SECLEVEL=3
Groups = X25519 Groups = X25519
PrivateKey = ${ENV::TEST_CERTS_DIR}/p384-server-key.pem PrivateKey = ${ENV::TEST_CERTS_DIR}/p384-server-key.pem
[2-SECLEVEL 3 with P-384 key, X25519 ECDHE-client] [4-SECLEVEL 3 with P-384 key, X25519 ECDHE-client]
CipherString = ECDHE:@SECLEVEL=3 CipherString = ECDHE:@SECLEVEL=3
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/p384-root.pem VerifyCAFile = ${ENV::TEST_CERTS_DIR}/p384-root.pem
VerifyMode = Peer VerifyMode = Peer
[test-2] [test-4]
ExpectedResult = Success ExpectedResult = Success
# =========================================================== # ===========================================================
[3-SECLEVEL 3 with ED448 key, TLSv1.2] [5-SECLEVEL 3 with ED448 key, TLSv1.2]
ssl_conf = 3-SECLEVEL 3 with ED448 key, TLSv1.2-ssl ssl_conf = 5-SECLEVEL 3 with ED448 key, TLSv1.2-ssl
[3-SECLEVEL 3 with ED448 key, TLSv1.2-ssl] [5-SECLEVEL 3 with ED448 key, TLSv1.2-ssl]
server = 3-SECLEVEL 3 with ED448 key, TLSv1.2-server server = 5-SECLEVEL 3 with ED448 key, TLSv1.2-server
client = 3-SECLEVEL 3 with ED448 key, TLSv1.2-client client = 5-SECLEVEL 3 with ED448 key, TLSv1.2-client
[3-SECLEVEL 3 with ED448 key, TLSv1.2-server] [5-SECLEVEL 3 with ED448 key, TLSv1.2-server]
Certificate = ${ENV::TEST_CERTS_DIR}/server-ed448-cert.pem Certificate = ${ENV::TEST_CERTS_DIR}/server-ed448-cert.pem
CipherString = DEFAULT:@SECLEVEL=3 CipherString = DEFAULT:@SECLEVEL=3
MaxProtocol = TLSv1.2 MaxProtocol = TLSv1.2
PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed448-key.pem PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed448-key.pem
[3-SECLEVEL 3 with ED448 key, TLSv1.2-client] [5-SECLEVEL 3 with ED448 key, TLSv1.2-client]
CipherString = DEFAULT CipherString = DEFAULT
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-ed448-cert.pem VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-ed448-cert.pem
VerifyMode = Peer VerifyMode = Peer
[test-3] [test-5]
ExpectedResult = Success ExpectedResult = Success

View File

@ -23,13 +23,38 @@ our @tests = (
our @tests_ec = ( our @tests_ec = (
{ {
name => "SECLEVEL 3 with ED448 key", name => "SECLEVEL 4 with ED448 key",
server => { "CipherString" => "DEFAULT:\@SECLEVEL=3", server => { "CipherString" => "DEFAULT:\@SECLEVEL=4",
"Certificate" => test_pem("server-ed448-cert.pem"), "Certificate" => test_pem("server-ed448-cert.pem"),
"PrivateKey" => test_pem("server-ed448-key.pem") }, "PrivateKey" => test_pem("server-ed448-key.pem") },
client => { "VerifyCAFile" => test_pem("root-ed448-cert.pem") }, client => { "CipherString" => "DEFAULT:\@SECLEVEL=4",
"VerifyCAFile" => test_pem("root-ed448-cert.pem") },
test => { "ExpectedResult" => "Success" }, test => { "ExpectedResult" => "Success" },
}, },
{
# The Ed488 signature algorithm will not be enabled.
# Because of the config order, the certificate is first loaded, and
# then the security level is chaged. If you try this with s_server
# the order will be reversed and it will instead fail to load the key.
name => "SECLEVEL 5 server with ED448 key",
server => { "CipherString" => "DEFAULT:\@SECLEVEL=5",
"Certificate" => test_pem("server-ed448-cert.pem"),
"PrivateKey" => test_pem("server-ed448-key.pem") },
client => { "CipherString" => "DEFAULT:\@SECLEVEL=4",
"VerifyCAFile" => test_pem("root-ed448-cert.pem") },
test => { "ExpectedResult" => "ServerFail" },
},
{
# The client will not sent the Ed488 signature algorithm, so the server
# doesn't have a useable signature algorithm for the certificate.
name => "SECLEVEL 5 client with ED448 key",
server => { "CipherString" => "DEFAULT:\@SECLEVEL=4",
"Certificate" => test_pem("server-ed448-cert.pem"),
"PrivateKey" => test_pem("server-ed448-key.pem") },
client => { "CipherString" => "DEFAULT:\@SECLEVEL=5",
"VerifyCAFile" => test_pem("root-ed448-cert.pem") },
test => { "ExpectedResult" => "ServerFail" },
},
{ {
name => "SECLEVEL 3 with P-384 key, X25519 ECDHE", name => "SECLEVEL 3 with P-384 key, X25519 ECDHE",
server => { "CipherString" => "DEFAULT:\@SECLEVEL=3", server => { "CipherString" => "DEFAULT:\@SECLEVEL=3",