Set version number correctly.
[openssl.git] / crypto / cms / cms_sd.c
index 6f31f6309fa87c0261045f5e8a78dbf8d4869632..ac5103abf7ccc04b61613697102730dfe440cdd6 100644 (file)
@@ -54,6 +54,7 @@
 #include "cryptlib.h"
 #include <openssl/asn1t.h>
 #include <openssl/pem.h>
+#include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include <openssl/err.h>
 #include <openssl/cms.h>
@@ -158,8 +159,8 @@ static void cms_sd_set_version(CMS_SignedData *sd)
                        if (sd->version < 3)
                                sd->version = 3;
                        }
-               else
-                       sd->version = 1;
+               else if (si->version < 1)
+                       si->version = 1;
                }
 
        if (sd->version < 1)
@@ -212,29 +213,13 @@ int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type)
        switch(type)
                {
                case CMS_SIGNERINFO_ISSUER_SERIAL:
-               sid->d.issuerAndSerialNumber =
-                       M_ASN1_new_of(CMS_IssuerAndSerialNumber);
-               if (!sid->d.issuerAndSerialNumber)
-                       goto merr;
-               if (!X509_NAME_set(&sid->d.issuerAndSerialNumber->issuer,
-                                       X509_get_issuer_name(cert)))
-                       goto merr;
-               if (!ASN1_STRING_copy(
-                       sid->d.issuerAndSerialNumber->serialNumber,
-                               X509_get_serialNumber(cert)))
-                       goto merr;
+               if (!cms_set1_ias(&sid->d.issuerAndSerialNumber, cert))
+                       return 0;
                break;
 
                case CMS_SIGNERINFO_KEYIDENTIFIER:
-               if (!cert->skid)
-                       {
-                       CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER,
-                                       CMS_R_CERTIFICATE_HAS_NO_KEYID);
+               if (!cms_set1_keyid(&sid->d.subjectKeyIdentifier, cert))
                        return 0;
-                       }
-               sid->d.subjectKeyIdentifier = ASN1_STRING_dup(cert->skid);
-               if (!sid->d.subjectKeyIdentifier)
-                       goto merr;
                break;
 
                default:
@@ -245,11 +230,6 @@ int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type)
        sid->type = type;
 
        return 1;
-
-       merr:
-       CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, ERR_R_MALLOC_FAILURE);
-       return 0;
-
        }
 
 int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid,
@@ -275,26 +255,33 @@ int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid,
 
 int cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert)
        {
-       int ret;
        if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL)
+               return cms_ias_cert_cmp(sid->d.issuerAndSerialNumber, cert);
+       else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
+               return cms_keyid_cert_cmp(sid->d.subjectKeyIdentifier, cert);
+       else
+               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)
                {
-               ret = X509_NAME_cmp(sid->d.issuerAndSerialNumber->issuer,
-                                       X509_get_issuer_name(cert));
-               if (ret)
-                       return ret;
-               return ASN1_INTEGER_cmp(sid->d.issuerAndSerialNumber->serialNumber,
-                                       X509_get_serialNumber(cert));
+               CMSerr(CMS_F_CMS_SD_ASN1_CTRL,
+                               CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
+               return 0;
                }
-       else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
+       if (i <= 0)
                {
-               X509_check_purpose(cert, -1, -1);
-               if (!cert->skid)
-                       return -1;
-               return ASN1_OCTET_STRING_cmp(sid->d.subjectKeyIdentifier,
-                                                       cert->skid);
+               CMSerr(CMS_F_CMS_SD_ASN1_CTRL, CMS_R_CTRL_FAILURE);
+               return 0;
                }
-       else
-               return -1;
+       return 1;
        }
 
 CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
@@ -324,6 +311,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)
                {
@@ -360,7 +349,7 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
                goto err;
                }
 
-       cms_DigestAlgorithm_set(si->digestAlgorithm, md);
+       X509_ALGOR_set_md(si->digestAlgorithm, md);
 
        /* See if digest is present in digestAlgorithms */
        for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++)
@@ -377,7 +366,7 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
                alg = X509_ALGOR_new();
                if (!alg)
                        goto merr;
-               cms_DigestAlgorithm_set(alg, md);
+               X509_ALGOR_set_md(alg, md);
                if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg))
                        {
                        X509_ALGOR_free(alg);
@@ -385,35 +374,21 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
                        }
                }
 
-       if (pk->ameth && pk->ameth->pkey_ctrl)
+       if (!(flags & CMS_KEY_PARAM) && !cms_sd_asn1_ctrl(si, 0))
+               goto err;
+       if (!(flags & CMS_NOATTR))
                {
-               i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_SIGN,
-                                               0, si);
-               if (i == -2)
+               /* Initialialize signed attributes strutucture so other
+                * attributes such as signing time etc are added later
+                * even if we add none here.
+                */
+               if (!si->signedAttrs)
                        {
-                       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;
+                       si->signedAttrs = sk_X509_ATTRIBUTE_new_null();
+                       if (!si->signedAttrs)
+                               goto merr;
                        }
-               }
 
-       if (!(flags & CMS_NOATTR))
-               {
-               /* Copy content type across */
-               ASN1_OBJECT *ctype =
-                               OBJ_dup(sd->encapContentInfo->eContentType); 
-               if (!ctype)
-                       goto merr;
-               i = CMS_signed_add1_attr_by_NID(si, NID_pkcs9_contentType,
-                                               V_ASN1_OBJECT, ctype, -1);
-               ASN1_OBJECT_free(ctype);
-               if (i <= 0)
-                       goto merr;
                if (!(flags & CMS_NOSMIMECAP))
                        {
                        STACK_OF(X509_ALGOR) *smcap = NULL;
@@ -428,7 +403,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;
                        }
@@ -441,6 +416,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 ||
@@ -488,6 +479,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;
@@ -615,13 +616,19 @@ void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk, X509 **signer,
                *psig = si->signatureAlgorithm;
        }
 
-static int cms_SignerInfo_content_sign(CMS_SignerInfo *si, BIO *chain)
+ASN1_OCTET_STRING *CMS_SignerInfo_get0_signature(CMS_SignerInfo *si)
+       {
+       return si->signature;
+       }
+
+static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms,
+                                       CMS_SignerInfo *si, BIO *chain)
        {
        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);
@@ -630,21 +637,52 @@ static int cms_SignerInfo_content_sign(CMS_SignerInfo *si, BIO *chain)
 
        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 */
 
        if (CMS_signed_get_attr_count(si) >= 0)
                {
+               ASN1_OBJECT *ctype =
+                       cms->d.signedData->encapContentInfo->eContentType; 
                unsigned char md[EVP_MAX_MD_SIZE];
                unsigned int mdlen;
-               EVP_DigestFinal_ex(&mctx, md, &mdlen);
+               if (!EVP_DigestFinal_ex(&mctx, md, &mdlen))
+                       goto err;
                if (!CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest,
                                                V_ASN1_OCTET_STRING,
                                                md, mdlen))
                        goto err;
+               /* Copy content type across */
+               if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_contentType,
+                                       V_ASN1_OBJECT, ctype, -1) <= 0)
+                       goto err;
                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;
+               siglen = EVP_PKEY_size(si->pkey);
+               sig = OPENSSL_malloc(siglen);
+               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;
@@ -670,6 +708,8 @@ static int cms_SignerInfo_content_sign(CMS_SignerInfo *si, BIO *chain)
 
        err:
        EVP_MD_CTX_cleanup(&mctx);
+       if (pctx)
+               EVP_PKEY_CTX_free(pctx);
        return r;
 
        }
@@ -683,7 +723,7 @@ int cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain)
        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
                {
                si = sk_CMS_SignerInfo_value(sinfos, i);
-               if (!cms_SignerInfo_content_sign(si, chain))
+               if (!cms_SignerInfo_content_sign(cms, si, chain))
                        return 0;
                }
        cms->d.signedData->encapContentInfo->partial = 0;
@@ -692,7 +732,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;
@@ -703,7 +743,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)
                {
@@ -711,8 +750,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)
@@ -725,15 +770,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,
@@ -743,7 +788,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);
 
@@ -752,15 +797,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;
@@ -774,27 +818,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)
+       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;
        }
 
@@ -834,7 +881,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)
@@ -853,18 +903,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,
@@ -883,8 +932,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,
@@ -894,6 +953,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;