Introduce limits to prevent malicious keys being able to
authorMark J. Cox <mark@openssl.org>
Thu, 28 Sep 2006 11:53:51 +0000 (11:53 +0000)
committerMark J. Cox <mark@openssl.org>
Thu, 28 Sep 2006 11:53:51 +0000 (11:53 +0000)
cause a denial of service.  (CVE-2006-2940)
[Steve Henson, Bodo Moeller]

Fix ASN.1 parsing of certain invalid structures that can result
in a denial of service.  (CVE-2006-2937)  [Steve Henson]

Fix buffer overflow in SSL_get_shared_ciphers() function.
(CVE-2006-3738) [Tavis Ormandy and Will Drewry, Google Security Team]

Fix SSL client code which could crash if connecting to a
malicious SSLv2 server.  (CVE-2006-4343)
[Tavis Ormandy and Will Drewry, Google Security Team]

15 files changed:
CHANGES
NEWS
crypto/asn1/tasn_dec.c
crypto/dh/dh.h
crypto/dh/dh_err.c
crypto/dh/dh_key.c
crypto/dsa/dsa.h
crypto/dsa/dsa_err.c
crypto/dsa/dsa_ossl.c
crypto/rsa/rsa.h
crypto/rsa/rsa_eay.c
crypto/rsa/rsa_err.c
ssl/s2_clnt.c
ssl/s3_srvr.c
ssl/ssl_lib.c

diff --git a/CHANGES b/CHANGES
index 6ece190c106a81ef1f1e4c278c0425c43d0b4e78..6a6c30a28a7ccc9c6419e3aca076ff7afc20038b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,20 @@
 
  Changes between 0.9.7k and 0.9.7l  [xx XXX xxxx]
 
+  *) Introduce limits to prevent malicious keys being able to
+     cause a denial of service.  (CVE-2006-2940)
+     [Steve Henson, Bodo Moeller]
+
+  *) Fix ASN.1 parsing of certain invalid structures that can result
+     in a denial of service.  (CVE-2006-2937)  [Steve Henson]
+
+  *) Fix buffer overflow in SSL_get_shared_ciphers() function. 
+     (CVE-2006-3738) [Tavis Ormandy and Will Drewry, Google Security Team]
+
+  *) Fix SSL client code which could crash if connecting to a
+     malicious SSLv2 server.  (CVE-2006-4343)
+     [Tavis Ormandy and Will Drewry, Google Security Team]
+
   *) Change ciphersuite string processing so that an explicit
      ciphersuite selects this one ciphersuite (so that "AES256-SHA"
      will no longer include "AES128-SHA"), and any other similar
diff --git a/NEWS b/NEWS
index 818ffde0ac80db0188b02015079b881b0ae743cd..bd3ed1fdd15adf777a9970d32fc9e26195cd55c9 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,11 @@
   This file gives a brief overview of the major changes between each OpenSSL
   release. For more details please read the CHANGES file.
 
+  Major changes between OpenSSL 0.9.7k and OpenSSL 0.9.7l:
+
+      o Introduce limits to prevent malicious key DoS  (CVE-2006-2940)
+      o Fix security issues (CVE-2006-2937, CVE-2006-3737, CVE-2006-4343)
+
   Major changes between OpenSSL 0.9.7j and OpenSSL 0.9.7k:
 
       o Fix Daniel Bleichenbacher forged signature attack, CVE-2006-4339
index e5d5e4bfd15dc78868e0bd140bdd1b42d405d1f9..fb7caa3f2c80876ba533b24fa8c60e5ad96cb216 100644 (file)
@@ -629,6 +629,7 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long inl
                ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR);
                return 0;
        } else if(ret == -1) return -1;
+        ret = 0;
        /* SEQUENCE, SET and "OTHER" are left in encoded form */
        if((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) {
                /* Clear context cache for type OTHER because the auto clear when
index 92c7481e10ad2f27a5d44ccb7a82050b07e2c1f7..fe47553112964149f277baff174a22888916ba4f 100644 (file)
 #include <openssl/crypto.h>
 #include <openssl/ossl_typ.h>
        
+#ifndef OPENSSL_DH_MAX_MODULUS_BITS
+# define OPENSSL_DH_MAX_MODULUS_BITS   10000
+#endif
+
 #define DH_FLAG_CACHE_MONT_P     0x01
 #define DH_FLAG_NO_EXP_CONSTTIME 0x02 /* new with 0.9.7h; the built-in DH
                                        * implementation now uses constant time
@@ -207,6 +211,7 @@ void ERR_load_DH_strings(void);
 /* Reason codes. */
 #define DH_R_BAD_GENERATOR                              101
 #define DH_R_NO_PRIVATE_VALUE                           100
+#define DH_R_MODULUS_TOO_LARGE                           103
 
 #ifdef  __cplusplus
 }
index 83ccb41221243abd9a0b0ef608e4fc7c0c238f2c..eb3d43104d2268a008ff920ada89699d59b7bfa2 100644 (file)
@@ -82,6 +82,7 @@ static ERR_STRING_DATA DH_str_functs[]=
 static ERR_STRING_DATA DH_str_reasons[]=
        {
 {ERR_REASON(DH_R_BAD_GENERATOR)          ,"bad generator"},
+{ERR_REASON(DH_R_MODULUS_TOO_LARGE)      ,"modulus too large"},               
 {ERR_REASON(DH_R_NO_PRIVATE_VALUE)       ,"no private value"},
 {0,NULL}
        };
index 3a39f7c8cae2d13afb16e2e5e2bcdbd9ed3155d6..c6e618bca2e4180fb9d9730c26d7378a7e3911ea 100644 (file)
@@ -180,6 +180,12 @@ static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
        BIGNUM *tmp;
        int ret= -1;
 
+       if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS)
+               {
+               DHerr(DH_F_DH_COMPUTE_KEY,DH_R_MODULUS_TOO_LARGE);
+               goto err;
+               }
+
        ctx = BN_CTX_new();
        if (ctx == NULL) goto err;
        BN_CTX_start(ctx);
index 851e3f0445c648ed6e4202dc45cf1543bdde9edf..6948f868348da740aab170f0cdd6c8c30c3f515a 100644 (file)
 # include <openssl/dh.h>
 #endif
 
+#ifndef OPENSSL_DSA_MAX_MODULUS_BITS
+# define OPENSSL_DSA_MAX_MODULUS_BITS  10000
+#endif
+
 #define DSA_FLAG_CACHE_MONT_P  0x01
 #define DSA_FLAG_NO_EXP_CONSTTIME       0x02 /* new with 0.9.7h; the built-in DSA
                                               * implementation now uses constant time
@@ -259,8 +263,10 @@ void ERR_load_DSA_strings(void);
 #define DSA_F_SIG_CB                                    114
 
 /* Reason codes. */
+#define DSA_R_BAD_Q_VALUE                               102
 #define DSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE               100
 #define DSA_R_MISSING_PARAMETERS                        101
+#define DSA_R_MODULUS_TOO_LARGE                                 103
 
 #ifdef  __cplusplus
 }
index fd42053572bcc229e280de41b031b5757b66e9bb..d7fac691546d1be08e6c8fb0895e9391aa9af988 100644 (file)
@@ -89,8 +89,10 @@ static ERR_STRING_DATA DSA_str_functs[]=
 
 static ERR_STRING_DATA DSA_str_reasons[]=
        {
+{ERR_REASON(DSA_R_BAD_Q_VALUE)           ,"bad q value"},
 {ERR_REASON(DSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE),"data too large for key size"},
 {ERR_REASON(DSA_R_MISSING_PARAMETERS)    ,"missing parameters"},
+{ERR_REASON(DSA_R_MODULUS_TOO_LARGE)     ,"modulus too large"},
 {0,NULL}
        };
 
index 12509a708336ea65066687ac8efdb71b2ed1cfca..5de5fc7e91acc259a65fc03ac497701e71a7fee4 100644 (file)
@@ -274,6 +274,18 @@ static int dsa_do_verify(const unsigned char *dgst, int dgst_len, DSA_SIG *sig,
                return -1;
                }
 
+       if (BN_num_bits(dsa->q) != 160)
+               {
+               DSAerr(DSA_F_DSA_DO_VERIFY,DSA_R_BAD_Q_VALUE);
+               return -1;
+               }
+
+       if (BN_num_bits(dsa->p) > OPENSSL_DSA_MAX_MODULUS_BITS)
+               {
+               DSAerr(DSA_F_DSA_DO_VERIFY,DSA_R_MODULUS_TOO_LARGE);
+               return -1;
+               }
+
        BN_init(&u1);
        BN_init(&u2);
        BN_init(&t1);
index 0b639cd37ffac7b75f13e66d6e39a1ded6931c0f..9eda2695869480b2e1ba48dc4d1a9f4b3a75f67b 100644 (file)
@@ -154,6 +154,17 @@ struct rsa_st
        BN_BLINDING *blinding;
        };
 
+#ifndef OPENSSL_RSA_MAX_MODULUS_BITS
+# define OPENSSL_RSA_MAX_MODULUS_BITS  16384
+#endif
+
+#ifndef OPENSSL_RSA_SMALL_MODULUS_BITS
+# define OPENSSL_RSA_SMALL_MODULUS_BITS        3072
+#endif
+#ifndef OPENSSL_RSA_MAX_PUBEXP_BITS
+# define OPENSSL_RSA_MAX_PUBEXP_BITS   64 /* exponent limit enforced for "large" modulus only */
+#endif
+
 #define RSA_3  0x3L
 #define RSA_F4 0x10001L
 
@@ -386,6 +397,7 @@ void ERR_load_RSA_strings(void);
 #define RSA_R_IQMP_NOT_INVERSE_OF_Q                     126
 #define RSA_R_KEY_SIZE_TOO_SMALL                        120
 #define RSA_R_LAST_OCTET_INVALID                        134
+#define RSA_R_MODULUS_TOO_LARGE                                 105
 #define RSA_R_NULL_BEFORE_BLOCK_MISSING                         113
 #define RSA_R_N_DOES_NOT_EQUAL_P_Q                      127
 #define RSA_R_OAEP_DECODING_ERROR                       121
index d1986c190817f5db875ae17c7d68dad4d77b95f7..6791c66bbcad426e6729e93f0182a25e7e6b97bd 100644 (file)
@@ -157,6 +157,28 @@ static int RSA_eay_public_encrypt(int flen, const unsigned char *from,
        unsigned char *buf=NULL;
        BN_CTX *ctx=NULL;
 
+       if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS)
+               {
+               RSAerr(RSA_F_RSA_EAY_PUBLIC_DECRYPT, RSA_R_MODULUS_TOO_LARGE);
+               return -1;
+               }
+       if (BN_ucmp(rsa->n, rsa->e) <= 0)
+               {
+               RSAerr(RSA_F_RSA_EAY_PUBLIC_DECRYPT, RSA_R_BAD_E_VALUE);
+               return -1;
+               }
+       /* for large moduli, enforce exponent limit */
+       if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS)
+               {
+               if (BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS)
+                       {
+                       RSAerr(RSA_F_RSA_EAY_PUBLIC_DECRYPT, RSA_R_BAD_E_VALUE);
+                       return -1;
+                       }
+               }
+       
        BN_init(&f);
        BN_init(&ret);
        if ((ctx=BN_CTX_new()) == NULL) goto err;
@@ -600,6 +622,28 @@ static int RSA_eay_public_decrypt(int flen, const unsigned char *from,
        unsigned char *buf=NULL;
        BN_CTX *ctx=NULL;
 
+       if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS)
+               {
+               RSAerr(RSA_F_RSA_EAY_PUBLIC_ENCRYPT, RSA_R_MODULUS_TOO_LARGE);
+               return -1;
+               }
+
+       if (BN_ucmp(rsa->n, rsa->e) <= 0)
+               {
+               RSAerr(RSA_F_RSA_EAY_PUBLIC_ENCRYPT, RSA_R_BAD_E_VALUE);
+               return -1;
+               }
+
+       /* for large moduli, enforce exponent limit */
+       if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS)
+               {
+               if (BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS)
+                       {
+                       RSAerr(RSA_F_RSA_EAY_PUBLIC_ENCRYPT, RSA_R_BAD_E_VALUE);
+                       return -1;
+                       }
+               }
+
        BN_init(&f);
        BN_init(&ret);
        ctx=BN_CTX_new();
index 2ec4b30ff7987b87d22a138f02846a6cb2ffb40e..ddcb28e66302b90c37ccd602c6633653844f93cc 100644 (file)
@@ -129,6 +129,7 @@ static ERR_STRING_DATA RSA_str_reasons[]=
 {ERR_REASON(RSA_R_IQMP_NOT_INVERSE_OF_Q) ,"iqmp not inverse of q"},
 {ERR_REASON(RSA_R_KEY_SIZE_TOO_SMALL)    ,"key size too small"},
 {ERR_REASON(RSA_R_LAST_OCTET_INVALID)    ,"last octet invalid"},
+{ERR_REASON(RSA_R_MODULUS_TOO_LARGE)     ,"modulus too large"},
 {ERR_REASON(RSA_R_NULL_BEFORE_BLOCK_MISSING),"null before block missing"},
 {ERR_REASON(RSA_R_N_DOES_NOT_EQUAL_P_Q)  ,"n does not equal p q"},
 {ERR_REASON(RSA_R_OAEP_DECODING_ERROR)   ,"oaep decoding error"},
index eba04c715b3b3e8d1537c5618b757693fe2e4f58..215e4f8f53ac3bfdbf761463db6a8aebc28e6c2d 100644 (file)
@@ -538,7 +538,8 @@ static int get_server_hello(SSL *s)
                CRYPTO_add(&s->session->peer->references, 1, CRYPTO_LOCK_X509);
                }
 
-       if (s->session->peer != s->session->sess_cert->peer_key->x509)
+       if (s->session->sess_cert == NULL 
+      || s->session->peer != s->session->sess_cert->peer_key->x509)
                /* can't happen */
                {
                ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
index 36fc39d7f82527b0753db53623102eb0808a1b8a..98d0a075e5effcd737cd0d18c57e6c78e9f4b4f5 100644 (file)
@@ -1727,7 +1727,7 @@ static int ssl3_get_client_key_exchange(SSL *s)
 
                 if (kssl_ctx->client_princ)
                         {
-                        int len = strlen(kssl_ctx->client_princ);
+                        size_t len = strlen(kssl_ctx->client_princ);
                         if ( len < SSL_MAX_KRB5_PRINCIPAL_LENGTH ) 
                                 {
                                 s->session->krb5_client_princ_len = len;
index 2bd9a5af861169103f769090ba613069f32987ee..4e8f302a5e69b4a5cac44d2d8ad62bcbb94b9d9b 100644 (file)
@@ -1187,7 +1187,7 @@ char *SSL_get_shared_ciphers(const SSL *s,char *buf,int len)
                c=sk_SSL_CIPHER_value(sk,i);
                for (cp=c->name; *cp; )
                        {
-                       if (len-- == 0)
+                       if (len-- <= 0)
                                {
                                *p='\0';
                                return(buf);