(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]
+
*) Early start up entropy quality from the DEVRANDOM seed source has been
improved for older Linux systems. The RAND subsystem will wait for
/dev/random to be producing output before seeding from /dev/urandom.
unsigned char *ek = NULL;
size_t eklen;
int ret = 0;
+ size_t fixlen = 0;
CMS_EncryptedContentInfo *ec;
ec = cms->d.envelopedData->encryptedContentInfo;
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 == NULL)
return 0;
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;
}
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 {
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))
}
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;
}
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;
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();
}