summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2008-03-19 13:53:52 +0000
committerDr. Stephen Henson <steve@openssl.org>2008-03-19 13:53:52 +0000
commitab124380301794abe87583b7a88156eaff1c2eae (patch)
treefe116e37dc17d2a0b62013ee1a3a8caa6d93998c
parentc220e58f9e6e16890ebf8bb321ff45d94f4800a8 (diff)
Add support for KEKRecipientInfo in cms application.
-rw-r--r--apps/cms.c57
-rw-r--r--crypto/cms/cms.h7
-rw-r--r--crypto/cms/cms_env.c365
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, &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);
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++)