Blame SOURCES/openssl-fips-0.9.8e-cve-2012-0884.patch

c4366c
Fix MMA (Bleichenbacher's attack on PKCS #1 v1.5 RSA padding) weakness
c4366c
in PKCS7 code. When RSA decryption fails use a random key for
c4366c
content decryption and always return the same error.
c4366c
diff -up openssl-fips-0.9.8e/crypto/pkcs7/pk7_doit.c.pk7-mma openssl-fips-0.9.8e/crypto/pkcs7/pk7_doit.c
c4366c
--- openssl-fips-0.9.8e/crypto/pkcs7/pk7_doit.c.pk7-mma	2007-02-03 10:51:58.000000000 +0100
c4366c
+++ openssl-fips-0.9.8e/crypto/pkcs7/pk7_doit.c	2012-03-19 17:51:35.879037258 +0100
c4366c
@@ -423,6 +423,8 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE
c4366c
 		int max;
c4366c
 		X509_OBJECT ret;
c4366c
 #endif
c4366c
+		unsigned char *tkey = NULL;
c4366c
+		int tkeylen;
c4366c
 		int jj;
c4366c
 
c4366c
 		if ((etmp=BIO_new(BIO_f_cipher())) == NULL)
c4366c
@@ -464,36 +466,42 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE
c4366c
 
c4366c
 		if (pcert == NULL)
c4366c
 			{
c4366c
+			/* Temporary storage in case EVP_PKEY_decrypt
c4366c
+			 * overwrites output buffer on error.
c4366c
+			 */
c4366c
+			unsigned char *tmp2;
c4366c
+			tmp2 = OPENSSL_malloc(jj);
c4366c
+			if (!tmp2)
c4366c
+				goto err;
c4366c
+			jj = -1;
c4366c
+			/* Always attempt to decrypt all cases to avoid
c4366c
+			 * leaking timing information about a successful
c4366c
+			 * decrypt.
c4366c
+			 */
c4366c
 			for (i=0; i
c4366c
 				{
c4366c
+				int tret;
c4366c
 				ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
c4366c
-				jj=EVP_PKEY_decrypt(tmp,
c4366c
+				tret=EVP_PKEY_decrypt(tmp2,
c4366c
 					M_ASN1_STRING_data(ri->enc_key),
c4366c
 					M_ASN1_STRING_length(ri->enc_key),
c4366c
 						pkey);
c4366c
-				if (jj > 0)
c4366c
-					break;
c4366c
+				if (tret > 0)
c4366c
+					{
c4366c
+					memcpy(tmp, tmp2, tret);
c4366c
+					OPENSSL_cleanse(tmp2, tret);
c4366c
+					jj = tret;
c4366c
+					}
c4366c
 				ERR_clear_error();
c4366c
-				ri = NULL;
c4366c
-				}
c4366c
-			if (ri == NULL)
c4366c
-				{
c4366c
-				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
c4366c
-				      PKCS7_R_NO_RECIPIENT_MATCHES_KEY);
c4366c
-				goto err;
c4366c
 				}
c4366c
+			OPENSSL_free(tmp2);
c4366c
 			}
c4366c
 		else
c4366c
 			{
c4366c
 			jj=EVP_PKEY_decrypt(tmp,
c4366c
 				M_ASN1_STRING_data(ri->enc_key),
c4366c
 				M_ASN1_STRING_length(ri->enc_key), pkey);
c4366c
-			if (jj <= 0)
c4366c
-				{
c4366c
-				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
c4366c
-								ERR_R_EVP_LIB);
c4366c
-				goto err;
c4366c
-				}
c4366c
+			ERR_clear_error();
c4366c
 			}
c4366c
 
c4366c
 		evp_ctx=NULL;
c4366c
@@ -502,24 +510,49 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE
c4366c
 			goto err;
c4366c
 		if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
c4366c
 			goto err;
c4366c
+		/* Generate random key to counter MMA */
c4366c
+		tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
c4366c
+		tkey = OPENSSL_malloc(tkeylen);
c4366c
+		if (!tkey)
c4366c
+			goto err;
c4366c
+		if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
c4366c
+			goto err;
c4366c
+		/* If we have no key use random key */
c4366c
+		if (jj <= 0)
c4366c
+			{
c4366c
+			OPENSSL_free(tmp);
c4366c
+			jj = tkeylen;
c4366c
+			tmp = tkey;
c4366c
+			tkey = NULL;
c4366c
+			}
c4366c
 
c4366c
-		if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
c4366c
+		if (jj != tkeylen) {
c4366c
 			/* Some S/MIME clients don't use the same key
c4366c
 			 * and effective key length. The key length is
c4366c
 			 * determined by the size of the decrypted RSA key.
c4366c
 			 */
c4366c
 			if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, jj))
c4366c
 				{
c4366c
-				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
c4366c
-					PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH);
c4366c
-				goto err;
c4366c
+				/* As MMA defence use random key instead */
c4366c
+				OPENSSL_cleanse(tmp, jj);
c4366c
+				OPENSSL_free(tmp);
c4366c
+				jj = tkeylen;
c4366c
+				tmp = tkey;
c4366c
+				tkey = NULL;
c4366c
 				}
c4366c
 		} 
c4366c
+		ERR_clear_error();
c4366c
 		if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
c4366c
 			goto err;
c4366c
 
c4366c
 		OPENSSL_cleanse(tmp,jj);
c4366c
 
c4366c
+		if (tkey)
c4366c
+			{
c4366c
+			OPENSSL_cleanse(tkey, tkeylen);
c4366c
+			OPENSSL_free(tkey);
c4366c
+			}
c4366c
+
c4366c
 		if (out == NULL)
c4366c
 			out=etmp;
c4366c
 		else