Add support for KEKRecipientInfo in cms application.

This commit is contained in:
Dr. Stephen Henson 2008-03-19 13:53:52 +00:00
parent c220e58f9e
commit ab12438030
3 changed files with 259 additions and 170 deletions

View 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);

View 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,

View 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++)