Dr S N Henson of the OpenSSL core team and Open Network Security recently developed an ASN1 test suite for NISCC (www.niscc.gov.uk). When the test suite was run against OpenSSL two denial of service vulnerabilities were discovered. Certain types of public key can take disproportionate amounts of time to process. This could be used by an attacker in a denial of service attack. CVE-2006-2940 Any code which uses OpenSSL to parse ASN1 data from untrusted sources is affected. This includes SSL servers which enable client authentication, and S/MIME applications. diff -u -r1.37.2.2 dh.h --- crypto/dh/dh.h 9 Jan 2006 16:05:22 -0000 1.37.2.2 +++ crypto/dh/dh.h 15 Sep 2006 13:59:47 -0000 @@ -73,6 +73,8 @@ #include #endif +#define OPENSSL_DH_MAX_MODULUS_BITS 10000 + #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 @@ -221,6 +223,7 @@ /* Reason codes. */ #define DH_R_BAD_GENERATOR 101 #define DH_R_INVALID_PUBKEY 102 +#define DH_R_MODULUS_TOO_LARGE 103 #define DH_R_NO_PRIVATE_VALUE 100 #ifdef __cplusplus diff -u -r1.11.2.2 dh_err.c --- crypto/dh/dh_err.c 9 Jan 2006 16:05:22 -0000 1.11.2.2 +++ crypto/dh/dh_err.c 15 Sep 2006 13:59:47 -0000 @@ -84,6 +84,7 @@ { {ERR_REASON(DH_R_BAD_GENERATOR) ,"bad generator"}, {ERR_REASON(DH_R_INVALID_PUBKEY) ,"invalid public key"}, +{ERR_REASON(DH_R_MODULUS_TOO_LARGE) ,"modulus too large"}, {ERR_REASON(DH_R_NO_PRIVATE_VALUE) ,"no private value"}, {0,NULL} }; diff -u -r1.24.2.3 dh_key.c --- crypto/dh/dh_key.c 13 Mar 2006 23:12:06 -0000 1.24.2.3 +++ crypto/dh/dh_key.c 15 Sep 2006 13:59:47 -0000 @@ -179,6 +179,12 @@ int ret= -1; int check_result; + if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) + { + DHerr(DH_F_COMPUTE_KEY,DH_R_MODULUS_TOO_LARGE); + return -1; + } + ctx = BN_CTX_new(); if (ctx == NULL) goto err; BN_CTX_start(ctx); diff -u -r1.39 dsa.h --- crypto/dsa/dsa.h 16 May 2005 01:43:30 -0000 1.39 +++ crypto/dsa/dsa.h 15 Sep 2006 13:59:47 -0000 @@ -84,6 +84,8 @@ #endif #endif +#define OPENSSL_DSA_MAX_MODULUS_BITS 10000 + #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 @@ -270,8 +272,10 @@ #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 } diff -u -r1.13 dsa_err.c --- crypto/dsa/dsa_err.c 12 Apr 2005 16:15:12 -0000 1.13 +++ crypto/dsa/dsa_err.c 15 Sep 2006 13:59:47 -0000 @@ -89,8 +89,10 @@ 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} }; diff -u -r1.24.2.1 dsa_ossl.c --- crypto/dsa/dsa_ossl.c 26 May 2005 04:40:57 -0000 1.24.2.1 +++ crypto/dsa/dsa_ossl.c 15 Sep 2006 13:59:47 -0000 @@ -304,6 +304,18 @@ 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); diff -u -r1.55.2.6 rsa.h --- crypto/rsa/rsa.h 6 Sep 2006 06:43:25 -0000 1.55.2.6 +++ crypto/rsa/rsa.h 15 Sep 2006 13:59:48 -0000 @@ -159,6 +159,11 @@ BN_BLINDING *mt_blinding; }; +#define OPENSSL_RSA_MAX_MODULUS_BITS 16384 + +#define OPENSSL_RSA_SMALL_MODULUS_BITS 3072 +#define OPENSSL_RSA_MAX_PUBEXP_BITS 64 /* exponent limit enforced for "small" modulus only */ + #define RSA_3 0x3L #define RSA_F4 0x10001L @@ -407,6 +412,7 @@ #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_NO_PUBLIC_EXPONENT 140 #define RSA_R_NULL_BEFORE_BLOCK_MISSING 113 #define RSA_R_N_DOES_NOT_EQUAL_P_Q 127 diff -u -r1.46.2.6 rsa_eay.c --- crypto/rsa/rsa_eay.c 6 Sep 2006 06:43:25 -0000 1.46.2.6 +++ crypto/rsa/rsa_eay.c 15 Sep 2006 13:59:48 -0000 @@ -168,6 +168,28 @@ 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; + } + } + if ((ctx=BN_CTX_new()) == NULL) goto err; BN_CTX_start(ctx); f = BN_CTX_get(ctx); @@ -597,6 +619,28 @@ 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; + } + } + if((ctx = BN_CTX_new()) == NULL) goto err; BN_CTX_start(ctx); f = BN_CTX_get(ctx); diff -u -r1.17.2.5 rsa_err.c --- crypto/rsa/rsa_err.c 6 Sep 2006 06:43:26 -0000 1.17.2.5 +++ crypto/rsa/rsa_err.c 15 Sep 2006 13:59:48 -0000 @@ -137,6 +137,7 @@ {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_NO_PUBLIC_EXPONENT) ,"no public exponent"}, {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"},