diff options
-rw-r--r-- | CHANGES | 14 | ||||
-rw-r--r-- | crypto/cms/cms_env.c | 18 | ||||
-rw-r--r-- | crypto/cms/cms_lcl.h | 2 | ||||
-rw-r--r-- | crypto/cms/cms_smime.c | 4 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_doit.c | 12 |
5 files changed, 45 insertions, 5 deletions
@@ -39,6 +39,20 @@ (CVE-2019-1547) [Billy Bob Brumley] + *) Fixed a padding oracle in PKCS7_dataDecode and CMS_decrypt_set1_pkey. + An attack is simple, if the first CMS_recipientInfo is valid but the + second CMS_recipientInfo is chosen ciphertext. If the second + recipientInfo decodes to PKCS #1 v1.5 form plaintext, the correct + encryption key will be replaced by garbage, and the message cannot be + decoded, but if the RSA decryption fails, the correct encryption key is + used and the recipient will not notice the attack. + As a work around for this potential attack the length of the decrypted + key must be equal to the cipher default key length, in case the + certifiate is not given and all recipientInfo are tried out. + The old behaviour can be re-enabled in the CMS code by setting the + CMS_DEBUG_DECRYPT flag. + [Bernd Edlinger] + *) Document issue with installation paths in diverse Windows builds '/usr/local/ssl' is an unsafe prefix for location to install OpenSSL diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c index 93c06cb00a..77c8f0a483 100644 --- a/crypto/cms/cms_env.c +++ b/crypto/cms/cms_env.c @@ -422,6 +422,7 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, unsigned char *ek = NULL; size_t eklen; int ret = 0; + size_t fixlen = 0; CMS_EncryptedContentInfo *ec; ec = cms->d.envelopedData->encryptedContentInfo; @@ -430,6 +431,19 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, return 0; } + if (cms->d.envelopedData->encryptedContentInfo->havenocert + && !cms->d.envelopedData->encryptedContentInfo->debug) { + X509_ALGOR *calg = ec->contentEncryptionAlgorithm; + const EVP_CIPHER *ciph = EVP_get_cipherbyobj(calg->algorithm); + + if (ciph == NULL) { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_UNKNOWN_CIPHER); + return 0; + } + + fixlen = EVP_CIPHER_key_length(ciph); + } + ktri->pctx = EVP_PKEY_CTX_new(pkey, NULL); if (!ktri->pctx) return 0; @@ -460,7 +474,9 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, if (EVP_PKEY_decrypt(ktri->pctx, ek, &eklen, ktri->encryptedKey->data, - ktri->encryptedKey->length) <= 0) { + ktri->encryptedKey->length) <= 0 + || eklen == 0 + || (fixlen != 0 && eklen != fixlen)) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB); goto err; } diff --git a/crypto/cms/cms_lcl.h b/crypto/cms/cms_lcl.h index 20f2c25f5a..f1f78e6a47 100644 --- a/crypto/cms/cms_lcl.h +++ b/crypto/cms/cms_lcl.h @@ -172,6 +172,8 @@ struct CMS_EncryptedContentInfo_st { size_t keylen; /* Set to 1 if we are debugging decrypt and don't fake keys for MMA */ int debug; + /* Set to 1 if we have no cert and need extra safety measures for MMA */ + int havenocert; }; struct CMS_RecipientInfo_st { diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index 07e3472e10..0b3d96ca62 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -737,6 +737,10 @@ int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, cms->d.envelopedData->encryptedContentInfo->debug = 1; else cms->d.envelopedData->encryptedContentInfo->debug = 0; + if (!cert) + cms->d.envelopedData->encryptedContentInfo->havenocert = 1; + else + cms->d.envelopedData->encryptedContentInfo->havenocert = 0; if (!pk && !cert && !dcont && !out) return 1; if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert)) diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c index 6a463680d7..63bc88269f 100644 --- a/crypto/pkcs7/pk7_doit.c +++ b/crypto/pkcs7/pk7_doit.c @@ -191,7 +191,8 @@ static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, } static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen, - PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey) + PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey, + size_t fixlen) { EVP_PKEY_CTX *pctx = NULL; unsigned char *ek = NULL; @@ -224,7 +225,9 @@ static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen, } if (EVP_PKEY_decrypt(pctx, ek, &eklen, - ri->enc_key->data, ri->enc_key->length) <= 0) { + ri->enc_key->data, ri->enc_key->length) <= 0 + || eklen == 0 + || (fixlen != 0 && eklen != fixlen)) { ret = 0; PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB); goto err; @@ -571,13 +574,14 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) { ri = sk_PKCS7_RECIP_INFO_value(rsk, i); - if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0) + if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey, + EVP_CIPHER_key_length(evp_cipher)) < 0) goto err; ERR_clear_error(); } } else { /* Only exit on fatal errors, not decrypt failure */ - if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0) + if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey, 0) < 0) goto err; ERR_clear_error(); } |