forked from rpms/openssl
148 lines
5.7 KiB
Diff
148 lines
5.7 KiB
Diff
From 08229ad838c50f644d7e928e2eef147b4308ad64 Mon Sep 17 00:00:00 2001
|
|
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
|
|
Date: Sun, 1 Sep 2019 00:16:28 +0200
|
|
Subject: [PATCH] Fix 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.
|
|
|
|
Reviewed-by: Matt Caswell <matt@openssl.org>
|
|
(Merged from https://github.com/openssl/openssl/pull/9777)
|
|
|
|
(cherry picked from commit 5840ed0cd1e6487d247efbc1a04136a41d7b3a37)
|
|
---
|
|
crypto/cms/cms_env.c | 18 +++++++++++++++++-
|
|
crypto/cms/cms_lcl.h | 2 ++
|
|
crypto/cms/cms_smime.c | 4 ++++
|
|
crypto/pkcs7/pk7_doit.c | 12 ++++++++----
|
|
5 files changed, 45 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c
|
|
index bb95af75e3..25df1c40b1 100644
|
|
--- a/crypto/cms/cms_env.c
|
|
+++ b/crypto/cms/cms_env.c
|
|
@@ -363,6 +363,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;
|
|
|
|
@@ -371,6 +372,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 == NULL)
|
|
return 0;
|
|
@@ -401,7 +415,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 b5c06b7f6c..8eddb02493 100644
|
|
--- a/crypto/cms/cms_lcl.h
|
|
+++ b/crypto/cms/cms_lcl.h
|
|
@@ -125,6 +125,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 5dcf803f4b..3a26108b8c 100644
|
|
--- a/crypto/cms/cms_smime.c
|
|
+++ b/crypto/cms/cms_smime.c
|
|
@@ -743,6 +743,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 ee08e602a1..15a6160cfe 100644
|
|
--- a/crypto/pkcs7/pk7_doit.c
|
|
+++ b/crypto/pkcs7/pk7_doit.c
|
|
@@ -137,7 +137,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;
|
|
@@ -170,7 +171,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;
|
|
@@ -499,13 +502,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();
|
|
}
|
|
--
|
|
2.20.1
|
|
|