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 4a37adc..cce2514 100644 (file)
@@ -237,6 +237,11 @@ void *DH_get_ex_data(DH *d, int idx)
     return (CRYPTO_get_ex_data(&d->ex_data, 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));
 int DH_size(const DH *dh)
 {
     return (BN_num_bytes(dh->p));
index 5220b7d..3c4fd67 100644 (file)
 #include <openssl/rsa.h>
 #include <openssl/rand.h>
 
 #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));
 int RSA_size(const RSA *r)
 {
     return (BN_num_bytes(r->n));
index 97f26fd..e73f325 100644 (file)
@@ -2,32 +2,38 @@
 
 =head1 NAME
 
 
 =head1 NAME
 
-DH_size - get Diffie-Hellman prime size
+DH_size, DH_bits - get Diffie-Hellman prime size
 
 =head1 SYNOPSIS
 
 
 =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
 
 
 =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().
 
 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
 
 
 =head1 RETURN VALUE
 
-The size in bytes.
+The size.
 
 =head1 SEE ALSO
 
 
 =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.
 
 =head1 HISTORY
 
 DH_size() is available in all versions of SSLeay and OpenSSL.
+DH_bits() was added in OpenSSL 1.1.0.
 
 =cut
 
 =cut
index 5b7f835..f68d5e8 100644 (file)
@@ -2,32 +2,37 @@
 
 =head1 NAME
 
 
 =head1 NAME
 
-RSA_size - get RSA modulus size
+RSA_size, RSA_bits - get RSA modulus size
 
 =head1 SYNOPSIS
 
 
 =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
 
 
 =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.
 
 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
 
 
 =head1 RETURN VALUE
 
-The size in bytes.
+The size.
 
 =head1 SEE ALSO
 
 
 =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.
 
 =head1 HISTORY
 
 RSA_size() is available in all versions of SSLeay and OpenSSL.
+RSA_bits() was added in OpenSSL 1.1.0.
 
 =cut
 
 =cut
index c3ccd06..1c8a327 100644 (file)
@@ -12,8 +12,6 @@ dh - Diffie-Hellman key agreement
  DH *  DH_new(void);
  void  DH_free(DH *dh);
 
  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);
  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 45ac53f..743334f 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_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);
 
  RSA *RSA_generate_key(int num, unsigned long e,
     void (*callback)(int,int,void *), void *cb_arg);
 
index 2d7c739..e0f4b57 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);
 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,
 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 9ba6497..727b9df 100644 (file)
@@ -319,6 +319,7 @@ struct rsa_st {
 
 RSA *RSA_new(void);
 RSA *RSA_new_method(ENGINE *engine);
 
 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);
 
 int RSA_size(const RSA *rsa);
 int RSA_security_bits(const RSA *rsa);
 
index 632d743..2f7b093 100644 (file)
@@ -3335,6 +3335,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
 #ifndef OPENSSL_NO_DH
     DH *dh;
 #endif
 #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;
 
     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
     }
 #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
     }
 #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)) {
         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) {
         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)) {
                 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;
                 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
         } 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)) {
                 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;
             }
                 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
         {
         } else
 #endif
         {
@@ -3455,7 +3484,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
     }
     return (1);
  f_err:
     }
     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);
 }
  err:
     return (0);
 }
index c297ef7..edeb50d 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:
 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