Add support for KEKRecipientInfo in cms application.
authorDr. Stephen Henson <steve@openssl.org>
Wed, 19 Mar 2008 13:53:52 +0000 (13:53 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 19 Mar 2008 13:53:52 +0000 (13:53 +0000)
apps/cms.c
crypto/cms/cms.h
crypto/cms/cms_env.c

index a280d8e19c94b2abdafc07329ff1249e130cbad2..6c5c4eb8196fb8d48dd64f09221e8582c3a892d1 100644 (file)
@@ -122,8 +122,8 @@ int MAIN(int argc, char **argv)
 #ifndef OPENSSL_NO_ENGINE
        char *engine=NULL;
 #endif
-       unsigned char *secret_key = NULL;
-       size_t secret_keylen = 0;
+       unsigned char *secret_key = NULL, *secret_keyid = NULL;
+       size_t secret_keylen = 0, secret_keyidlen = 0;
 
        X509_VERIFY_PARAM *vpm = NULL;
 
@@ -254,6 +254,20 @@ int MAIN(int argc, char **argv)
                                }
                        secret_keylen = (size_t)ltmp;
                        }
+               else if (!strcmp(*args,"-secretkeyid"))
+                       {
+                       long ltmp;
+                       if (!args[1])
+                               goto argerr;
+                       args++;
+                       secret_keyid = string_to_hex(*args, &ltmp);
+                       if (!secret_keyid)
+                               {
+                               BIO_printf(bio_err, "Invalid id %s\n", *args);
+                               goto argerr;
+                               }
+                       secret_keyidlen = (size_t)ltmp;
+                       }
                else if (!strcmp(*args,"-rand"))
                        {
                        if (!args[1])
@@ -459,7 +473,7 @@ int MAIN(int argc, char **argv)
                }
        else if (operation == SMIME_ENCRYPT)
                {
-               if (!*args)
+               if (!*args && !secret_key)
                        {
                        BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
                        badarg = 1;
@@ -592,17 +606,20 @@ int MAIN(int argc, char **argv)
                        goto end;
 #endif
                        }
-               encerts = sk_X509_new_null();
+
+               if (secret_key && !secret_keyid)
+                       {
+                       BIO_printf(bio_err, "No sectre key id\n");
+                       goto end;
+                       }
+
+               if (*args)
+                       encerts = sk_X509_new_null();
                while (*args)
                        {
                        if (!(cert = load_cert(bio_err,*args,FORMAT_PEM,
                                NULL, e, "recipient certificate file")))
-                               {
-#if 0                          /* An appropriate message is already printed */
-                               BIO_printf(bio_err, "Can't read recipient certificate file %s\n", *args);
-#endif
                                goto end;
-                               }
                        sk_X509_push(encerts, cert);
                        cert = NULL;
                        args++;
@@ -737,13 +754,33 @@ int MAIN(int argc, char **argv)
                }
        else if (operation == SMIME_ENCRYPT)
                {
+               flags |= CMS_PARTIAL;
                cms = CMS_encrypt(encerts, in, cipher, flags);
+               if (!cms)
+                       goto end;
+               if (secret_key)
+                       {
+                       if (!CMS_add0_recipient_key(cms, NID_undef, 
+                                               secret_key, secret_keylen,
+                                               secret_keyid, secret_keyidlen,
+                                               NULL, NULL, NULL))
+                               goto end;
+                       /* NULL these because call absorbs them */
+                       secret_key = NULL;
+                       secret_keyid = NULL;
+                       }
+               if (!(flags & CMS_STREAM))
+                       {
+                       if (!CMS_final(cms, in, flags))
+                               goto end;
+                       }
                }
        else if (operation == SMIME_ENCRYPTED_ENCRYPT)
                {
                cms = CMS_EncryptedData_encrypt(in, cipher,
                                                secret_key, secret_keylen,
                                                flags);
+
                }
        else if (operation & SMIME_SIGNERS)
                {
@@ -903,6 +940,8 @@ end:
                sk_free(skkeys);
        if (secret_key)
                OPENSSL_free(secret_key);
+       if (secret_keyid)
+               OPENSSL_free(secret_keyid);
        X509_STORE_free(store);
        X509_free(cert);
        X509_free(recip);
index 6061b8885e82d24d6ea7d97e42857f0bfce61dd4..5a74c4bb213597f5e2175fb0f8d42bba61f95c86 100644 (file)
@@ -181,6 +181,13 @@ int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri,
                                        ASN1_OCTET_STRING **keyid,
                                        X509_NAME **issuer, ASN1_INTEGER **sno);
 
+CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
+                                       unsigned char *key, size_t keylen,
+                                       unsigned char *id, size_t idlen,
+                                       ASN1_GENERALIZEDTIME *date,
+                                       ASN1_OBJECT *otherTypeId,
+                                       ASN1_TYPE *otherType);
+       
 int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
        
 int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
index d2e82906c6c5e35fdd28876b3d10aa47726a2985..1bea5582161497c5d486354e39e1dfb1969c7586 100644 (file)
@@ -139,9 +139,12 @@ CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher)
        return NULL;
        }
 
+/* Key Transport Recipient Info (KTRI) routines */
+
 /* Add a recipient certificate. For now only handle key transport.
  * If we ever handle key agreement will need updating.
  */
+
 CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
                                        X509 *recip, unsigned int flags)
        {
@@ -230,144 +233,6 @@ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
 
        }
 
-int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri,
-                                       X509_ALGOR **palg,
-                                       ASN1_OCTET_STRING **pid,
-                                       ASN1_GENERALIZEDTIME **pdate,
-                                       ASN1_OBJECT **potherid,
-                                       ASN1_TYPE **pothertype)
-       {
-       CMS_KEKIdentifier *rkid;
-       if (ri->type != CMS_RECIPINFO_KEK)
-               {
-               CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID, CMS_R_NOT_KEK);
-               return 0;
-               }
-       rkid =  ri->d.kekri->kekid;
-       if (palg)
-               *palg = ri->d.kekri->keyEncryptionAlgorithm;
-       if (pid)
-               *pid = rkid->keyIdentifier;
-       if (pdate)
-               *pdate = rkid->date;
-       if (potherid)
-               {
-               if (rkid->other)
-                       *potherid = rkid->other->keyAttrId;
-               else
-                       *potherid = NULL;
-               }
-       if (pothertype)
-               {
-               if (rkid->other)
-                       *pothertype = rkid->other->keyAttr;
-               else
-                       *pothertype = NULL;
-               }
-       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,
-                                       unsigned char *id, size_t idlen,
-                                       ASN1_GENERALIZEDTIME *date,
-                                       ASN1_OBJECT *otherTypeId,
-                                       ASN1_TYPE *otherType)
-       {
-       CMS_RecipientInfo *ri = NULL;
-       CMS_EnvelopedData *env;
-       CMS_KEKRecipientInfo *kekri;
-       size_t exp_keylen = 0;
-       env = cms_get0_enveloped(cms);
-       if (!env)
-               goto err;
-
-       exp_keylen = aes_wrap_keylen(nid);
-
-       if (!exp_keylen)
-               {
-               CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
-                               CMS_R_UNSUPPORTED_KEK_ALGORITHM);
-               goto err;
-               }
-
-       if (keylen != exp_keylen)
-               {
-               CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH);
-               goto err;
-               }
-
-       /* Initialize recipient info */
-       ri = M_ASN1_new_of(CMS_RecipientInfo);
-       if (!ri)
-               goto merr;
-
-       ri->d.kekri = M_ASN1_new_of(CMS_KEKRecipientInfo);
-       if (!ri->d.kekri)
-               goto merr;
-       ri->type = CMS_RECIPINFO_KEK;
-
-       kekri = ri->d.kekri;
-
-       if (otherTypeId)
-               {
-               kekri->kekid->other = M_ASN1_new_of(CMS_OtherKeyAttribute);
-               if (kekri->kekid->other == NULL)
-                       goto merr;
-               }
-
-       if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
-               goto merr;
-
-       /* After this point no calls can fail */
-
-       kekri->version = 4;
-
-       kekri->key = key;
-       kekri->keylen = keylen;
-
-       ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen);
-
-       kekri->kekid->date = date;
-
-       kekri->kekid->other->keyAttrId = otherTypeId;
-       kekri->kekid->other->keyAttr = otherType;
-
-       X509_ALGOR_set0(kekri->keyEncryptionAlgorithm,
-                               OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL);
-
-       return ri;
-
-       merr:
-       CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, ERR_R_MALLOC_FAILURE);
-       err:
-       if (ri)
-               M_ASN1_free_of(ri, CMS_RecipientInfo);
-       return NULL;
-
-       }
-
 int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
                                        EVP_PKEY **pk, X509 **recip,
                                        X509_ALGOR **palg)
@@ -431,29 +296,6 @@ int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_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;
-               }
-       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;
-       }
-                       
 /* Encrypt content key in key transport recipient info */
 
 static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
@@ -519,6 +361,8 @@ static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
 
        }
 
+/* Decrypt content key from KTRI */
+
 static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
                                                        CMS_RecipientInfo *ri)
        {
@@ -585,6 +429,201 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
        return ret;
        }
 
+/* Key Encrypted Key (KEK) RecipientInfo routines */
+
+/* For now hard code AES key wrap info */
+
+static size_t 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,
+                                       unsigned char *id, size_t idlen,
+                                       ASN1_GENERALIZEDTIME *date,
+                                       ASN1_OBJECT *otherTypeId,
+                                       ASN1_TYPE *otherType)
+       {
+       CMS_RecipientInfo *ri = NULL;
+       CMS_EnvelopedData *env;
+       CMS_KEKRecipientInfo *kekri;
+       env = cms_get0_enveloped(cms);
+       if (!env)
+               goto err;
+
+       if (nid == NID_undef)
+               {
+               switch (keylen)
+                       {
+                       case 16:
+                       nid = NID_id_aes128_wrap;
+                       break;
+
+                       case  24:
+                       nid = NID_id_aes192_wrap;
+                       break;
+
+                       case  32:
+                       nid = NID_id_aes256_wrap;
+                       break;
+
+                       default:
+                       CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
+                                               CMS_R_INVALID_KEY_LENGTH);
+                       goto err;
+                       }
+
+               }
+       else
+               {
+
+               size_t exp_keylen = aes_wrap_keylen(nid);
+
+               if (!exp_keylen)
+                       {
+                       CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
+                                       CMS_R_UNSUPPORTED_KEK_ALGORITHM);
+                       goto err;
+                       }
+
+               if (keylen != exp_keylen)
+                       {
+                       CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
+                                       CMS_R_INVALID_KEY_LENGTH);
+                       goto err;
+                       }
+
+               }
+
+       /* Initialize recipient info */
+       ri = M_ASN1_new_of(CMS_RecipientInfo);
+       if (!ri)
+               goto merr;
+
+       ri->d.kekri = M_ASN1_new_of(CMS_KEKRecipientInfo);
+       if (!ri->d.kekri)
+               goto merr;
+       ri->type = CMS_RECIPINFO_KEK;
+
+       kekri = ri->d.kekri;
+
+       if (otherTypeId)
+               {
+               kekri->kekid->other = M_ASN1_new_of(CMS_OtherKeyAttribute);
+               if (kekri->kekid->other == NULL)
+                       goto merr;
+               }
+
+       if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
+               goto merr;
+
+
+       /* After this point no calls can fail */
+
+       kekri->version = 4;
+
+       kekri->key = key;
+       kekri->keylen = keylen;
+
+       ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen);
+
+       kekri->kekid->date = date;
+
+       if (kekri->kekid->other)
+               {
+               kekri->kekid->other->keyAttrId = otherTypeId;
+               kekri->kekid->other->keyAttr = otherType;
+               }
+
+       X509_ALGOR_set0(kekri->keyEncryptionAlgorithm,
+                               OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL);
+
+       return ri;
+
+       merr:
+       CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, ERR_R_MALLOC_FAILURE);
+       err:
+       if (ri)
+               M_ASN1_free_of(ri, CMS_RecipientInfo);
+       return NULL;
+
+       }
+
+int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri,
+                                       X509_ALGOR **palg,
+                                       ASN1_OCTET_STRING **pid,
+                                       ASN1_GENERALIZEDTIME **pdate,
+                                       ASN1_OBJECT **potherid,
+                                       ASN1_TYPE **pothertype)
+       {
+       CMS_KEKIdentifier *rkid;
+       if (ri->type != CMS_RECIPINFO_KEK)
+               {
+               CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID, CMS_R_NOT_KEK);
+               return 0;
+               }
+       rkid =  ri->d.kekri->kekid;
+       if (palg)
+               *palg = ri->d.kekri->keyEncryptionAlgorithm;
+       if (pid)
+               *pid = rkid->keyIdentifier;
+       if (pdate)
+               *pdate = rkid->date;
+       if (potherid)
+               {
+               if (rkid->other)
+                       *potherid = rkid->other->keyAttrId;
+               else
+                       *potherid = NULL;
+               }
+       if (pothertype)
+               {
+               if (rkid->other)
+                       *pothertype = rkid->other->keyAttr;
+               else
+                       *pothertype = NULL;
+               }
+       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;
+               }
+       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;
+       }
+
 
 /* Encrypt content key in KEK recipient info */
 
@@ -646,6 +685,8 @@ static int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms,
 
        }
 
+/* Decrypt content key in KEK recipient info */
+
 static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
                                        CMS_RecipientInfo *ri)
        {
@@ -752,6 +793,8 @@ BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
        if (!ret || !ec->cipher)
                return ret;
 
+       /* Now encrypt content key according to each RecipientInfo type */
+
        rinfos = cms->d.envelopedData->recipientInfos;
 
        for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++)