From 6e3bc4f0730a3cb7d2d263153cb234da51637b38 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Tue, 18 Mar 2008 01:00:38 +0000 Subject: [PATCH] More support for KEK RecipientInfo. Generalise RecipientInfo and enveloped data handling so applications can add their own key lookup routines as well as using the standard ones. --- crypto/aes/Makefile | 4 +- crypto/aes/aes.h | 7 ++ crypto/aes/aes_wrap.c | 8 +- crypto/cms/cms.h | 14 ++- crypto/cms/cms_env.c | 269 +++++++++++++++++++++++++++++++++++------ crypto/cms/cms_err.c | 10 ++ crypto/cms/cms_smime.c | 47 ++++--- 7 files changed, 295 insertions(+), 64 deletions(-) diff --git a/crypto/aes/Makefile b/crypto/aes/Makefile index 632fdb55bd..80dcc3251c 100644 --- a/crypto/aes/Makefile +++ b/crypto/aes/Makefile @@ -24,8 +24,8 @@ APPS= LIB=$(TOP)/libcrypto.a LIBSRC=aes_core.c aes_misc.c aes_ecb.c aes_cbc.c aes_cfb.c aes_ofb.c \ - aes_ctr.c aes_ige.c -LIBOBJ=aes_misc.o aes_ecb.o aes_cfb.o aes_ofb.o aes_ctr.o aes_ige.o \ + aes_ctr.c aes_ige.c aes_wrap.c +LIBOBJ=aes_misc.o aes_ecb.o aes_cfb.o aes_ofb.o aes_ctr.o aes_ige.o aes_wrap.o \ $(AES_ENC) SRC= $(LIBSRC) diff --git a/crypto/aes/aes.h b/crypto/aes/aes.h index 949a754a0f..51f91e6079 100644 --- a/crypto/aes/aes.h +++ b/crypto/aes/aes.h @@ -128,6 +128,13 @@ void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key2, const unsigned char *ivec, const int enc); +int AES_wrap_key(AES_KEY *key, const unsigned char *iv, + unsigned char *out, + const unsigned char *in, unsigned int inlen); +int AES_unwrap_key(AES_KEY *key, const unsigned char *iv, + unsigned char *out, + const unsigned char *in, unsigned int inlen); + #ifdef __cplusplus } diff --git a/crypto/aes/aes_wrap.c b/crypto/aes/aes_wrap.c index ba62b55a9f..9feacd65d8 100644 --- a/crypto/aes/aes_wrap.c +++ b/crypto/aes/aes_wrap.c @@ -55,6 +55,10 @@ #include #include +static const unsigned char default_iv[] = { + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, +}; + int AES_wrap_key(AES_KEY *key, const unsigned char *iv, unsigned char *out, const unsigned char *in, unsigned int inlen) @@ -195,10 +199,6 @@ static const unsigned char key[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; -static const unsigned char default_iv[] = { - 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, -}; - static const unsigned char e1[] = { 0x1f, 0xa6, 0x8b, 0x0a, 0x81, 0x12, 0xb4, 0x47, 0xae, 0xf3, 0x4b, 0xd8, 0xfb, 0x5a, 0x7b, 0x82, diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h index b6c9792305..6061b8885e 100644 --- a/crypto/cms/cms.h +++ b/crypto/cms/cms.h @@ -172,6 +172,7 @@ int CMS_RecipientInfo_type(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); +int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey); int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert); int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri, EVP_PKEY **pk, X509 **recip, @@ -180,8 +181,7 @@ int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri, ASN1_OCTET_STRING **keyid, X509_NAME **issuer, ASN1_INTEGER **sno); -int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, - EVP_PKEY *pkey); +int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri); int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, unsigned int flags); @@ -315,11 +315,16 @@ void ERR_load_CMS_strings(void); #define CMS_F_CMS_GET0_REVOCATION_CHOICES 120 #define CMS_F_CMS_GET0_SIGNED 121 #define CMS_F_CMS_RECIPIENTINFO_DECRYPT 150 +#define CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT 161 +#define CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT 162 #define CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID 158 #define CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP 122 +#define CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT 160 #define CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT 155 #define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS 123 #define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID 124 +#define CMS_F_CMS_RECIPIENTINFO_SET0_KEY 163 +#define CMS_F_CMS_RECIPIENTINFO_SET0_PKEY 159 #define CMS_F_CMS_SET1_SIGNERIDENTIFIER 125 #define CMS_F_CMS_SET_DETACHED 126 #define CMS_F_CMS_SIGN 127 @@ -349,7 +354,9 @@ void ERR_load_CMS_strings(void); #define CMS_R_CTRL_FAILURE 108 #define CMS_R_ERROR_GETTING_PUBLIC_KEY 109 #define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE 110 +#define CMS_R_ERROR_SETTING_KEY 155 #define CMS_R_ERROR_SETTING_RECIPIENTINFO 150 +#define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH 156 #define CMS_R_INVALID_KEY_LENGTH 140 #define CMS_R_MD_BIO_INIT_ERROR 111 #define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH 112 @@ -387,8 +394,11 @@ void ERR_load_CMS_strings(void); #define CMS_R_UNSUPPORTED_CONTENT_TYPE 135 #define CMS_R_UNSUPPORTED_KEK_ALGORITHM 153 #define CMS_R_UNSUPPORTED_RECIPIENT_TYPE 151 +#define CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE 154 #define CMS_R_UNSUPPORTED_TYPE 136 +#define CMS_R_UNWRAP_ERROR 157 #define CMS_R_VERIFICATION_FAILURE 137 +#define CMS_R_WRAP_ERROR 158 #ifdef __cplusplus } diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c index 5ac3e125dc..008524932d 100644 --- a/crypto/cms/cms_env.c +++ b/crypto/cms/cms_env.c @@ -58,6 +58,7 @@ #include #include #include +#include #include "cms_lcl.h" #include "asn1_locl.h" @@ -266,6 +267,26 @@ int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri, return 1; } +/* For now hard code AES key wrap info */ + +static int aes_wrap_keylen(int nid) + { + switch (nid) + { + case NID_id_aes128_wrap: + return 16; + + case NID_id_aes192_wrap: + return 24; + + case NID_id_aes256_wrap: + return 32; + + default: + return 0; + } + } + CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid, unsigned char *key, size_t keylen, @@ -282,31 +303,18 @@ CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid, if (!env) goto err; - /* For now hard code checks on nids */ - switch (nid) - { - case NID_id_aes128_wrap: - exp_keylen = 16; - break; + exp_keylen = aes_wrap_keylen(nid); - case NID_id_aes192_wrap: - exp_keylen = 24; - break; - - case NID_id_aes256_wrap: - exp_keylen = 32; - break; - - default: + if (!exp_keylen) + { CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_UNSUPPORTED_KEK_ALGORITHM); goto err; } - if (exp_keylen && (keylen != exp_keylen)) + if (keylen != exp_keylen) { - CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, - CMS_R_INVALID_KEY_LENGTH); + CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH); goto err; } @@ -408,10 +416,43 @@ int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert) CMS_R_NOT_KEY_TRANSPORT); return -2; } - return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert); } +int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey) + { + if (ri->type != CMS_RECIPINFO_TRANS) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY, + CMS_R_NOT_KEY_TRANSPORT); + return 0; + } + ri->d.ktri->pkey = pkey; + return 1; + } + +int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri, + unsigned char *key, size_t keylen) + { + CMS_KEKRecipientInfo *kekri; + int wrap_nid; + if (ri->type != CMS_RECIPINFO_KEK) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY, CMS_R_NOT_KEK); + return 0; + } + wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm); + if (aes_wrap_keylen(wrap_nid) != keylen) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY, + CMS_R_INVALID_KEY_LENGTH); + return 0; + } + kekri->key = key; + kekri->keylen = keylen; + return 1; + } + /* Encrypt content key in key transport recipient info */ static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms, @@ -477,25 +518,23 @@ static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms, } -int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, - EVP_PKEY *pkey) +static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, + CMS_RecipientInfo *ri) { - CMS_KeyTransRecipientInfo *ktri; + CMS_KeyTransRecipientInfo *ktri = ri->d.ktri; EVP_PKEY_CTX *pctx = NULL; unsigned char *ek = NULL; size_t eklen; + int ret; - int ret = 0; - - if (ri->type != CMS_RECIPINFO_TRANS) + if (ktri->pkey == NULL) { - CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, - CMS_R_NOT_KEY_TRANSPORT); + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, + CMS_R_NO_PRIVATE_KEY); return 0; } - ktri = ri->d.ktri; - pctx = EVP_PKEY_CTX_new(pkey, NULL); + pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL); if (!pctx) return 0; @@ -505,7 +544,7 @@ int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT, EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0) { - CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, CMS_R_CTRL_ERROR); + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CTRL_ERROR); goto err; } @@ -518,7 +557,8 @@ int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, if (ek == NULL) { - CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, ERR_R_MALLOC_FAILURE); + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, + ERR_R_MALLOC_FAILURE); goto err; } @@ -526,7 +566,7 @@ int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, ktri->encryptedKey->data, ktri->encryptedKey->length) <= 0) { - CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, CMS_R_CMS_LIB); + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB); goto err; } @@ -544,6 +584,155 @@ int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, return ret; } + +/* Encrypt content key in KEK recipient info */ + +static int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms, + CMS_RecipientInfo *ri) + { + CMS_EncryptedContentInfo *ec; + CMS_KEKRecipientInfo *kekri; + AES_KEY actx; + unsigned char *wkey = NULL; + int wkeylen; + int r = 0; + + ec = cms->d.envelopedData->encryptedContentInfo; + + kekri = ri->d.kekri; + + if (!kekri->key) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_NO_KEY); + return 0; + } + + if (AES_set_encrypt_key(kekri->key, kekri->keylen << 3, &actx)) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, + CMS_R_ERROR_SETTING_KEY); + goto err; + } + + wkey = OPENSSL_malloc(ec->keylen + 8); + + if (!wkey) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, + ERR_R_MALLOC_FAILURE); + goto err; + } + + wkeylen = AES_wrap_key(&actx, NULL, wkey, ec->key, ec->keylen); + + if (wkeylen <= 0) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR); + goto err; + } + + ASN1_STRING_set0(kekri->encryptedKey, wkey, wkeylen); + + r = 1; + + err: + + if (!r && wkey) + OPENSSL_free(wkey); + OPENSSL_cleanse(&actx, sizeof(actx)); + + return r; + + } + +static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, + CMS_RecipientInfo *ri) + { + CMS_EncryptedContentInfo *ec; + CMS_KEKRecipientInfo *kekri; + AES_KEY actx; + unsigned char *ukey = NULL; + int ukeylen; + int r = 0; + + ec = cms->d.envelopedData->encryptedContentInfo; + + kekri = ri->d.kekri; + + if (!kekri->key) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_NO_KEY); + return 0; + } + + /* If encrypted key length is invalid don't bother */ + + if (kekri->encryptedKey->length < 16) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, + CMS_R_INVALID_ENCRYPTED_KEY_LENGTH); + goto err; + } + + if (AES_set_decrypt_key(kekri->key, kekri->keylen << 3, &actx)) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, + CMS_R_ERROR_SETTING_KEY); + goto err; + } + + ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8); + + if (!ukey) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, + ERR_R_MALLOC_FAILURE); + goto err; + } + + ukeylen = AES_unwrap_key(&actx, NULL, ukey, + kekri->encryptedKey->data, + kekri->encryptedKey->length); + + if (ukeylen <= 0) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, + CMS_R_UNWRAP_ERROR); + goto err; + } + + ec->key = ukey; + ec->keylen = ukeylen; + + r = 1; + + err: + + if (!r && ukey) + OPENSSL_free(ukey); + OPENSSL_cleanse(&actx, sizeof(actx)); + + return r; + + } + +int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri) + { + switch(ri->type) + { + case CMS_RECIPINFO_TRANS: + return cms_RecipientInfo_ktri_decrypt(cms, ri); + + case CMS_RECIPINFO_KEK: + return cms_RecipientInfo_kekri_decrypt(cms, ri); + + default: + CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, + CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE); + return 0; + } + } + BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) { CMS_EncryptedContentInfo *ec; @@ -562,20 +751,28 @@ BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) if (!ret || !ec->cipher) return ret; - rinfos = cms->d.envelopedData->recipientInfos; for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) { ri = sk_CMS_RecipientInfo_value(rinfos, i); - if (ri->type == CMS_RECIPINFO_TRANS) - r = cms_RecipientInfo_ktri_encrypt(cms, ri); - else + + switch (ri->type) { + case CMS_RECIPINFO_TRANS: + r = cms_RecipientInfo_ktri_encrypt(cms, ri); + break; + + case CMS_RECIPINFO_KEK: + r = cms_RecipientInfo_kekri_encrypt(cms, ri); + break; + + default: CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, CMS_R_UNSUPPORTED_RECIPIENT_TYPE); goto err; } + if (r <= 0) { CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c index acc756adf1..f7df77ba90 100644 --- a/crypto/cms/cms_err.c +++ b/crypto/cms/cms_err.c @@ -113,11 +113,16 @@ static ERR_STRING_DATA CMS_str_functs[]= {ERR_FUNC(CMS_F_CMS_GET0_REVOCATION_CHOICES), "CMS_GET0_REVOCATION_CHOICES"}, {ERR_FUNC(CMS_F_CMS_GET0_SIGNED), "CMS_GET0_SIGNED"}, {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_DECRYPT), "CMS_RecipientInfo_decrypt"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT), "CMS_RECIPIENTINFO_KEKRI_DECRYPT"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT), "CMS_RECIPIENTINFO_KEKRI_ENCRYPT"}, {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID), "CMS_RECIPIENTINFO_KEKRI_GET0_ID"}, {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP), "CMS_RecipientInfo_ktri_cert_cmp"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT), "CMS_RECIPIENTINFO_KTRI_DECRYPT"}, {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT), "CMS_RECIPIENTINFO_KTRI_ENCRYPT"}, {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS), "CMS_RecipientInfo_ktri_get0_algs"}, {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID), "CMS_RecipientInfo_ktri_get0_signer_id"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_KEY), "CMS_RECIPIENTINFO_SET0_KEY"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY), "CMS_RecipientInfo_set0_pkey"}, {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"}, @@ -150,7 +155,9 @@ static ERR_STRING_DATA CMS_str_reasons[]= {ERR_REASON(CMS_R_CTRL_FAILURE) ,"ctrl failure"}, {ERR_REASON(CMS_R_ERROR_GETTING_PUBLIC_KEY),"error getting public key"}, {ERR_REASON(CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE),"error reading messagedigest attribute"}, +{ERR_REASON(CMS_R_ERROR_SETTING_KEY) ,"error setting key"}, {ERR_REASON(CMS_R_ERROR_SETTING_RECIPIENTINFO),"error setting recipientinfo"}, +{ERR_REASON(CMS_R_INVALID_ENCRYPTED_KEY_LENGTH),"invalid encrypted key length"}, {ERR_REASON(CMS_R_INVALID_KEY_LENGTH) ,"invalid key length"}, {ERR_REASON(CMS_R_MD_BIO_INIT_ERROR) ,"md bio init error"}, {ERR_REASON(CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH),"messagedigest attribute wrong length"}, @@ -188,8 +195,11 @@ static ERR_STRING_DATA CMS_str_reasons[]= {ERR_REASON(CMS_R_UNSUPPORTED_CONTENT_TYPE),"unsupported content type"}, {ERR_REASON(CMS_R_UNSUPPORTED_KEK_ALGORITHM),"unsupported kek algorithm"}, {ERR_REASON(CMS_R_UNSUPPORTED_RECIPIENT_TYPE),"unsupported recipient type"}, +{ERR_REASON(CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE),"unsupported recpientinfo type"}, {ERR_REASON(CMS_R_UNSUPPORTED_TYPE) ,"unsupported type"}, +{ERR_REASON(CMS_R_UNWRAP_ERROR) ,"unwrap error"}, {ERR_REASON(CMS_R_VERIFICATION_FAILURE) ,"verification failure"}, +{ERR_REASON(CMS_R_WRAP_ERROR) ,"wrap error"}, {0,NULL} }; diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index 3a813de246..dcc0e6ba10 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -498,8 +498,6 @@ int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, BIO *dcont, BIO *out, unsigned int flags) { - STACK_OF(CMS_RecipientInfo) *ris; - CMS_RecipientInfo *ri; int i, r; BIO *cont; if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) @@ -509,28 +507,37 @@ int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, } if (!dcont && !check_content(cms)) return 0; - ris = CMS_get0_RecipientInfos(cms); - for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) + if (pk) { - ri = sk_CMS_RecipientInfo_value(ris, i); - if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS) - continue; - /* If we have a cert try matching RecipientInfo otherwise - * try them all. - */ - if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)) + STACK_OF(CMS_RecipientInfo) *ris; + CMS_RecipientInfo *ri; + ris = CMS_get0_RecipientInfos(cms); + for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { - if (CMS_RecipientInfo_decrypt(cms, ri, pk) > 0) - break; - else if (cert) - return 0; + ri = sk_CMS_RecipientInfo_value(ris, i); + if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS) + continue; + /* If we have a cert try matching RecipientInfo + * otherwise try them all. + */ + if (!cert || + (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)) + { + CMS_RecipientInfo_set0_pkey(ri, pk); + r = CMS_RecipientInfo_decrypt(cms, ri); + CMS_RecipientInfo_set0_pkey(ri, NULL); + if (r > 0) + break; + if (cert) + return 0; + } } - } - if (i == sk_CMS_RecipientInfo_num(ris)) - { - CMSerr(CMS_F_CMS_DECRYPT, CMS_R_NO_MATCHING_RECIPIENT); - return 0; + if (i == sk_CMS_RecipientInfo_num(ris)) + { + CMSerr(CMS_F_CMS_DECRYPT, CMS_R_NO_MATCHING_RECIPIENT); + return 0; + } } cont = CMS_dataInit(cms, dcont); if (!cont) -- 2.34.1