CMS public key parameter support.
authorDr. Stephen Henson <steve@openssl.org>
Wed, 19 Jun 2013 17:17:14 +0000 (18:17 +0100)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 21 Jun 2013 20:33:00 +0000 (21:33 +0100)
Add support for customisation of CMS handling of signed and enveloped
data from custom public key parameters.

This will provide support for RSA-PSS and RSA-OAEP but could also be
applied to other algorithms.

crypto/cms/cms.h
crypto/cms/cms_asn1.c
crypto/cms/cms_env.c
crypto/cms/cms_err.c
crypto/cms/cms_lcl.h
crypto/cms/cms_sd.c

index 198688e..1624b79 100644 (file)
@@ -112,6 +112,7 @@ DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
 #define CMS_REUSE_DIGEST               0x8000
 #define CMS_USE_KEYID                  0x10000
 #define CMS_DEBUG_DECRYPT              0x20000
+#define CMS_KEY_PARAM                  0x40000
 
 const ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms);
 
@@ -190,6 +191,7 @@ int CMS_decrypt_set1_password(CMS_ContentInfo *cms,
 
 STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms);
 int CMS_RecipientInfo_type(CMS_RecipientInfo *ri);
+EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri);
 CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher);
 CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
                                        X509 *recip, unsigned int flags);
@@ -256,6 +258,8 @@ int CMS_SignedData_init(CMS_ContentInfo *cms);
 CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
                        X509 *signer, EVP_PKEY *pk, const EVP_MD *md,
                        unsigned int flags);
+EVP_PKEY_CTX *CMS_SignerInfo_get0_pkey_ctx(CMS_SignerInfo *si);
+EVP_MD_CTX *CMS_SignerInfo_get0_md_ctx(CMS_SignerInfo *si);
 STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms);
 
 void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer);
@@ -374,6 +378,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_F_CMS_ENVELOPEDDATA_CREATE                  124
 #define CMS_F_CMS_ENVELOPEDDATA_INIT_BIO                125
 #define CMS_F_CMS_ENVELOPED_DATA_INIT                   126
+#define CMS_F_CMS_ENV_ASN1_CTRL                                 171
 #define CMS_F_CMS_FINAL                                         127
 #define CMS_F_CMS_GET0_CERTIFICATE_CHOICES              128
 #define CMS_F_CMS_GET0_CONTENT                          129
@@ -399,6 +404,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_F_CMS_RECIPIENTINFO_SET0_KEY                144
 #define CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD           168
 #define CMS_F_CMS_RECIPIENTINFO_SET0_PKEY               145
+#define CMS_F_CMS_SD_ASN1_CTRL                          170
 #define CMS_F_CMS_SET1_SIGNERIDENTIFIER                         146
 #define CMS_F_CMS_SET_DETACHED                          147
 #define CMS_F_CMS_SIGN                                  148
index cfe67fb..6a692cd 100644 (file)
@@ -97,6 +97,8 @@ static int cms_si_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
                        EVP_PKEY_free(si->pkey);
                if (si->signer)
                        X509_free(si->signer);
+               if (si->pctx)
+                       EVP_MD_CTX_cleanup(&si->mctx);
                }
        return 1;
        }
@@ -227,6 +229,8 @@ static int cms_ri_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
                                EVP_PKEY_free(ktri->pkey);
                        if (ktri->recip)
                                X509_free(ktri->recip);
+                       if (ktri->pctx)
+                               EVP_PKEY_CTX_free(ktri->pctx);
                        }
                else if (ri->type == CMS_RECIPINFO_KEK)
                        {
index 632dbae..c26dd59 100644 (file)
@@ -103,6 +103,27 @@ static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms)
        return cms_get0_enveloped(cms);
        }
 
+static int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd)
+       {
+       EVP_PKEY *pkey = ri->d.ktri->pkey;
+       int i;
+       if (!pkey->ameth || !pkey->ameth->pkey_ctrl)
+               return 1;
+       i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_ENVELOPE, cmd, ri);
+       if (i == -2)
+               {
+               CMSerr(CMS_F_CMS_ENV_ASN1_CTRL,
+                               CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
+               return 0;
+               }
+       if (i <= 0)
+               {
+               CMSerr(CMS_F_CMS_ENV_ASN1_CTRL, CMS_R_CTRL_FAILURE);
+               return 0;
+               }
+       return 1;
+       }
+
 STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms)
        {
        CMS_EnvelopedData *env;
@@ -117,6 +138,13 @@ int CMS_RecipientInfo_type(CMS_RecipientInfo *ri)
        return ri->type;
        }
 
+EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri)
+       {
+       if (ri->type == CMS_RECIPINFO_TRANS)
+               return ri->d.ktri->pctx;
+       return NULL;
+       }
+
 CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher)
        {
        CMS_ContentInfo *cms;
@@ -151,7 +179,7 @@ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
        CMS_KeyTransRecipientInfo *ktri;
        CMS_EnvelopedData *env;
        EVP_PKEY *pk = NULL;
-       int i, type;
+       int type;
        env = cms_get0_enveloped(cms);
        if (!env)
                goto err;
@@ -200,23 +228,16 @@ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
        if (!cms_set1_SignerIdentifier(ktri->rid, recip, type))
                goto err;
 
-       if (pk->ameth && pk->ameth->pkey_ctrl)
+       if (flags & CMS_KEY_PARAM)
                {
-               i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_ENVELOPE,
-                                               0, ri);
-               if (i == -2)
-                       {
-                       CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
-                               CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
+               ktri->pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
+               if (!ktri->pctx)
+                       return 0;
+               if (EVP_PKEY_encrypt_init(ktri->pctx) <= 0)
                        goto err;
-                       }
-               if (i <= 0)
-                       {
-                       CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
-                               CMS_R_CTRL_FAILURE);
-                       goto err;
-                       }
                }
+       else if (!cms_env_asn1_ctrl(ri, 0))
+               goto err;
 
        if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
                goto merr;
@@ -302,7 +323,7 @@ static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
        {
        CMS_KeyTransRecipientInfo *ktri;
        CMS_EncryptedContentInfo *ec;
-       EVP_PKEY_CTX *pctx = NULL;
+       EVP_PKEY_CTX *pctx;
        unsigned char *ek = NULL;
        size_t eklen;
 
@@ -317,12 +338,22 @@ static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
        ktri = ri->d.ktri;
        ec = cms->d.envelopedData->encryptedContentInfo;
 
-       pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
-       if (!pctx)
-               return 0;
+       pctx = ktri->pctx;
 
-       if (EVP_PKEY_encrypt_init(pctx) <= 0)
-               goto err;
+       if (pctx)
+               {
+               if (!cms_env_asn1_ctrl(ri, 0))
+                       goto err;
+               }
+       else
+               {
+               pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
+               if (!pctx)
+                       return 0;
+
+               if (EVP_PKEY_encrypt_init(pctx) <= 0)
+                       goto err;
+               }
 
        if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
                                EVP_PKEY_CTRL_CMS_ENCRYPT, 0, ri) <= 0)
@@ -353,7 +384,10 @@ static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
 
        err:
        if (pctx)
+               {
                EVP_PKEY_CTX_free(pctx);
+               ktri->pctx = NULL;
+               }
        if (ek)
                OPENSSL_free(ek);
        return ret;
@@ -366,7 +400,7 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
                                                        CMS_RecipientInfo *ri)
        {
        CMS_KeyTransRecipientInfo *ktri = ri->d.ktri;
-       EVP_PKEY_CTX *pctx = NULL;
+       EVP_PKEY *pkey = ktri->pkey;
        unsigned char *ek = NULL;
        size_t eklen;
        int ret = 0;
@@ -380,21 +414,24 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
                return 0;
                }
 
-       pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
-       if (!pctx)
+       ktri->pctx = EVP_PKEY_CTX_new(pkey, NULL);
+       if (!ktri->pctx)
                return 0;
 
-       if (EVP_PKEY_decrypt_init(pctx) <= 0)
+       if (EVP_PKEY_decrypt_init(ktri->pctx) <= 0)
+               goto err;
+
+       if (!cms_env_asn1_ctrl(ri, 1))
                goto err;
 
-       if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT,
+       if (EVP_PKEY_CTX_ctrl(ktri->pctx, -1, EVP_PKEY_OP_DECRYPT,
                                EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0)
                {
                CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CTRL_ERROR);
                goto err;
                }
 
-       if (EVP_PKEY_decrypt(pctx, NULL, &eklen,
+       if (EVP_PKEY_decrypt(ktri->pctx, NULL, &eklen,
                                ktri->encryptedKey->data,
                                ktri->encryptedKey->length) <= 0)
                goto err;
@@ -408,7 +445,7 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
                goto err;
                }
 
-       if (EVP_PKEY_decrypt(pctx, ek, &eklen,
+       if (EVP_PKEY_decrypt(ktri->pctx, ek, &eklen,
                                ktri->encryptedKey->data,
                                ktri->encryptedKey->length) <= 0)
                {
@@ -428,8 +465,11 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
        ec->keylen = eklen;
 
        err:
-       if (pctx)
-               EVP_PKEY_CTX_free(pctx);
+       if (ktri->pctx)
+               {
+               EVP_PKEY_CTX_free(ktri->pctx);
+               ktri->pctx = NULL;
+               }
        if (!ret && ek)
                OPENSSL_free(ek);
 
index cc58ea5..35aca59 100644 (file)
@@ -103,6 +103,7 @@ static ERR_STRING_DATA CMS_str_functs[]=
 {ERR_FUNC(CMS_F_CMS_ENVELOPEDDATA_CREATE),     "CMS_EnvelopedData_create"},
 {ERR_FUNC(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO),   "cms_EnvelopedData_init_bio"},
 {ERR_FUNC(CMS_F_CMS_ENVELOPED_DATA_INIT),      "CMS_ENVELOPED_DATA_INIT"},
+{ERR_FUNC(CMS_F_CMS_ENV_ASN1_CTRL),    "CMS_ENV_ASN1_CTRL"},
 {ERR_FUNC(CMS_F_CMS_FINAL),    "CMS_final"},
 {ERR_FUNC(CMS_F_CMS_GET0_CERTIFICATE_CHOICES), "CMS_GET0_CERTIFICATE_CHOICES"},
 {ERR_FUNC(CMS_F_CMS_GET0_CONTENT),     "CMS_get0_content"},
@@ -128,6 +129,7 @@ static ERR_STRING_DATA CMS_str_functs[]=
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_KEY),   "CMS_RecipientInfo_set0_key"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD),      "CMS_RecipientInfo_set0_password"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY),  "CMS_RecipientInfo_set0_pkey"},
+{ERR_FUNC(CMS_F_CMS_SD_ASN1_CTRL),     "CMS_SD_ASN1_CTRL"},
 {ERR_FUNC(CMS_F_CMS_SET1_SIGNERIDENTIFIER),    "cms_set1_SignerIdentifier"},
 {ERR_FUNC(CMS_F_CMS_SET_DETACHED),     "CMS_set_detached"},
 {ERR_FUNC(CMS_F_CMS_SIGN),     "CMS_sign"},
index d5a70b4..b62dc72 100644 (file)
@@ -140,6 +140,9 @@ struct CMS_SignerInfo_st
        /* Signing certificate and key */
        X509 *signer;
        EVP_PKEY *pkey;
+       /* Digest and public key context for alternative parameters */
+       EVP_MD_CTX mctx;
+       EVP_PKEY_CTX *pctx;
        };
 
 struct CMS_SignerIdentifier_st
@@ -202,6 +205,8 @@ struct CMS_KeyTransRecipientInfo_st
        /* Recipient Key and cert */
        X509 *recip;
        EVP_PKEY *pkey;
+       /* Public key context for this operation */
+       EVP_PKEY_CTX *pctx;
        };
 
 struct CMS_KeyAgreeRecipientInfo_st
index f448a35..b7dbf52 100644 (file)
@@ -297,6 +297,27 @@ int cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert)
                return -1;
        }
 
+static int cms_sd_asn1_ctrl(CMS_SignerInfo *si, int cmd)
+       {
+       EVP_PKEY *pkey = si->pkey;
+       int i;
+       if (!pkey->ameth || !pkey->ameth->pkey_ctrl)
+               return 1;
+       i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_SIGN, cmd, si);
+       if (i == -2)
+               {
+               CMSerr(CMS_F_CMS_SD_ASN1_CTRL,
+                               CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
+               return 0;
+               }
+       if (i <= 0)
+               {
+               CMSerr(CMS_F_CMS_SD_ASN1_CTRL, CMS_R_CTRL_FAILURE);
+               return 0;
+               }
+       return 1;
+       }
+
 CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
                        X509 *signer, EVP_PKEY *pk, const EVP_MD *md,
                        unsigned int flags)
@@ -324,6 +345,8 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
 
        si->pkey = pk;
        si->signer = signer;
+       EVP_MD_CTX_init(&si->mctx);
+       si->pctx = NULL;
 
        if (flags & CMS_USE_KEYID)
                {
@@ -385,23 +408,8 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
                        }
                }
 
-       if (pk->ameth && pk->ameth->pkey_ctrl)
-               {
-               i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_SIGN,
-                                               0, si);
-               if (i == -2)
-                       {
-                       CMSerr(CMS_F_CMS_ADD1_SIGNER,
-                               CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
-                       goto err;
-                       }
-               if (i <= 0)
-                       {
-                       CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_CTRL_FAILURE);
-                       goto err;
-                       }
-               }
-
+       if (!(flags & CMS_KEY_PARAM) && !cms_sd_asn1_ctrl(si, 0))
+               goto err;
        if (!(flags & CMS_NOATTR))
                {
                /* Initialialize signed attributes strutucture so other
@@ -429,7 +437,7 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
                        {
                        if (!cms_copy_messageDigest(cms, si))
                                goto err;
-                       if (!(flags & CMS_PARTIAL) &&
+                       if (!(flags & (CMS_PARTIAL|CMS_KEY_PARAM)) &&
                                        !CMS_SignerInfo_sign(si))
                                goto err;
                        }
@@ -442,6 +450,22 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
                        goto merr;
                }
 
+       if (flags & CMS_KEY_PARAM)
+               {
+               if (flags & CMS_NOATTR)
+                       {
+                       si->pctx = EVP_PKEY_CTX_new(si->pkey, NULL);
+                       if (!si->pctx)
+                               goto err;
+                       if (EVP_PKEY_sign_init(si->pctx) <= 0)
+                               goto err;
+                       if (EVP_PKEY_CTX_set_signature_md(si->pctx, md) <= 0)
+                               goto err;
+                       }
+               else if (EVP_DigestSignInit(&si->mctx, &si->pctx, md, NULL, pk) <= 0)
+                       goto err;
+               }
+
        if (!sd->signerInfos)
                sd->signerInfos = sk_CMS_SignerInfo_new_null();
        if (!sd->signerInfos ||
@@ -489,6 +513,16 @@ static int cms_add1_signingTime(CMS_SignerInfo *si, ASN1_TIME *t)
 
        }
 
+EVP_PKEY_CTX *CMS_SignerInfo_get0_pkey_ctx(CMS_SignerInfo *si)
+       {
+       return si->pctx;
+       }
+
+EVP_MD_CTX *CMS_SignerInfo_get0_md_ctx(CMS_SignerInfo *si)
+       {
+       return &si->mctx;
+       }
+
 STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms)
        {
        CMS_SignedData *sd;
@@ -621,9 +655,9 @@ static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms,
        {
        EVP_MD_CTX mctx;
        int r = 0;
+       EVP_PKEY_CTX *pctx = NULL;
        EVP_MD_CTX_init(&mctx);
 
-
        if (!si->pkey)
                {
                CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, CMS_R_NO_PRIVATE_KEY);
@@ -632,6 +666,9 @@ static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms,
 
        if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm))
                goto err;
+       /* Set SignerInfo algortihm details if we used custom parametsr */
+       if (si->pctx && !cms_sd_asn1_ctrl(si, 0))
+               goto err;
 
        /* If any signed attributes calculate and add messageDigest attribute */
 
@@ -654,6 +691,26 @@ static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms,
                if (!CMS_SignerInfo_sign(si))
                        goto err;
                }
+       else if (si->pctx)
+               {
+               unsigned char *sig;
+               size_t siglen;
+               unsigned char md[EVP_MAX_MD_SIZE];
+               unsigned int mdlen;
+               pctx = si->pctx;
+               if (!EVP_DigestFinal_ex(&mctx, md, &mdlen))
+                       goto err;
+               sig = OPENSSL_malloc(EVP_PKEY_size(si->pkey));
+               if (!sig)
+                       {
+                       CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN,
+                                       ERR_R_MALLOC_FAILURE);
+                       goto err;
+                       }
+               if (EVP_PKEY_sign(pctx, sig, &siglen, md, mdlen) <= 0)
+                       goto err;
+               ASN1_STRING_set0(si->signature, sig, siglen);
+               }
        else
                {
                unsigned char *sig;
@@ -679,6 +736,8 @@ static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms,
 
        err:
        EVP_MD_CTX_cleanup(&mctx);
+       if (pctx)
+               EVP_PKEY_CTX_free(pctx);
        return r;
 
        }
@@ -701,7 +760,7 @@ int cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain)
 
 int CMS_SignerInfo_sign(CMS_SignerInfo *si)
        {
-       EVP_MD_CTX mctx;
+       EVP_MD_CTX *mctx = &si->mctx;
        EVP_PKEY_CTX *pctx;
        unsigned char *abuf = NULL;
        int alen;
@@ -712,7 +771,6 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si)
        if (md == NULL)
                return 0;
 
-       EVP_MD_CTX_init(&mctx);
 
        if (CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1) < 0)
                {
@@ -720,8 +778,14 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si)
                        goto err;
                }
 
-       if (EVP_DigestSignInit(&mctx, &pctx, md, NULL, si->pkey) <= 0)
-               goto err;
+       if (si->pctx)
+               pctx = si->pctx;
+       else
+               {
+               EVP_MD_CTX_init(mctx);
+               if (EVP_DigestSignInit(mctx, &pctx, md, NULL, si->pkey) <= 0)
+                       goto err;
+               }
 
        if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
                                EVP_PKEY_CTRL_CMS_SIGN, 0, si) <= 0)
@@ -734,15 +798,15 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si)
                                ASN1_ITEM_rptr(CMS_Attributes_Sign));
        if(!abuf)
                goto err;
-       if (EVP_DigestSignUpdate(&mctx, abuf, alen) <= 0)
+       if (EVP_DigestSignUpdate(mctx, abuf, alen) <= 0)
                goto err;
-       if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0)
+       if (EVP_DigestSignFinal(mctx, NULL, &siglen) <= 0)
                goto err;
        OPENSSL_free(abuf);
        abuf = OPENSSL_malloc(siglen);
        if(!abuf)
                goto err;
-       if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0)
+       if (EVP_DigestSignFinal(mctx, abuf, &siglen) <= 0)
                goto err;
 
        if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
@@ -752,7 +816,7 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si)
                goto err;
                }
 
-       EVP_MD_CTX_cleanup(&mctx);
+       EVP_MD_CTX_cleanup(mctx);
 
        ASN1_STRING_set0(si->signature, abuf, siglen);
 
@@ -761,15 +825,14 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si)
        err:
        if (abuf)
                OPENSSL_free(abuf);
-       EVP_MD_CTX_cleanup(&mctx);
+       EVP_MD_CTX_cleanup(mctx);
        return 0;
 
        }
 
 int CMS_SignerInfo_verify(CMS_SignerInfo *si)
        {
-       EVP_MD_CTX mctx;
-       EVP_PKEY_CTX *pctx;
+       EVP_MD_CTX *mctx = &si->mctx;
        unsigned char *abuf = NULL;
        int alen, r = -1;
        const EVP_MD *md = NULL;
@@ -783,27 +846,30 @@ int CMS_SignerInfo_verify(CMS_SignerInfo *si)
        md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
        if (md == NULL)
                return -1;
-       EVP_MD_CTX_init(&mctx);
-       if (EVP_DigestVerifyInit(&mctx, &pctx, md, NULL, si->pkey) <= 0)
+       EVP_MD_CTX_init(mctx);
+       if (EVP_DigestVerifyInit(mctx, &si->pctx, md, NULL, si->pkey) <= 0)
+               goto err;
+
+       if (!cms_sd_asn1_ctrl(si, 1))
                goto err;
 
        alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs,&abuf,
                                ASN1_ITEM_rptr(CMS_Attributes_Verify));
        if(!abuf)
                goto err;
-       r = EVP_DigestVerifyUpdate(&mctx, abuf, alen);
+       r = EVP_DigestVerifyUpdate(mctx, abuf, alen);
        OPENSSL_free(abuf);
        if (r <= 0)
                {
                r = -1;
                goto err;
                }
-       r = EVP_DigestVerifyFinal(&mctx,
+       r = EVP_DigestVerifyFinal(mctx,
                        si->signature->data, si->signature->length);
        if (r <= 0)
                CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_VERIFICATION_FAILURE);
        err:
-       EVP_MD_CTX_cleanup(&mctx);
+       EVP_MD_CTX_cleanup(mctx);
        return r;
        }
 
@@ -843,7 +909,10 @@ int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain)
        {
        ASN1_OCTET_STRING *os = NULL;
        EVP_MD_CTX mctx;
+       EVP_PKEY_CTX *pkctx = NULL;
        int r = -1;
+       unsigned char mval[EVP_MAX_MD_SIZE];
+       unsigned int mlen;
        EVP_MD_CTX_init(&mctx);
        /* If we have any signed attributes look for messageDigest value */
        if (CMS_signed_get_attr_count(si) >= 0)
@@ -862,18 +931,17 @@ int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain)
        if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm))
                goto err;
 
+       if (EVP_DigestFinal_ex(&mctx, mval, &mlen) <= 0)
+               {
+               CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
+                       CMS_R_UNABLE_TO_FINALIZE_CONTEXT);
+               goto err;
+               }
+
        /* If messageDigest found compare it */
 
        if (os)
                {
-               unsigned char mval[EVP_MAX_MD_SIZE];
-               unsigned int mlen;
-               if (EVP_DigestFinal_ex(&mctx, mval, &mlen) <= 0)
-                       {
-                       CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
-                               CMS_R_UNABLE_TO_FINALIZE_CONTEXT);
-                       goto err;
-                       }
                if (mlen != (unsigned int)os->length)
                        {
                        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
@@ -892,8 +960,18 @@ int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain)
                }
        else
                {
-               r = EVP_VerifyFinal(&mctx, si->signature->data,
-                                       si->signature->length, si->pkey);
+               const EVP_MD *md = EVP_MD_CTX_md(&mctx);
+               pkctx = EVP_PKEY_CTX_new(si->pkey, NULL);
+               if (EVP_PKEY_verify_init(pkctx) <= 0)
+                       goto err;
+               if (EVP_PKEY_CTX_set_signature_md(pkctx, md) <= 0)
+                       goto err;
+               si->pctx = pkctx;
+               if (!cms_sd_asn1_ctrl(si, 1))
+                       goto err;
+               r = EVP_PKEY_verify(pkctx, si->signature->data,
+                                       si->signature->length,
+                                       mval, mlen);
                if (r <= 0)
                        {
                        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
@@ -903,6 +981,8 @@ int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain)
                }
 
        err:
+       if (pkctx)
+               EVP_PKEY_CTX_free(pkctx);
        EVP_MD_CTX_cleanup(&mctx);
        return r;