More support for KEK RecipientInfo.
authorDr. Stephen Henson <steve@openssl.org>
Tue, 18 Mar 2008 01:00:38 +0000 (01:00 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Tue, 18 Mar 2008 01:00:38 +0000 (01:00 +0000)
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
crypto/aes/aes.h
crypto/aes/aes_wrap.c
crypto/cms/cms.h
crypto/cms/cms_env.c
crypto/cms/cms_err.c
crypto/cms/cms_smime.c

index 632fdb5..80dcc32 100644 (file)
@@ -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)
index 949a754..51f91e6 100644 (file)
@@ -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
 }
index ba62b55..9feacd6 100644 (file)
 #include <openssl/aes.h>
 #include <openssl/bio.h>
 
+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,
index b6c9792..6061b88 100644 (file)
@@ -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
 }
index 5ac3e12..0085249 100644 (file)
@@ -58,6 +58,7 @@
 #include <openssl/err.h>
 #include <openssl/cms.h>
 #include <openssl/rand.h>
+#include <openssl/aes.h>
 #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,
index acc756a..f7df77b 100644 (file)
@@ -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}
        };
 
index 3a813de..dcc0e6b 100644 (file)
@@ -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)