Properly check certificate in case of export ciphers.
authorKurt Roeckx <kurt@roeckx.be>
Sat, 18 Apr 2015 10:23:12 +0000 (12:23 +0200)
committerKurt Roeckx <kurt@roeckx.be>
Mon, 8 Jun 2015 22:46:59 +0000 (00:46 +0200)
Reviewed-by: Matt Caswell <matt@openssl.org>
MR #588

crypto/dh/dh_lib.c
crypto/rsa/rsa_crpt.c
doc/crypto/DH_size.pod
doc/crypto/RSA_size.pod
doc/crypto/dh.pod
doc/crypto/rsa.pod
include/openssl/dh.h
include/openssl/rsa.h
ssl/s3_clnt.c
util/libeay.num

index 4a37adc9f8208eb7eb7298ff2871f8c3d9e1e165..cce2514bbfca272bacdd50e620f1ffe09a06a315 100644 (file)
@@ -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));
index 5220b7d068fc13b1e181ec8b49a98d28cc6d38c8..3c4fd67714567a8c76fdb9dfc9af2160612b2967 100644 (file)
 #include <openssl/rsa.h>
 #include <openssl/rand.h>
 
+int RSA_bits(const RSA *r)
+{
+    return (BN_num_bits(r->n));
+}
+
 int RSA_size(const RSA *r)
 {
     return (BN_num_bytes(r->n));
index 97f26fda7855e8e865e9e9d7893a4d3d15d7f124..e73f32589a0ca36fef8e2d068f86230b66d297c2 100644 (file)
@@ -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 <openssl/dh.h>
+#include <openssl/dh.h>
 
- 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().
 
-B<dh-E<gt>p> must not be B<NULL>.
+DH_bits() returns the number of significant bits.
+
+B<dh> and B<dh-E<gt>p> must not be B<NULL>.
 
 =head1 RETURN VALUE
 
-The size in bytes.
+The size.
 
 =head1 SEE ALSO
 
-L<dh(3)|dh(3)>, L<DH_generate_key(3)|DH_generate_key(3)>
+L<dh(3)|dh(3)>, L<DH_generate_key(3)|DH_generate_key(3)>,
+L<BN_num_bits(3)|BN_num_bits(3)>
 
 =head1 HISTORY
 
 DH_size() is available in all versions of SSLeay and OpenSSL.
+DH_bits() was added in OpenSSL 1.1.0.
 
 =cut
index 5b7f835f95d6dc01ecb6c5419761985d6eded98d..f68d5e8e3c1782b8c1568bb1e8b308b340970f3a 100644 (file)
@@ -2,32 +2,37 @@
 
 =head1 NAME
 
-RSA_size - get RSA modulus size
+RSA_size, RSA_bits - get RSA modulus size
 
 =head1 SYNOPSIS
 
- #include <openssl/rsa.h>
+#include <openssl/rsa.h>
 
- 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.
 
-B<rsa-E<gt>n> must not be B<NULL>.
+RSA_bits() returns the number of significant bits.
+
+B<rsa> and B<rsa-E<gt>n> must not be B<NULL>.
 
 =head1 RETURN VALUE
 
-The size in bytes.
+The size.
 
 =head1 SEE ALSO
 
-L<rsa(3)|rsa(3)>
+L<rsa(3)|rsa(3)>, L<BN_num_bits(3)|BN_num_bits(3)>
 
 =head1 HISTORY
 
 RSA_size() is available in all versions of SSLeay and OpenSSL.
+RSA_bits() was added in OpenSSL 1.1.0.
 
 =cut
index c3ccd062078304ad6f237417dae48047bfe0c4f8..1c8a327458a54bbb5588b0fed10b073e58f420a1 100644 (file)
@@ -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);
index 45ac53ffc1472fcbc5fdb14487dc823f7a72b51f..743334ff79891c8a3cdae25b9ee826a7c340b0cc 100644 (file)
@@ -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);
 
index 2d7c739eca980f8fb176deaf1b160315ceef3a36..e0f4b57349ec410d8799515a8a8cde894e8fcb82 100644 (file)
@@ -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,
index 9ba64970b650947746367080d660b47db062c316..727b9df4c48102a7ab41361cc6cac863d8f4c2d1 100644 (file)
@@ -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);
 
index 632d743871d3944f7295794b4bc5235902c99287..2f7b093c3dd2cdf42da4bf5e89c690c5532d5b37 100644 (file)
@@ -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);
 }
index c297ef789dd7f3b1bba61f93170479ebb14da6db..edeb50d34f5cfd7927f7ca0d5565ad6b59a02582 100755 (executable)
@@ -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