libssl patch available
11 March, 2015 by tedu@tedunangst.com | openbsd
When CVE-2015-0204 (RSA silently downgrades to EXPORT_RSA) was announced, it was labeled "Severity: Low". Our assessment at the time was that export ciphers had already been removed prior to the release of 5.6, and that the fix was not worth backporting to 5.5. Then CVE-2015-0204 was renamed the FREAK attack. Now it has a fancy name so you know it's important. Unfortunately, our original assessment was not entirely correct. Some of the features exploited by FREAK were not deleted until after 5.6, although this was not known until testing tools became available. We've corrected libssl by backporting the necessary changes to 5.6. The patch below includes the fix for CVE-2015-0204 as well as some other "low severity" fixes for similar downgrade issues relating to ECDHE. Statement regarding 5.5: SSL/TLS is hooped. There have been too many changes, large and small, that make backporting and testing indvidual fixes difficult. Additionally, many small fixes get overlooked. Thanks to Florian Riehm for pointing out that 5.6 was still vulnerable to FREAK. http://ftp.openbsd.org/pub/OpenBSD/patches/5.6/common/017_openssl.patch.sig untrusted comment: signature from openbsd 5.6 base private key RWR0EANmo9nqhpxHVrEZWmf2qAA9zblsetB0gpcMFrkMumxjVXGdcaRNHc7TS+IkdiYNDncAU2qjYSaM8bDI+nQp9HUayjp3RQQ OpenBSD 5.6 errata 17, Mar 13, 2015: Don't permit TLS client connections to be downgraded to weak keys. Apply by doing: cd /usr/src signify -Vep /etc/signify/openbsd-56-base.pub -x 017_openssl.patch.sig -m - | \ patch -p0 And then rebuild and install libssl: cd lib/libssl/ssl make obj make depend make make install Index: lib/libssl/src/ssl/d1_clnt.c =================================================================== RCS file: /cvs/src/lib/libssl/src/ssl/d1_clnt.c,v retrieving revision 1.33 diff -u -p -r1.33 d1_clnt.c --- lib/libssl/src/ssl/d1_clnt.c 7 Aug 2014 20:02:23 -0000 1.33 +++ lib/libssl/src/ssl/d1_clnt.c 10 Mar 2015 17:11:46 -0000 @@ -939,20 +939,16 @@ dtls1_send_client_key_exchange(SSL *s) RSA *rsa; unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH]; - if (s->session->sess_cert->peer_rsa_tmp != NULL) - rsa = s->session->sess_cert->peer_rsa_tmp; - else { - pkey = X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); - if ((pkey == NULL) || - (pkey->type != EVP_PKEY_RSA) || - (pkey->pkey.rsa == NULL)) { - SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - rsa = pkey->pkey.rsa; - EVP_PKEY_free(pkey); + pkey = X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); + if ((pkey == NULL) || + (pkey->type != EVP_PKEY_RSA) || + (pkey->pkey.rsa == NULL)) { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; } + rsa = pkey->pkey.rsa; + EVP_PKEY_free(pkey); tmp_buf[0] = s->client_version >> 8; tmp_buf[1] = s->client_version&0xff; Index: lib/libssl/src/ssl/s3_clnt.c =================================================================== RCS file: /cvs/src/lib/libssl/src/ssl/s3_clnt.c,v retrieving revision 1.85 diff -u -p -r1.85 s3_clnt.c --- lib/libssl/src/ssl/s3_clnt.c 7 Aug 2014 01:24:10 -0000 1.85 +++ lib/libssl/src/ssl/s3_clnt.c 10 Mar 2015 17:11:59 -0000 @@ -1162,6 +1162,9 @@ ssl3_get_key_exchange(SSL *s) int curve_nid = 0; int encoded_pt_len = 0; + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + alg_a = s->s3->tmp.new_cipher->algorithm_auth; + /* * Use same message size as in ssl3_get_certificate_request() * as ServerKeyExchange message may be skipped. @@ -1170,17 +1173,27 @@ ssl3_get_key_exchange(SSL *s) SSL3_ST_CR_KEY_EXCH_B, -1, s->max_cert_list, &ok); if (!ok) return ((int)n); + + EVP_MD_CTX_init(&md_ctx); if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) { + /* + * Do not skip server key exchange if this cipher suite uses + * ephemeral keys. + */ + if (alg_k & (SSL_kDHE|SSL_kECDHE)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_UNEXPECTED_MESSAGE); + al = SSL_AD_UNEXPECTED_MESSAGE; + goto f_err; + } + s->s3->tmp.reuse_message = 1; + EVP_MD_CTX_cleanup(&md_ctx); return (1); } - param = p = (unsigned char *)s->init_msg; if (s->session->sess_cert != NULL) { - RSA_free(s->session->sess_cert->peer_rsa_tmp); - s->session->sess_cert->peer_rsa_tmp = NULL; - DH_free(s->session->sess_cert->peer_dh_tmp); s->session->sess_cert->peer_dh_tmp = NULL; @@ -1192,68 +1205,10 @@ ssl3_get_key_exchange(SSL *s) goto err; } + param = p = (unsigned char *)s->init_msg; param_len = 0; - alg_k = s->s3->tmp.new_cipher->algorithm_mkey; - alg_a = s->s3->tmp.new_cipher->algorithm_auth; - EVP_MD_CTX_init(&md_ctx); - - if (alg_k & SSL_kRSA) { - if ((rsa = RSA_new()) == NULL) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } - if (2 > n) - goto truncated; - n2s(p, i); - param_len = i + 2; - if (param_len > n) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_BAD_RSA_MODULUS_LENGTH); - goto f_err; - } - if (!(rsa->n = BN_bin2bn(p, i, rsa->n))) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - ERR_R_BN_LIB); - goto err; - } - p += i; - if (param_len + 2 > n) - goto truncated; - n2s(p, i); - param_len += i + 2; - if (param_len > n) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_BAD_RSA_E_LENGTH); - goto f_err; - } - if (!(rsa->e = BN_bin2bn(p, i, rsa->e))) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - ERR_R_BN_LIB); - goto err; - } - p += i; - n -= param_len; - - /* - * This should be because we are using an - * export cipher - */ - if (alg_a & SSL_aRSA) - pkey = X509_get_pubkey( - s->session->sess_cert->peer_pkeys[ - SSL_PKEY_RSA_ENC].x509); - else { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - s->session->sess_cert->peer_rsa_tmp = rsa; - rsa = NULL; - } else if (alg_k & SSL_kDHE) { + if (alg_k & SSL_kDHE) { if ((dh = DH_new()) == NULL) { SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_DH_LIB); @@ -1311,6 +1266,17 @@ ssl3_get_key_exchange(SSL *s) p += i; n -= param_len; + /* + * Check the strength of the DH key just constructed. + * Discard keys weaker than 1024 bits. + */ + + if (DH_size(dh) < 1024 / 8) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_BAD_DH_P_LENGTH); + goto err; + } + if (alg_a & SSL_aRSA) pkey = X509_get_pubkey( s->session->sess_cert->peer_pkeys[ @@ -1953,23 +1919,19 @@ ssl3_send_client_key_exchange(SSL *s) goto err; } - if (s->session->sess_cert->peer_rsa_tmp != NULL) - rsa = s->session->sess_cert->peer_rsa_tmp; - else { - pkey = X509_get_pubkey( - s->session->sess_cert->peer_pkeys[ - SSL_PKEY_RSA_ENC].x509); - if ((pkey == NULL) || - (pkey->type != EVP_PKEY_RSA) || - (pkey->pkey.rsa == NULL)) { - SSLerr( - SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - rsa = pkey->pkey.rsa; + pkey = X509_get_pubkey( + s->session->sess_cert->peer_pkeys[ + SSL_PKEY_RSA_ENC].x509); + if ((pkey == NULL) || + (pkey->type != EVP_PKEY_RSA) || + (pkey->pkey.rsa == NULL)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); EVP_PKEY_free(pkey); + goto err; } + rsa = pkey->pkey.rsa; + EVP_PKEY_free(pkey); tmp_buf[0] = s->client_version >> 8; tmp_buf[1] = s->client_version & 0xff; @@ -2598,7 +2560,6 @@ ssl3_check_cert_and_algorithm(SSL *s) long alg_k, alg_a; EVP_PKEY *pkey = NULL; SESS_CERT *sc; - RSA *rsa; DH *dh; alg_k = s->s3->tmp.new_cipher->algorithm_mkey; @@ -2614,8 +2575,6 @@ ssl3_check_cert_and_algorithm(SSL *s) ERR_R_INTERNAL_ERROR); goto err; } - - rsa = s->session->sess_cert->peer_rsa_tmp; dh = s->session->sess_cert->peer_dh_tmp; /* This is the passed certificate. */ @@ -2648,7 +2607,7 @@ ssl3_check_cert_and_algorithm(SSL *s) goto f_err; } if ((alg_k & SSL_kRSA) && - !(has_bits(i, EVP_PK_RSA|EVP_PKT_ENC) || (rsa != NULL))) { + !has_bits(i, EVP_PK_RSA|EVP_PKT_ENC)) { SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_RSA_ENCRYPTING_CERT); goto f_err; Index: lib/libssl/src/ssl/ssl_cert.c =================================================================== RCS file: /cvs/src/lib/libssl/src/ssl/ssl_cert.c,v retrieving revision 1.41 diff -u -p -r1.41 ssl_cert.c --- lib/libssl/src/ssl/ssl_cert.c 10 Jul 2014 08:25:00 -0000 1.41 +++ lib/libssl/src/ssl/ssl_cert.c 10 Mar 2015 17:11:46 -0000 @@ -407,7 +407,6 @@ ssl_sess_cert_free(SESS_CERT *sc) X509_free(sc->peer_pkeys[i].x509); } - RSA_free(sc->peer_rsa_tmp); DH_free(sc->peer_dh_tmp); EC_KEY_free(sc->peer_ecdh_tmp); Index: lib/libssl/src/ssl/ssl_locl.h =================================================================== RCS file: /cvs/src/lib/libssl/src/ssl/ssl_locl.h,v retrieving revision 1.63 diff -u -p -r1.63 ssl_locl.h --- lib/libssl/src/ssl/ssl_locl.h 28 Jul 2014 04:23:12 -0000 1.63 +++ lib/libssl/src/ssl/ssl_locl.h 10 Mar 2015 17:11:46 -0000 @@ -464,7 +464,7 @@ typedef struct sess_cert_st { /* Obviously we don't have the private keys of these, * so maybe we shouldn't even use the CERT_PKEY type here. */ - RSA *peer_rsa_tmp; + RSA *__peer_rsa_tmp; DH *peer_dh_tmp; EC_KEY *peer_ecdh_tmp;