Fix CMS so that it still works with non fetchable algorithms.
authorShane Lontis <shane.lontis@oracle.com>
Thu, 20 Aug 2020 03:28:11 +0000 (13:28 +1000)
committerDmitry Belyavskiy <beldmit@gmail.com>
Sat, 22 Aug 2020 08:07:14 +0000 (11:07 +0300)
Fixes #12633

For CMS the Gost engine still requires calls to EVP_get_digestbyname() and EVP_get_cipherbyname() when
EVP_MD_fetch() and EVP_CIPHER_fetch() return NULL.

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/12689)

crypto/cms/cms_enc.c
crypto/cms/cms_env.c
crypto/cms/cms_lib.c
crypto/cms/cms_sd.c

index e25453ec9cc15edc834a02cff43b99282b0e223c..48934ef2a150a7447f44fdd4312fa77f1620a2a6 100644 (file)
@@ -45,6 +45,7 @@ BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
 
     BIO_get_cipher_ctx(b, &ctx);
 
+    (void)ERR_set_mark();
     if (enc) {
         cipher = ec->cipher;
         /*
@@ -58,17 +59,21 @@ BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
     if (cipher != NULL) {
         fetched_ciph = EVP_CIPHER_fetch(cms_ctx->libctx, EVP_CIPHER_name(cipher),
                                         cms_ctx->propq);
-        if (fetched_ciph == NULL) {
-            CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_UNKNOWN_CIPHER);
-            goto err;
-        }
+        if (fetched_ciph != NULL)
+            cipher = fetched_ciph;
+    }
+    if (cipher == NULL) {
+        (void)ERR_clear_last_mark();
+        CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_UNKNOWN_CIPHER);
+        goto err;
     }
-    if (EVP_CipherInit_ex(ctx, fetched_ciph, NULL, NULL, NULL, enc) <= 0) {
+    (void)ERR_pop_to_mark();
+
+    if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc) <= 0) {
         CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
                CMS_R_CIPHER_INITIALISATION_ERROR);
         goto err;
     }
-    EVP_CIPHER_free(fetched_ciph);
 
     if (enc) {
         int ivlen;
@@ -159,6 +164,7 @@ BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
     ok = 1;
 
  err:
+    EVP_CIPHER_free(fetched_ciph);
     if (!keep_key || !ok) {
         OPENSSL_clear_free(ec->key, ec->keylen);
         ec->key = NULL;
index 94961cd038a5933406ebb97fe08ea23cf9b04e73..1fed65c44296119512e7883bffc338e5694fb04d 100644 (file)
@@ -466,7 +466,8 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
     size_t eklen;
     int ret = 0;
     size_t fixlen = 0;
-    EVP_CIPHER *ciph = NULL;
+    const EVP_CIPHER *cipher = NULL;
+    EVP_CIPHER *fetched_cipher = NULL;
     CMS_EncryptedContentInfo *ec;
     const CMS_CTX *ctx = cms_get0_cmsctx(cms);
 
@@ -482,14 +483,22 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
         X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
         const char *name = OBJ_nid2sn(OBJ_obj2nid(calg->algorithm));
 
-        ciph = EVP_CIPHER_fetch(ctx->libctx, name, ctx->propq);
-        if (ciph == NULL) {
+        (void)ERR_set_mark();
+        fetched_cipher = EVP_CIPHER_fetch(ctx->libctx, name, ctx->propq);
+
+        if (fetched_cipher != NULL)
+            cipher = fetched_cipher;
+        else
+            cipher = EVP_get_cipherbyobj(calg->algorithm);
+        if (cipher == NULL) {
+            (void)ERR_clear_last_mark();
             CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_UNKNOWN_CIPHER);
             return 0;
         }
+        (void)ERR_pop_to_mark();
 
-        fixlen = EVP_CIPHER_key_length(ciph);
-        EVP_CIPHER_free(ciph);
+        fixlen = EVP_CIPHER_key_length(cipher);
+        EVP_CIPHER_free(fetched_cipher);
     }
 
     ktri->pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkey, ctx->propq);
@@ -514,7 +523,6 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
         goto err;
 
     ek = OPENSSL_malloc(eklen);
-
     if (ek == NULL) {
         CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, ERR_R_MALLOC_FAILURE);
         goto err;
index 92321dfc33dc6e1540b8684bd408c501686e0c21..7c9b2494a2b5adb2f56f35f27c4454553d91e83e 100644 (file)
@@ -394,26 +394,37 @@ BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm,
 {
     BIO *mdbio = NULL;
     const ASN1_OBJECT *digestoid;
-    EVP_MD *digest = NULL;
+    const EVP_MD *digest = NULL;
+    EVP_MD *fetched_digest = NULL;
     const char *alg;
 
     X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
     alg = OBJ_nid2sn(OBJ_obj2nid(digestoid));
-    digest = EVP_MD_fetch(ctx->libctx, alg, ctx->propq);
+
+    (void)ERR_set_mark();
+    fetched_digest = EVP_MD_fetch(ctx->libctx, alg, ctx->propq);
+
+    if (fetched_digest != NULL)
+        digest = fetched_digest;
+    else
+        digest = EVP_get_digestbyobj(digestoid);
     if (digest == NULL) {
+        (void)ERR_clear_last_mark();
         CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO,
                CMS_R_UNKNOWN_DIGEST_ALGORITHM);
         goto err;
     }
+    (void)ERR_pop_to_mark();
+
     mdbio = BIO_new(BIO_f_md());
     if (mdbio == NULL || !BIO_set_md(mdbio, digest)) {
         CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO, CMS_R_MD_BIO_INIT_ERROR);
         goto err;
     }
-    EVP_MD_free(digest);
+    EVP_MD_free(fetched_digest);
     return mdbio;
  err:
-    EVP_MD_free(digest);
+    EVP_MD_free(fetched_digest);
     BIO_free(mdbio);
     return NULL;
 }
index 4fac4e6182aa5a3c232c92089d7be0c230543c30..c11d44487bb014b86c9a76afb76802b24e43a7ac 100644 (file)
@@ -817,7 +817,8 @@ int CMS_SignerInfo_verify(CMS_SignerInfo *si)
     unsigned char *abuf = NULL;
     int alen, r = -1;
     const char *name;
-    EVP_MD *md = NULL;
+    const EVP_MD *md;
+    EVP_MD *fetched_md = NULL;
     const CMS_CTX *ctx = si->cms_ctx;
 
     if (si->pkey == NULL) {
@@ -829,9 +830,21 @@ int CMS_SignerInfo_verify(CMS_SignerInfo *si)
         return -1;
 
     name = OBJ_nid2sn(OBJ_obj2nid(si->digestAlgorithm->algorithm));
-    md = EVP_MD_fetch(ctx->libctx, name, ctx->propq);
-    if (md == NULL)
+
+    (void)ERR_set_mark();
+    fetched_md = EVP_MD_fetch(ctx->libctx, name, ctx->propq);
+
+    if (fetched_md != NULL)
+        md = fetched_md;
+    else
+        md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
+    if (md == NULL) {
+        (void)ERR_clear_last_mark();
+        CMSerr(0, CMS_R_UNKNOWN_DIGEST_ALGORITHM);
         return -1;
+    }
+    (void)ERR_pop_to_mark();
+
     if (si->mctx == NULL && (si->mctx = EVP_MD_CTX_new()) == NULL) {
         CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -860,7 +873,7 @@ int CMS_SignerInfo_verify(CMS_SignerInfo *si)
     if (r <= 0)
         CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_VERIFICATION_FAILURE);
  err:
-    EVP_MD_free(md);
+    EVP_MD_free(fetched_md);
     EVP_MD_CTX_reset(mctx);
     return r;
 }