Skip to content

Commit

Permalink
Reduce the security bits for MD5 and SHA1 based signatures in TLS
Browse files Browse the repository at this point in the history
This has as effect that SHA1 and MD5+SHA1 are no longer supported at
security level 1, and that TLS < 1.2 is no longer supported at the
default security level of 1, and that you need to set the security
level to 0 to use TLS < 1.2.

Reviewed-by: Tim Hudson <tjh@openssl.org>
GH: #10787
  • Loading branch information
kroeckx committed Jun 27, 2020
1 parent 526f1f1 commit aba03ae
Show file tree
Hide file tree
Showing 21 changed files with 1,915 additions and 1,822 deletions.
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ OpenSSL 3.0

*Paul Dale*

* The security strength of SHA1 and MD5 based signatures in TLS has been
reduced. This results in SSL 3, TLS 1.0, TLS 1.1 and DTLS 1.0 no longer
working at the default security level of 1 and instead requires security
level 0. The security level can be changed either using the cipher string
with @SECLEVEL, or calling SSL_CTX_set_security_level().

*Kurt Roeckx*

* EVP_PKEY_get0_RSA(), EVP_PKEY_get0_DSA(), EVP_PKEY_get0_DH(), and
EVP_PKEY_get0_EC_KEY() can now handle EVP_PKEYs with provider side
internal keys, if they correspond to one of those built in types.
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ OpenSSL 3.0
RC4, RC5 and SEED cipher functions have been deprecated.
* All of the low level DH, DSA, ECDH, ECDSA and RSA public key functions
have been deprecated.
* SSL 3, TLS 1.0, TLS 1.1, and DTLS 1.0 only work at security level 0.

OpenSSL 1.1.1
-------------
Expand Down
18 changes: 18 additions & 0 deletions ssl/t1_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1413,8 +1413,26 @@ static int sigalg_security_bits(SSL_CTX *ctx, const SIGALG_LOOKUP *lu)
return 0;
if (md != NULL)
{
int md_type = EVP_MD_type(md);

/* Security bits: half digest bits */
secbits = EVP_MD_size(md) * 4;
/*
* SHA1 and MD5 are known to be broken. Reduce security bits so that
* they're no longer accepted at security level 1. The real values don't
* really matter as long as they're lower than 80, which is our
* security level 1.
* https://eprint.iacr.org/2020/014 puts a chosen-prefix attack for
* SHA1 at 2^63.4 and MD5+SHA1 at 2^67.2
* https://documents.epfl.ch/users/l/le/lenstra/public/papers/lat.pdf
* puts a chosen-prefix attack for MD5 at 2^39.
*/
if (md_type == NID_sha1)
secbits = 64;
else if (md_type == NID_md5_sha1)
secbits = 67;
else if (md_type == NID_md5)
secbits = 39;
} else {
/* Values from https://tools.ietf.org/html/rfc8032#section-8.5 */
if (lu->sigalg == TLSEXT_SIGALG_ed25519)
Expand Down
3 changes: 2 additions & 1 deletion test/recipes/70-test_renegotiation.t
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ SKIP: {
# handshake
$proxy->clear();
$proxy->filter(undef);
$proxy->clientflags("-no_tls1_3");
$proxy->ciphers("DEFAULT:\@SECLEVEL=0");
$proxy->clientflags("-no_tls1_3 -cipher AES128-SHA:\@SECLEVEL=0");
$proxy->serverflags("-no_tls1_3 -no_tls1_2");
$proxy->reneg(1);
$proxy->start();
Expand Down
1 change: 1 addition & 0 deletions test/recipes/70-test_sslextension.t
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ SKIP: {
#Test 3: Sending a zero length extension block should pass
$proxy->clear();
$proxy->filter(\&extension_filter);
$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
$proxy->start();
ok(TLSProxy::Message->success, "Zero extension length test");

Expand Down
13 changes: 12 additions & 1 deletion test/recipes/70-test_sslrecords.t
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,17 @@ use constant {
FRAGMENTED_IN_SSLV2 => 3,
ALERT_BEFORE_SSLV2 => 4
};

# The TLSv1.2 in SSLv2 ClientHello need to run at security level 0
# because in a SSLv2 ClientHello we can't send extentions to indicate
# which signature algorithm we want to use, and the default is SHA1.

#Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello
my $sslv2testtype = TLSV1_2_IN_SSLV2;
$proxy->clear();
$proxy->filter(\&add_sslv2_filter);
$proxy->serverflags("-tls1_2");
$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
$proxy->start();
ok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test");

Expand All @@ -96,6 +102,7 @@ ok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test");
$sslv2testtype = SSLV2_IN_SSLV2;
$proxy->clear();
$proxy->serverflags("-tls1_2");
$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
$proxy->start();
ok(TLSProxy::Message->fail(), "SSLv2 in SSLv2 ClientHello test");

Expand All @@ -105,6 +112,7 @@ ok(TLSProxy::Message->fail(), "SSLv2 in SSLv2 ClientHello test");
$sslv2testtype = FRAGMENTED_IN_TLSV1_2;
$proxy->clear();
$proxy->serverflags("-tls1_2");
$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
$proxy->start();
ok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test");

Expand All @@ -113,6 +121,7 @@ ok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test");
$sslv2testtype = FRAGMENTED_IN_SSLV2;
$proxy->clear();
$proxy->serverflags("-tls1_2");
$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
$proxy->start();
ok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test");

Expand All @@ -121,6 +130,7 @@ ok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test");
$sslv2testtype = ALERT_BEFORE_SSLV2;
$proxy->clear();
$proxy->serverflags("-tls1_2");
$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
$proxy->start();
ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");

Expand All @@ -140,7 +150,8 @@ SKIP: {
#Test 11: Sending an unrecognised record type in TLS1.1 should fail
$fatal_alert = 0;
$proxy->clear();
$proxy->clientflags("-tls1_1");
$proxy->clientflags("-tls1_1 -cipher DEFAULT:\@SECLEVEL=0");
$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
$proxy->start();
ok($fatal_alert, "Unrecognised record type in TLS1.1");
}
Expand Down
40 changes: 21 additions & 19 deletions test/recipes/70-test_sslsigalgs.t
Original file line number Diff line number Diff line change
Expand Up @@ -138,32 +138,32 @@ SKIP: {

$proxy->filter(\&sigalgs_filter);

#Test 10: Sending no sig algs extension in TLSv1.2 should succeed at
# security level 1
#Test 10: Sending no sig algs extension in TLSv1.2 will make it use
# SHA1, which is only supported at security level 0.
$proxy->clear();
$testtype = NO_SIG_ALGS_EXT;
$proxy->clientflags("-no_tls1_3 -cipher DEFAULT:\@SECLEVEL=1");
$proxy->ciphers("ECDHE-RSA-AES128-SHA:\@SECLEVEL=1");
$proxy->clientflags("-no_tls1_3 -cipher DEFAULT:\@SECLEVEL=0");
$proxy->ciphers("ECDHE-RSA-AES128-SHA:\@SECLEVEL=0");
$proxy->start();
ok(TLSProxy::Message->success, "No TLSv1.2 sigalgs seclevel 1");
ok(TLSProxy::Message->success, "No TLSv1.2 sigalgs seclevel 0");

#Test 11: Sending no sig algs extension in TLSv1.2 should fail at security
# level 2 since it will try to use SHA1. Testing client at level 1,
# server level 2.
# level 1 since it will try to use SHA1. Testing client at level 0,
# server level 1.
$proxy->clear();
$testtype = NO_SIG_ALGS_EXT;
$proxy->clientflags("-tls1_2 -cipher DEFAULT:\@SECLEVEL=1");
$proxy->ciphers("DEFAULT:\@SECLEVEL=2");
$proxy->clientflags("-tls1_2 -cipher DEFAULT:\@SECLEVEL=0");
$proxy->ciphers("DEFAULT:\@SECLEVEL=1");
$proxy->start();
ok(TLSProxy::Message->fail, "No TLSv1.2 sigalgs server seclevel 2");
ok(TLSProxy::Message->fail, "No TLSv1.2 sigalgs server seclevel 1");

#Test 12: Sending no sig algs extension in TLSv1.2 should fail at security
# level 2 since it will try to use SHA1. Testing client at level 2,
# server level 1.
# level 1 since it will try to use SHA1. Testing client at level 1,
# server level 0.
$proxy->clear();
$testtype = NO_SIG_ALGS_EXT;
$proxy->clientflags("-tls1_2 -cipher DEFAULT:\@SECLEVEL=2");
$proxy->ciphers("DEFAULT:\@SECLEVEL=1");
$proxy->clientflags("-tls1_2 -cipher DEFAULT:\@SECLEVEL=1");
$proxy->ciphers("DEFAULT:\@SECLEVEL=0");
$proxy->start();
ok(TLSProxy::Message->fail, "No TLSv1.2 sigalgs client seclevel 2");

Expand Down Expand Up @@ -221,15 +221,16 @@ SKIP: {
ok(TLSProxy::Message->fail, "No matching TLSv1.2 sigalgs");
$proxy->filter(\&sigalgs_filter);

#Test 19: No sig algs extension, ECDSA cert, TLSv1.2 should succeed
#Test 19: No sig algs extension, ECDSA cert, will use SHA1,
# TLSv1.2 should succeed at security level 0
$proxy->clear();
$testtype = NO_SIG_ALGS_EXT;
$proxy->clientflags("-no_tls1_3");
$proxy->clientflags("-no_tls1_3 -cipher DEFAULT:\@SECLEVEL=0");
$proxy->serverflags("-cert " . srctop_file("test", "certs",
"server-ecdsa-cert.pem") .
" -key " . srctop_file("test", "certs",
"server-ecdsa-key.pem")),
$proxy->ciphers("ECDHE-ECDSA-AES128-SHA");
$proxy->ciphers("ECDHE-ECDSA-AES128-SHA:\@SECLEVEL=0");
$proxy->start();
ok(TLSProxy::Message->success, "No TLSv1.2 sigalgs, ECDSA");
}
Expand All @@ -245,18 +246,19 @@ SKIP: {
$proxy->filter(\&modify_sigalgs_filter);
$proxy->start();
ok($dsa_status && $sha1_status && $sha224_status,
"DSA/SHA2 sigalg sent for 1.3-only ClientHello");
"DSA and SHA1 sigalgs not sent for 1.3-only ClientHello");

#Test 21: signature_algorithms with backwards compatible ClientHello
SKIP: {
skip "TLSv1.2 disabled", 1 if disabled("tls1_2");
$testtype = COMPAT_SIGALGS;
$dsa_status = $sha1_status = $sha224_status = 0;
$proxy->clear();
$proxy->clientflags("-cipher AES128-SHA\@SECLEVEL=0");
$proxy->filter(\&modify_sigalgs_filter);
$proxy->start();
ok($dsa_status && $sha1_status && $sha224_status,
"DSA sigalg not sent for compat ClientHello");
"backwards compatible sigalg sent for compat ClientHello");
}
}

Expand Down
2 changes: 2 additions & 0 deletions test/recipes/70-test_sslversions.t
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ ok(TLSProxy::Message->success()
#Test 6: no TLSv1.3 or TLSv1.2 version in supported versions extension, but
#TLSv1.1 and TLSv1.0 are present. Should just use TLSv1.1 and succeed
$proxy->clear();
$proxy->clientflags("-cipher DEFAULT:\@SECLEVEL=0");
$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
$testtype = TLS1_1_AND_1_0_ONLY;
$proxy->start();
$record = pop @{$proxy->record_list};
Expand Down
1 change: 1 addition & 0 deletions test/recipes/70-test_tls13downgrade.t
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ SKIP: {
$proxy->clear();
$proxy->filter(undef);
$proxy->clientflags("-no_tls1_2");
$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
$proxy->start();
ok(TLSProxy::Message->success(), "TLSv1.2 client-side protocol hole");

Expand Down
Loading

0 comments on commit aba03ae

Please sign in to comment.