From ab124380301794abe87583b7a88156eaff1c2eae Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 19 Mar 2008 13:53:52 +0000 Subject: [PATCH] Add support for KEKRecipientInfo in cms application. --- apps/cms.c | 57 +++++-- crypto/cms/cms.h | 7 + crypto/cms/cms_env.c | 365 ++++++++++++++++++++++++------------------- 3 files changed, 259 insertions(+), 170 deletions(-) diff --git a/apps/cms.c b/apps/cms.c index a280d8e19c..6c5c4eb819 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -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, <mp); + 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); diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h index 6061b8885e..5a74c4bb21 100644 --- a/crypto/cms/cms.h +++ b/crypto/cms/cms.h @@ -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, diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c index d2e82906c6..1bea558216 100644 --- a/crypto/cms/cms_env.c +++ b/crypto/cms/cms_env.c @@ -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++) -- 2.25.1