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