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
/*
* 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
* 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;
int pkeyid = EVP_PKEY_id(pkey);
const SIGALG_LOOKUP *lu;
int secbits = 0;
/* Should never happen */
if (pkeyid == -1)
@ -1189,20 +1215,20 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey)
SSL_R_UNKNOWN_DIGEST);
return 0;
}
if (md != NULL) {
/*
* Make sure security callback allows algorithm. For historical
* reasons we have to pass the sigalg as a two byte char array.
*/
sigalgstr[0] = (sig >> 8) & 0xff;
sigalgstr[1] = sig & 0xff;
if (!ssl_security(s, SSL_SECOP_SIGALG_CHECK,
EVP_MD_size(md) * 4, EVP_MD_type(md),
(void *)sigalgstr)) {
SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS12_CHECK_PEER_SIGALG,
SSL_R_WRONG_SIGNATURE_TYPE);
return 0;
}
/*
* Make sure security callback allows algorithm. For historical
* reasons we have to pass the sigalg as a two byte char array.
*/
sigalgstr[0] = (sig >> 8) & 0xff;
sigalgstr[1] = sig & 0xff;
secbits = sigalg_security_bits(s->ctx, lu);
if (secbits == 0 ||
!ssl_security(s, SSL_SECOP_SIGALG_CHECK, secbits,
md != NULL ? EVP_MD_type(md) : NID_undef,
(void *)sigalgstr)) {
SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS12_CHECK_PEER_SIGALG,
SSL_R_WRONG_SIGNATURE_TYPE);
return 0;
}
/* Store the sigalg the peer uses */
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 */
secbits = sigalg_security_bits(s->ctx, lu);
sigalgstr[0] = (lu->sigalg >> 8) & 0xff;
sigalgstr[1] = lu->sigalg & 0xff;
return ssl_security(s, op, secbits, lu->hash, (void *)sigalgstr);

View File

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

View File

@ -23,13 +23,38 @@ our @tests = (
our @tests_ec = (
{
name => "SECLEVEL 3 with ED448 key",
server => { "CipherString" => "DEFAULT:\@SECLEVEL=3",
name => "SECLEVEL 4 with ED448 key",
server => { "CipherString" => "DEFAULT:\@SECLEVEL=4",
"Certificate" => test_pem("server-ed448-cert.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" },
},
{
# 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",
server => { "CipherString" => "DEFAULT:\@SECLEVEL=3",