Add support for KEK decrypt in cms utility.
authorDr. Stephen Henson <steve@openssl.org>
Wed, 19 Mar 2008 18:39:51 +0000 (18:39 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 19 Mar 2008 18:39:51 +0000 (18:39 +0000)
apps/cms.c
crypto/cms/cms.h
crypto/cms/cms_env.c
crypto/cms/cms_err.c
crypto/cms/cms_smime.c
test/cms-test.pl

index 6c5c4eb..2cbd43b 100644 (file)
@@ -465,7 +465,7 @@ int MAIN(int argc, char **argv)
                }
        else if (operation == SMIME_DECRYPT)
                {
-               if (!recipfile && !keyfile)
+               if (!recipfile && !keyfile && !secret_key)
                        {
                        BIO_printf(bio_err, "No recipient certificate or key specified\n");
                        badarg = 1;
@@ -838,7 +838,30 @@ int MAIN(int argc, char **argv)
        ret = 4;
        if (operation == SMIME_DECRYPT)
                {
-               if (!CMS_decrypt(cms, key, recip, indata, out, flags))
+
+               if (secret_key)
+                       {
+                       if (!CMS_decrypt_set1_key(cms,
+                                               secret_key, secret_keylen,
+                                               secret_keyid, secret_keyidlen))
+                               {
+                               BIO_puts(bio_err,
+                                       "Error decrypting CMS using secret key\n");
+                               goto end;
+                               }
+                       }
+
+               if (key)
+                       {
+                       if (!CMS_decrypt_set1_pkey(cms, key, recip))
+                               {
+                               BIO_puts(bio_err,
+                                       "Error decrypting CMS using private key\n");
+                               goto end;
+                               }
+                       }
+
+               if (!CMS_decrypt(cms, NULL, NULL, indata, out, flags))
                        {
                        BIO_printf(bio_err, "Error decrypting CMS structure\n");
                        goto end;
index 5a74c4b..49fdcf5 100644 (file)
@@ -166,6 +166,11 @@ CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in,
 int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pkey, X509 *cert,
                                BIO *data, BIO *dcont,
                                unsigned int flags);
+       
+int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert);
+int CMS_decrypt_set1_key(CMS_ContentInfo *cms, 
+                               unsigned char *key, size_t keylen,
+                               unsigned char *id, size_t idlen);
 
 STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms);
 int CMS_RecipientInfo_type(CMS_RecipientInfo *ri);
@@ -187,7 +192,13 @@ CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
                                        ASN1_GENERALIZEDTIME *date,
                                        ASN1_OBJECT *otherTypeId,
                                        ASN1_TYPE *otherType);
-       
+
+int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri, 
+                               unsigned char *key, size_t keylen);
+
+int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri, 
+                                       const unsigned char *id, size_t idlen);
+
 int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
        
 int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
@@ -297,6 +308,8 @@ void ERR_load_CMS_strings(void);
 #define CMS_F_CMS_DECRYPT                               152
 #define CMS_F_CMS_DECRYPTEDCONTENT_DECRYPT_BIO          145
 #define CMS_F_CMS_DECRYPTEDCONTENT_ENCRYPT_BIO          143
+#define CMS_F_CMS_DECRYPT_SET1_KEY                      167
+#define CMS_F_CMS_DECRYPT_SET1_PKEY                     168
 #define CMS_F_CMS_DIGESTALGORITHM_FIND_CTX              110
 #define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO              111
 #define CMS_F_CMS_DIGESTEDDATA_DO_FINAL                         112
@@ -322,9 +335,12 @@ 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_KEKI_KEY_CMP            164
 #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_KEKRI_ID_CMP            166
+#define CMS_F_CMS_RECIPIENTINFO_KEKRI_KEY_CMP           165
 #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
@@ -359,6 +375,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_R_CONTENT_VERIFY_ERROR                      106
 #define CMS_R_CTRL_ERROR                                107
 #define CMS_R_CTRL_FAILURE                              108
+#define CMS_R_DECRYPT_ERROR                             159
 #define CMS_R_ERROR_GETTING_PUBLIC_KEY                  109
 #define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE     110
 #define CMS_R_ERROR_SETTING_KEY                                 155
index 1bea558..d948754 100644 (file)
@@ -431,6 +431,24 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
 
 /* Key Encrypted Key (KEK) RecipientInfo routines */
 
+int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri, 
+                                       const unsigned char *id, size_t idlen)
+       {
+       ASN1_OCTET_STRING tmp_os;
+       CMS_KEKRecipientInfo *kekri;
+       if (ri->type != CMS_RECIPINFO_KEK)
+               {
+               CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP, CMS_R_NOT_KEK);
+               return -2;
+               }
+       kekri = ri->d.kekri;
+       tmp_os.type = V_ASN1_OCTET_STRING;
+       tmp_os.flags = 0;
+       tmp_os.data = (unsigned char *)id;
+       tmp_os.length = (int)idlen;
+       return ASN1_OCTET_STRING_cmp(&tmp_os, kekri->kekid->keyIdentifier);
+       }
+
 /* For now hard code AES key wrap info */
 
 static size_t aes_wrap_keylen(int nid)
@@ -605,20 +623,13 @@ 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;
                }
+
        kekri = ri->d.kekri;
-       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;
@@ -695,7 +706,7 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
        AES_KEY actx;
        unsigned char *ukey = NULL;
        int ukeylen;
-       int r = 0;
+       int r = 0, wrap_nid;
 
        ec = cms->d.envelopedData->encryptedContentInfo;
 
@@ -707,6 +718,14 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
                return 0;
                }
 
+       wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm);
+       if (aes_wrap_keylen(wrap_nid) != kekri->keylen)
+               {
+               CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
+                       CMS_R_INVALID_KEY_LENGTH);
+               return 0;
+               }
+
        /* If encrypted key length is invalid don't bother */
 
        if (kekri->encryptedKey->length < 16)
index f7df77b..6fbab4d 100644 (file)
@@ -71,7 +71,7 @@
 static ERR_STRING_DATA CMS_str_functs[]=
        {
 {ERR_FUNC(CMS_F_CHECK_CONTENT),        "CHECK_CONTENT"},
-{ERR_FUNC(CMS_F_CMS_ADD0_RECIPIENT_KEY),       "CMS_ADD0_RECIPIENT_KEY"},
+{ERR_FUNC(CMS_F_CMS_ADD0_RECIPIENT_KEY),       "CMS_add0_recipient_key"},
 {ERR_FUNC(CMS_F_CMS_ADD1_RECIPIENT_CERT),      "CMS_add1_recipient_cert"},
 {ERR_FUNC(CMS_F_CMS_ADD1_SIGNER),      "CMS_add1_signer"},
 {ERR_FUNC(CMS_F_CMS_ADD1_SIGNINGTIME), "CMS_ADD1_SIGNINGTIME"},
@@ -88,6 +88,8 @@ static ERR_STRING_DATA CMS_str_functs[]=
 {ERR_FUNC(CMS_F_CMS_DECRYPT),  "CMS_decrypt"},
 {ERR_FUNC(CMS_F_CMS_DECRYPTEDCONTENT_DECRYPT_BIO),     "CMS_DECRYPTEDCONTENT_DECRYPT_BIO"},
 {ERR_FUNC(CMS_F_CMS_DECRYPTEDCONTENT_ENCRYPT_BIO),     "CMS_DECRYPTEDCONTENT_ENCRYPT_BIO"},
+{ERR_FUNC(CMS_F_CMS_DECRYPT_SET1_KEY), "CMS_DECRYPT_SET1_KEY"},
+{ERR_FUNC(CMS_F_CMS_DECRYPT_SET1_PKEY),        "CMS_DECRYPT_SET1_PKEY"},
 {ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX), "CMS_DIGESTALGORITHM_FIND_CTX"},
 {ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO), "CMS_DIGESTALGORITHM_INIT_BIO"},
 {ERR_FUNC(CMS_F_CMS_DIGESTEDDATA_DO_FINAL),    "CMS_DIGESTEDDATA_DO_FINAL"},
@@ -113,15 +115,18 @@ 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_KEKI_KEY_CMP),       "CMS_RECIPIENTINFO_KEKI_KEY_CMP"},
 {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_KEKRI_ID_CMP),       "CMS_RecipientInfo_kekri_id_cmp"},
+{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_KEY_CMP),      "CMS_RECIPIENTINFO_KEKRI_KEY_CMP"},
 {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_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"},
@@ -153,6 +158,7 @@ static ERR_STRING_DATA CMS_str_reasons[]=
 {ERR_REASON(CMS_R_CONTENT_VERIFY_ERROR)  ,"content verify error"},
 {ERR_REASON(CMS_R_CTRL_ERROR)            ,"ctrl error"},
 {ERR_REASON(CMS_R_CTRL_FAILURE)          ,"ctrl failure"},
+{ERR_REASON(CMS_R_DECRYPT_ERROR)         ,"decrypt error"},
 {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"},
index c9be5a0..6388df8 100644 (file)
@@ -493,12 +493,87 @@ CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
                CMS_ContentInfo_free(cms);
        return NULL;
        }
+
+int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
+       {
+       STACK_OF(CMS_RecipientInfo) *ris;
+       CMS_RecipientInfo *ri;
+       int i, r;
+       ris = CMS_get0_RecipientInfos(cms);
+       for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
+               {
+               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)
+                               return 1;
+                       if (cert)
+                               {
+                               CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY,
+                                               CMS_R_DECRYPT_ERROR);
+                               return 0;
+                               }
+                       ERR_clear_error();
+                       }
+               }
+
+       CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT);
+       return 0;
+
+       }
+
+int CMS_decrypt_set1_key(CMS_ContentInfo *cms, 
+                               unsigned char *key, size_t keylen,
+                               unsigned char *id, size_t idlen)
+       {
+       STACK_OF(CMS_RecipientInfo) *ris;
+       CMS_RecipientInfo *ri;
+       int i, r;
+       ris = CMS_get0_RecipientInfos(cms);
+       for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
+               {
+               ri = sk_CMS_RecipientInfo_value(ris, i);
+               if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK)
+                               continue;
+
+               /* If we have an id try matching RecipientInfo
+                * otherwise try them all.
+                */
+               if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0))
+                       {
+                       CMS_RecipientInfo_set0_key(ri, key, keylen);
+                       r = CMS_RecipientInfo_decrypt(cms, ri);
+                       CMS_RecipientInfo_set0_key(ri, NULL, 0);
+                       if (r > 0)
+                               return 1;
+                       if (id)
+                               {
+                               CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY,
+                                               CMS_R_DECRYPT_ERROR);
+                               return 0;
+                               }
+                       ERR_clear_error();
+                       }
+               }
+
+       CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT);
+       return 0;
+
+       }
        
 int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
                                BIO *dcont, BIO *out,
                                unsigned int flags)
        {
-       int i, r;
+       int r;
        BIO *cont;
        if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped)
                {
@@ -507,39 +582,9 @@ int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
                }
        if (!dcont && !check_content(cms))
                return 0;
-       if (pk)
-               {
-               STACK_OF(CMS_RecipientInfo) *ris;
-               CMS_RecipientInfo *ri;
-               ris = CMS_get0_RecipientInfos(cms);
-               for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
-                       {
-                       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;
-                               ERR_clear_error();
-                               }
-                       }
+       if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert))
+               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)
                return 0;
index 3dfbe8d..db272e4 100644 (file)
@@ -235,6 +235,27 @@ my @smime_cms_tests = (
         "-decrypt -recip $smdir/smrsa1.pem -in test.cms -out smtst.txt"
     ],
 
+    [
+        "enveloped content test streaming PEM format, KEK",
+        "-encrypt -in smcont.txt -outform PEM -aes128"
+          . " -stream -out test.cms "
+          . " -secretkey 000102030405060708090A0B0C0D0E0F "
+          . " -secretkeyid C0FEE0",
+        "-decrypt -in test.cms -out smtst.txt -inform PEM"
+          . " -secretkey 000102030405060708090A0B0C0D0E0F "
+          . " -secretkeyid C0FEE0"
+    ],
+
+    [
+        "enveloped content test streaming PEM format, KEK, key only",
+        "-encrypt -in smcont.txt -outform PEM -aes128"
+          . " -stream -out test.cms "
+          . " -secretkey 000102030405060708090A0B0C0D0E0F "
+          . " -secretkeyid C0FEE0",
+        "-decrypt -in test.cms -out smtst.txt -inform PEM"
+          . " -secretkey 000102030405060708090A0B0C0D0E0F "
+    ],
+
     [
         "data content test streaming PEM format",
         "-data_create -in smcont.txt -outform PEM -nodetach"