From 26c79d5641dcc85c666e0594c11663c00ec6c195 Mon Sep 17 00:00:00 2001 From: Kurt Roeckx Date: Sat, 18 Apr 2015 12:23:12 +0200 Subject: [PATCH] Properly check certificate in case of export ciphers. Reviewed-by: Matt Caswell MR #588 --- crypto/dh/dh_lib.c | 5 ++++ crypto/rsa/rsa_crpt.c | 5 ++++ doc/crypto/DH_size.pod | 20 ++++++++++----- doc/crypto/RSA_size.pod | 19 +++++++++----- doc/crypto/dh.pod | 2 -- doc/crypto/rsa.pod | 2 -- include/openssl/dh.h | 1 + include/openssl/rsa.h | 1 + ssl/s3_clnt.c | 57 +++++++++++++++++++++++++++++++---------- util/libeay.num | 2 ++ 10 files changed, 82 insertions(+), 32 deletions(-) diff --git a/crypto/dh/dh_lib.c b/crypto/dh/dh_lib.c index 4a37adc9f8..cce2514bbf 100644 --- a/crypto/dh/dh_lib.c +++ b/crypto/dh/dh_lib.c @@ -237,6 +237,11 @@ void *DH_get_ex_data(DH *d, int idx) return (CRYPTO_get_ex_data(&d->ex_data, idx)); } +int DH_bits(const DH *dh) +{ + return BN_num_bits(dh->p); +} + int DH_size(const DH *dh) { return (BN_num_bytes(dh->p)); diff --git a/crypto/rsa/rsa_crpt.c b/crypto/rsa/rsa_crpt.c index 5220b7d068..3c4fd67714 100644 --- a/crypto/rsa/rsa_crpt.c +++ b/crypto/rsa/rsa_crpt.c @@ -64,6 +64,11 @@ #include #include +int RSA_bits(const RSA *r) +{ + return (BN_num_bits(r->n)); +} + int RSA_size(const RSA *r) { return (BN_num_bytes(r->n)); diff --git a/doc/crypto/DH_size.pod b/doc/crypto/DH_size.pod index 97f26fda78..e73f32589a 100644 --- a/doc/crypto/DH_size.pod +++ b/doc/crypto/DH_size.pod @@ -2,32 +2,38 @@ =head1 NAME -DH_size - get Diffie-Hellman prime size +DH_size, DH_bits - get Diffie-Hellman prime size =head1 SYNOPSIS - #include +#include - int DH_size(DH *dh); +int DH_size(const DH *dh); + +int DH_bits(const DH *dh); =head1 DESCRIPTION -This function returns the Diffie-Hellman size in bytes. It can be used +DH_size() returns the Diffie-Hellman prime size in bytes. It can be used to determine how much memory must be allocated for the shared secret computed by DH_compute_key(). -Bp> must not be B. +DH_bits() returns the number of significant bits. + +B and Bp> must not be B. =head1 RETURN VALUE -The size in bytes. +The size. =head1 SEE ALSO -L, L +L, L, +L =head1 HISTORY DH_size() is available in all versions of SSLeay and OpenSSL. +DH_bits() was added in OpenSSL 1.1.0. =cut diff --git a/doc/crypto/RSA_size.pod b/doc/crypto/RSA_size.pod index 5b7f835f95..f68d5e8e3c 100644 --- a/doc/crypto/RSA_size.pod +++ b/doc/crypto/RSA_size.pod @@ -2,32 +2,37 @@ =head1 NAME -RSA_size - get RSA modulus size +RSA_size, RSA_bits - get RSA modulus size =head1 SYNOPSIS - #include +#include - int RSA_size(const RSA *rsa); +int RSA_size(const RSA *rsa); + +int RSA_bits(const RSA *rsa); =head1 DESCRIPTION -This function returns the RSA modulus size in bytes. It can be used to +RSA_size() returns the RSA modulus size in bytes. It can be used to determine how much memory must be allocated for an RSA encrypted value. -Bn> must not be B. +RSA_bits() returns the number of significant bits. + +B and Bn> must not be B. =head1 RETURN VALUE -The size in bytes. +The size. =head1 SEE ALSO -L +L, L =head1 HISTORY RSA_size() is available in all versions of SSLeay and OpenSSL. +RSA_bits() was added in OpenSSL 1.1.0. =cut diff --git a/doc/crypto/dh.pod b/doc/crypto/dh.pod index c3ccd06207..1c8a327458 100644 --- a/doc/crypto/dh.pod +++ b/doc/crypto/dh.pod @@ -12,8 +12,6 @@ dh - Diffie-Hellman key agreement DH * DH_new(void); void DH_free(DH *dh); - int DH_size(const DH *dh); - DH * DH_generate_parameters(int prime_len, int generator, void (*callback)(int, int, void *), void *cb_arg); int DH_check(const DH *dh, int *codes); diff --git a/doc/crypto/rsa.pod b/doc/crypto/rsa.pod index 45ac53ffc1..743334ff79 100644 --- a/doc/crypto/rsa.pod +++ b/doc/crypto/rsa.pod @@ -26,8 +26,6 @@ rsa - RSA public key cryptosystem int RSA_verify(int type, unsigned char *m, unsigned int m_len, unsigned char *sigbuf, unsigned int siglen, RSA *rsa); - int RSA_size(const RSA *rsa); - RSA *RSA_generate_key(int num, unsigned long e, void (*callback)(int,int,void *), void *cb_arg); diff --git a/include/openssl/dh.h b/include/openssl/dh.h index 2d7c739eca..e0f4b57349 100644 --- a/include/openssl/dh.h +++ b/include/openssl/dh.h @@ -200,6 +200,7 @@ DH *DH_new_method(ENGINE *engine); DH *DH_new(void); void DH_free(DH *dh); int DH_up_ref(DH *dh); +int DH_bits(const DH *dh); int DH_size(const DH *dh); int DH_security_bits(const DH *dh); int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h index 9ba64970b6..727b9df4c4 100644 --- a/include/openssl/rsa.h +++ b/include/openssl/rsa.h @@ -319,6 +319,7 @@ struct rsa_st { RSA *RSA_new(void); RSA *RSA_new_method(ENGINE *engine); +int RSA_bits(const RSA *rsa); int RSA_size(const RSA *rsa); int RSA_security_bits(const RSA *rsa); diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 632d743871..2f7b093c3d 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -3335,6 +3335,7 @@ int ssl3_check_cert_and_algorithm(SSL *s) #ifndef OPENSSL_NO_DH DH *dh; #endif + int al = SSL_AD_HANDSHAKE_FAILURE; alg_k = s->s3->tmp.new_cipher->algorithm_mkey; alg_a = s->s3->tmp.new_cipher->algorithm_auth; @@ -3395,17 +3396,33 @@ int ssl3_check_cert_and_algorithm(SSL *s) } #endif #ifndef OPENSSL_NO_RSA - if ((alg_k & SSL_kRSA) && - !(has_bits(i, EVP_PK_RSA | EVP_PKT_ENC) || (rsa != NULL))) { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, - SSL_R_MISSING_RSA_ENCRYPTING_CERT); - goto f_err; + if (alg_k & SSL_kRSA) { + if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && + !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; + } else if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) { + if (pkey_bits <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + if (!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; + } + if (rsa != NULL) { + /* server key exchange is not allowed. */ + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR); + goto f_err; + } + } + } } #endif #ifndef OPENSSL_NO_DH - if ((alg_k & SSL_kDHE) && - !(has_bits(i, EVP_PK_DH | EVP_PKT_EXCH) || (dh != NULL))) { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_DH_KEY); + if ((alg_k & SSL_kDHE) && (dh == NULL)) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR); goto f_err; } else if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) && !has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) { @@ -3427,9 +3444,14 @@ int ssl3_check_cert_and_algorithm(SSL *s) pkey_bits > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { #ifndef OPENSSL_NO_RSA if (alg_k & SSL_kRSA) { - if (rsa == NULL - || RSA_size(rsa) * 8 > + if (rsa == NULL) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_EXPORT_TMP_RSA_KEY); + goto f_err; + } else if (RSA_bits(rsa) > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + /* We have a temporary RSA key but it's too large. */ + al = SSL_AD_EXPORT_RESTRICTION; SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_EXPORT_TMP_RSA_KEY); goto f_err; @@ -3437,14 +3459,21 @@ int ssl3_check_cert_and_algorithm(SSL *s) } else #endif #ifndef OPENSSL_NO_DH - if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd)) { - if (dh == NULL - || DH_size(dh) * 8 > + if (alg_k & SSL_kDHE) { + if (DH_bits(dh) > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + /* We have a temporary DH key but it's too large. */ + al = SSL_AD_EXPORT_RESTRICTION; SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_EXPORT_TMP_DH_KEY); goto f_err; } + } else if (alg_k & (SSL_kDHr | SSL_kDHd)) { + /* The cert should have had an export DH key. */ + al = SSL_AD_EXPORT_RESTRICTION; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_EXPORT_TMP_DH_KEY); + goto f_err; } else #endif { @@ -3455,7 +3484,7 @@ int ssl3_check_cert_and_algorithm(SSL *s) } return (1); f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + ssl3_send_alert(s, SSL3_AL_FATAL, al); err: return (0); } diff --git a/util/libeay.num b/util/libeay.num index c297ef789d..edeb50d34f 100755 --- a/util/libeay.num +++ b/util/libeay.num @@ -4571,3 +4571,5 @@ ASN1_INTEGER_get_uint64 4929 EXIST::FUNCTION: ASN1_INTEGER_set_uint64 4930 EXIST::FUNCTION: PKCS5_pbe2_set_scrypt 4931 EXIST::FUNCTION: PKCS8_set0_pbe 4932 EXIST::FUNCTION: +DH_bits 4933 EXIST::FUNCTION:DH +RSA_bits 4934 EXIST::FUNCTION:RSA -- 2.40.0