Add support for KEKRecipientInfo in cms application.
This commit is contained in:
parent
c220e58f9e
commit
ab12438030
57
apps/cms.c
57
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);
|
||||
|
@ -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,
|
||||
|
@ -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++)
|
||||
|
Loading…
x
Reference in New Issue
Block a user