summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmilia Kasper <emilia@openssl.org>2015-03-04 09:05:02 -0800
committerMatt Caswell <matt@openssl.org>2015-03-19 12:58:35 +0000
commit86f8fb0e344d62454f8daf3e15236b2b59210756 (patch)
tree60dfd04aea8199ad46fe8121794a334fef21d9aa
parentc0334c2c92dd1bc3ad8138ba6e74006c3631b0f9 (diff)
Fix reachable assert in SSLv2 servers.
This assert is reachable for servers that support SSLv2 and export ciphers. Therefore, such servers can be DoSed by sending a specially crafted SSLv2 CLIENT-MASTER-KEY. Also fix s2_srvr.c to error out early if the key lengths are malformed. These lengths are sent unencrypted, so this does not introduce an oracle. CVE-2015-0293 This issue was discovered by Sean Burford (Google) and Emilia Käsper of the OpenSSL development team. Reviewed-by: Richard Levitte <levitte@openssl.org> Reviewed-by: Tim Hudson <tjh@openssl.org>
-rw-r--r--ssl/s2_lib.c2
-rw-r--r--ssl/s2_srvr.c57
2 files changed, 46 insertions, 13 deletions
diff --git a/ssl/s2_lib.c b/ssl/s2_lib.c
index f8a9439303..d55b93f76b 100644
--- a/ssl/s2_lib.c
+++ b/ssl/s2_lib.c
@@ -493,7 +493,7 @@ int ssl2_generate_key_material(SSL *s)
OPENSSL_assert(s->session->master_key_length >= 0
&& s->session->master_key_length
- < (int)sizeof(s->session->master_key));
+ <= (int)sizeof(s->session->master_key));
EVP_DigestUpdate(&ctx, s->session->master_key,
s->session->master_key_length);
EVP_DigestUpdate(&ctx, &c, 1);
diff --git a/ssl/s2_srvr.c b/ssl/s2_srvr.c
index daba6dd7ad..4046697b26 100644
--- a/ssl/s2_srvr.c
+++ b/ssl/s2_srvr.c
@@ -454,11 +454,6 @@ static int get_client_master_key(SSL *s)
SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_NO_PRIVATEKEY);
return (-1);
}
- i = ssl_rsa_private_decrypt(s->cert, s->s2->tmp.enc,
- &(p[s->s2->tmp.clear]),
- &(p[s->s2->tmp.clear]),
- (s->s2->ssl2_rollback) ? RSA_SSLV23_PADDING :
- RSA_PKCS1_PADDING);
is_export = SSL_C_IS_EXPORT(s->session->cipher);
@@ -475,23 +470,61 @@ static int get_client_master_key(SSL *s)
} else
ek = 5;
+ /*
+ * The format of the CLIENT-MASTER-KEY message is
+ * 1 byte message type
+ * 3 bytes cipher
+ * 2-byte clear key length (stored in s->s2->tmp.clear)
+ * 2-byte encrypted key length (stored in s->s2->tmp.enc)
+ * 2-byte key args length (IV etc)
+ * clear key
+ * encrypted key
+ * key args
+ *
+ * If the cipher is an export cipher, then the encrypted key bytes
+ * are a fixed portion of the total key (5 or 8 bytes). The size of
+ * this portion is in |ek|. If the cipher is not an export cipher,
+ * then the entire key material is encrypted (i.e., clear key length
+ * must be zero).
+ */
+ if ((!is_export && s->s2->tmp.clear != 0) ||
+ (is_export && s->s2->tmp.clear + ek != EVP_CIPHER_key_length(c))) {
+ ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_LENGTH);
+ return -1;
+ }
+ /*
+ * The encrypted blob must decrypt to the encrypted portion of the key.
+ * Decryption can't be expanding, so if we don't have enough encrypted
+ * bytes to fit the key in the buffer, stop now.
+ */
+ if ((is_export && s->s2->tmp.enc < ek) ||
+ (!is_export && s->s2->tmp.enc < EVP_CIPHER_key_length(c))) {
+ ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+ SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_LENGTH_TOO_SHORT);
+ return -1;
+ }
+
+ i = ssl_rsa_private_decrypt(s->cert, s->s2->tmp.enc,
+ &(p[s->s2->tmp.clear]),
+ &(p[s->s2->tmp.clear]),
+ (s->s2->ssl2_rollback) ? RSA_SSLV23_PADDING :
+ RSA_PKCS1_PADDING);
+
/* bad decrypt */
# if 1
/*
* If a bad decrypt, continue with protocol but with a random master
* secret (Bleichenbacher attack)
*/
- if ((i < 0) || ((!is_export && (i != EVP_CIPHER_key_length(c)))
- || (is_export && ((i != ek)
- || (s->s2->tmp.clear +
- (unsigned int)i != (unsigned int)
- EVP_CIPHER_key_length(c)))))) {
+ if ((i < 0) || ((!is_export && i != EVP_CIPHER_key_length(c))
+ || (is_export && i != ek))) {
ERR_clear_error();
if (is_export)
i = ek;
else
i = EVP_CIPHER_key_length(c);
- if (RAND_pseudo_bytes(p, i) <= 0)
+ if (RAND_pseudo_bytes(&p[s->s2->tmp.clear], i) <= 0)
return 0;
}
# else
@@ -513,7 +546,7 @@ static int get_client_master_key(SSL *s)
# endif
if (is_export)
- i += s->s2->tmp.clear;
+ i = EVP_CIPHER_key_length(c);
if (i > SSL_MAX_MASTER_KEY_LENGTH) {
ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);