Browse Source

Fix error handling in CMS_EncryptedData_encrypt

That caused several memory leaks in case of error.
Also when the CMS object that is created by CMS_EncryptedData_encrypt
is not used in the normal way, but instead just deleted
by CMS_ContentInfo_free some memory was lost.

Fixes #21985

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22008)
Bernd Edlinger 8 months ago
parent
commit
13dd772f61

+ 13 - 2
crypto/cms/cms_asn1.c

@@ -51,6 +51,7 @@ static int cms_si_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
         EVP_PKEY_free(si->pkey);
         X509_free(si->signer);
         EVP_MD_CTX_free(si->mctx);
+        EVP_PKEY_CTX_free(si->pctx);
     }
     return 1;
 }
@@ -89,11 +90,21 @@ ASN1_SEQUENCE(CMS_OriginatorInfo) = {
         ASN1_IMP_SET_OF_OPT(CMS_OriginatorInfo, crls, CMS_RevocationInfoChoice, 1)
 } static_ASN1_SEQUENCE_END(CMS_OriginatorInfo)
 
-ASN1_NDEF_SEQUENCE(CMS_EncryptedContentInfo) = {
+static int cms_ec_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+                     void *exarg)
+{
+    CMS_EncryptedContentInfo *ec = (CMS_EncryptedContentInfo *)*pval;
+
+    if (operation == ASN1_OP_FREE_POST)
+        OPENSSL_clear_free(ec->key, ec->keylen);
+    return 1;
+}
+
+ASN1_NDEF_SEQUENCE_cb(CMS_EncryptedContentInfo, cms_ec_cb) = {
         ASN1_SIMPLE(CMS_EncryptedContentInfo, contentType, ASN1_OBJECT),
         ASN1_SIMPLE(CMS_EncryptedContentInfo, contentEncryptionAlgorithm, X509_ALGOR),
         ASN1_IMP_OPT(CMS_EncryptedContentInfo, encryptedContent, ASN1_OCTET_STRING_NDEF, 0)
-} static_ASN1_NDEF_SEQUENCE_END(CMS_EncryptedContentInfo)
+} ASN1_NDEF_SEQUENCE_END_cb(CMS_EncryptedContentInfo, CMS_EncryptedContentInfo)
 
 ASN1_SEQUENCE(CMS_KeyTransRecipientInfo) = {
         ASN1_EMBED(CMS_KeyTransRecipientInfo, version, INT32),

+ 1 - 0
crypto/cms/cms_local.h

@@ -342,6 +342,7 @@ struct CMS_Receipt_st {
 
 DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo)
 DECLARE_ASN1_ITEM(CMS_SignerInfo)
+DECLARE_ASN1_ITEM(CMS_EncryptedContentInfo)
 DECLARE_ASN1_ITEM(CMS_IssuerAndSerialNumber)
 DECLARE_ASN1_ITEM(CMS_Attributes_Sign)
 DECLARE_ASN1_ITEM(CMS_Attributes_Verify)

+ 13 - 1
crypto/cms/cms_sd.c

@@ -375,6 +375,8 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
         } else if (EVP_DigestSignInit(si->mctx, &si->pctx, md, NULL, pk) <=
                    0)
             goto err;
+        else
+            EVP_MD_CTX_set_flags(si->mctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
     }
 
     if (!sd->signerInfos)
@@ -600,6 +602,7 @@ static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms,
         unsigned char md[EVP_MAX_MD_SIZE];
         unsigned int mdlen;
         pctx = si->pctx;
+        si->pctx = NULL;
         if (!EVP_DigestFinal_ex(mctx, md, &mdlen))
             goto err;
         siglen = EVP_PKEY_size(si->pkey);
@@ -680,6 +683,7 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si)
         EVP_MD_CTX_reset(mctx);
         if (EVP_DigestSignInit(mctx, &pctx, md, NULL, si->pkey) <= 0)
             goto err;
+        EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
         si->pctx = pctx;
     }
 
@@ -745,8 +749,13 @@ int CMS_SignerInfo_verify(CMS_SignerInfo *si)
         return -1;
     }
     mctx = si->mctx;
+    if (si->pctx != NULL) {
+        EVP_PKEY_CTX_free(si->pctx);
+        si->pctx = NULL;
+    }
     if (EVP_DigestVerifyInit(mctx, &si->pctx, md, NULL, si->pkey) <= 0)
         goto err;
+    EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
 
     if (!cms_sd_asn1_ctrl(si, 1))
         goto err;
@@ -859,8 +868,11 @@ int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain)
         if (EVP_PKEY_CTX_set_signature_md(pkctx, md) <= 0)
             goto err;
         si->pctx = pkctx;
-        if (!cms_sd_asn1_ctrl(si, 1))
+        if (!cms_sd_asn1_ctrl(si, 1)) {
+            si->pctx = NULL;
             goto err;
+        }
+        si->pctx = NULL;
         r = EVP_PKEY_verify(pkctx, si->signature->data,
                             si->signature->length, mval, mlen);
         if (r <= 0) {

+ 2 - 1
crypto/cms/cms_smime.c

@@ -211,7 +211,7 @@ CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
     if (cms == NULL)
         return NULL;
     if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen))
-        return NULL;
+        goto err;
 
     if (!(flags & CMS_DETACHED))
         CMS_set_detached(cms, 0);
@@ -220,6 +220,7 @@ CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
         || CMS_final(cms, in, NULL, flags))
         return cms;
 
+ err:
     CMS_ContentInfo_free(cms);
     return NULL;
 }

+ 1 - 0
fuzz/corpora/cms/2aba8037213156ea1593054768d4576cb8d08309

@@ -0,0 +1 @@
+0	*├H├В


+ 1 - 0
fuzz/corpora/cms/2aba8037213156ea1593054768d4576cb8d083ed

@@ -0,0 +1 @@
+0	*├H├В


+ 7 - 0
test/recipes/80-test_cms.t

@@ -288,6 +288,13 @@ my @smime_cms_tests = (
 	"-secretkey", "000102030405060708090A0B0C0D0E0F", "-out", "smtst.txt" ]
     ],
 
+    [ "encrypted content test streaming PEM format -noout, 128 bit AES key",
+      [ "-EncryptedData_encrypt", "-in", $smcont, "-outform", "PEM",
+	"-aes128", "-secretkey", "000102030405060708090A0B0C0D0E0F",
+	"-stream", "-noout" ],
+      [ "-help" ]
+    ],
+
 );
 
 my @smime_cms_comp_tests = (