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

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