Commit 17c2764d authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

CMS support for key agreeement recipient info.

Add hooks to support key agreement recipient info type (KARI) using
algorithm specific code in the relevant public key ASN1 method.
parent ff7b6ce9
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -19,10 +19,10 @@ APPS=
LIB=$(TOP)/libcrypto.a
LIBSRC= cms_lib.c cms_asn1.c cms_att.c cms_io.c cms_smime.c cms_err.c \
	cms_sd.c cms_dd.c cms_cd.c cms_env.c cms_enc.c cms_ess.c \
	cms_pwri.c
	cms_pwri.c cms_kari.c
LIBOBJ= cms_lib.o cms_asn1.o cms_att.o cms_io.o cms_smime.o cms_err.o \
	cms_sd.o cms_dd.o cms_cd.o cms_env.o cms_enc.o cms_ess.o \
	cms_pwri.o
	cms_pwri.o cms_kari.o

SRC= $(LIBSRC)

+37 −1
Original line number Diff line number Diff line
@@ -73,9 +73,12 @@ typedef struct CMS_RevocationInfoChoice_st CMS_RevocationInfoChoice;
typedef struct CMS_RecipientInfo_st CMS_RecipientInfo;
typedef struct CMS_ReceiptRequest_st CMS_ReceiptRequest;
typedef struct CMS_Receipt_st CMS_Receipt;
typedef struct CMS_RecipientEncryptedKey_st CMS_RecipientEncryptedKey;
typedef struct CMS_OtherKeyAttribute_st CMS_OtherKeyAttribute;

DECLARE_STACK_OF(CMS_SignerInfo)
DECLARE_STACK_OF(GENERAL_NAMES)
DECLARE_STACK_OF(CMS_RecipientEncryptedKey)
DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo)
DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest)
DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
@@ -83,6 +86,7 @@ DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
#define CMS_SIGNERINFO_ISSUER_SERIAL	0
#define CMS_SIGNERINFO_KEYIDENTIFIER	1

#define CMS_RECIPINFO_NONE		-1
#define CMS_RECIPINFO_TRANS		0
#define CMS_RECIPINFO_AGREE		1
#define CMS_RECIPINFO_KEK		2
@@ -333,8 +337,32 @@ void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
					int *pallorfirst,
					STACK_OF(GENERAL_NAMES) **plist,
					STACK_OF(GENERAL_NAMES) **prto);

#endif
int CMS_RecipientInfo_kari_get0_alg(CMS_RecipientInfo *ri,
					X509_ALGOR **palg,
					ASN1_OCTET_STRING **pukm);
STACK_OF(CMS_RecipientEncryptedKey) *
	CMS_RecipientInfo_kari_get0_reks(CMS_RecipientInfo *ri);

int CMS_RecipientInfo_kari_get0_orig_id(CMS_RecipientInfo *ri,
					X509_ALGOR **pubalg,
					ASN1_BIT_STRING **pubkey,
					ASN1_OCTET_STRING **keyid,
					X509_NAME **issuer, ASN1_INTEGER **sno);

int CMS_RecipientInfo_kari_orig_id_cmp(CMS_RecipientInfo *ri, X509 *cert);
	
int CMS_RecipientEncryptedKey_get0_id(CMS_RecipientEncryptedKey *rek,
					ASN1_OCTET_STRING **keyid,
					ASN1_GENERALIZEDTIME **tm,
					CMS_OtherKeyAttribute **other,
					X509_NAME **issuer, ASN1_INTEGER **sno);
int CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek,
						X509 *cert);
int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk);
EVP_CIPHER_CTX *CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri);
int CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
					CMS_RecipientEncryptedKey *rek);

/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
@@ -391,6 +419,11 @@ void ERR_load_CMS_strings(void);
#define CMS_F_CMS_RECEIPT_VERIFY			 160
#define CMS_F_CMS_RECIPIENTINFO_DECRYPT			 134
#define CMS_F_CMS_RECIPIENTINFO_ENCRYPT			 169
#define CMS_F_CMS_RECIPIENTINFO_KARI_ENCRYPT		 178
#define CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ALG		 175
#define CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ORIG_ID	 173
#define CMS_F_CMS_RECIPIENTINFO_KARI_GET0_REKS		 172
#define CMS_F_CMS_RECIPIENTINFO_KARI_ORIG_ID_CMP	 174
#define CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT		 135
#define CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT		 136
#define CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID		 137
@@ -405,6 +438,8 @@ void ERR_load_CMS_strings(void);
#define CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD		 168
#define CMS_F_CMS_RECIPIENTINFO_SET0_PKEY		 145
#define CMS_F_CMS_SD_ASN1_CTRL				 170
#define CMS_F_CMS_SET1_IAS				 176
#define CMS_F_CMS_SET1_KEYID				 177
#define CMS_F_CMS_SET1_SIGNERIDENTIFIER			 146
#define CMS_F_CMS_SET_DETACHED				 147
#define CMS_F_CMS_SIGN					 148
@@ -456,6 +491,7 @@ void ERR_load_CMS_strings(void);
#define CMS_R_NOT_A_SIGNED_RECEIPT			 165
#define CMS_R_NOT_ENCRYPTED_DATA			 122
#define CMS_R_NOT_KEK					 123
#define CMS_R_NOT_KEY_AGREEMENT				 181
#define CMS_R_NOT_KEY_TRANSPORT				 124
#define CMS_R_NOT_PWRI					 177
#define CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE		 125
+36 −4
Original line number Diff line number Diff line
@@ -166,10 +166,22 @@ ASN1_CHOICE(CMS_KeyAgreeRecipientIdentifier) = {
  ASN1_IMP(CMS_KeyAgreeRecipientIdentifier, d.rKeyId, CMS_RecipientKeyIdentifier, 0)
} ASN1_CHOICE_END(CMS_KeyAgreeRecipientIdentifier)

ASN1_SEQUENCE(CMS_RecipientEncryptedKey) = {
static int cms_rek_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
							void *exarg)
	{
	CMS_RecipientEncryptedKey *rek = (CMS_RecipientEncryptedKey *)*pval;
	if(operation == ASN1_OP_FREE_POST)
		{
		if (rek->pkey)
			EVP_PKEY_free(rek->pkey);
		}
	return 1;
	}

ASN1_SEQUENCE_cb(CMS_RecipientEncryptedKey, cms_rek_cb) = {
	ASN1_SIMPLE(CMS_RecipientEncryptedKey, rid, CMS_KeyAgreeRecipientIdentifier),
	ASN1_SIMPLE(CMS_RecipientEncryptedKey, encryptedKey, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(CMS_RecipientEncryptedKey)
} ASN1_SEQUENCE_END_cb(CMS_RecipientEncryptedKey, CMS_RecipientEncryptedKey)

ASN1_SEQUENCE(CMS_OriginatorPublicKey) = {
  ASN1_SIMPLE(CMS_OriginatorPublicKey, algorithm, X509_ALGOR),
@@ -182,13 +194,33 @@ ASN1_CHOICE(CMS_OriginatorIdentifierOrKey) = {
  ASN1_IMP(CMS_OriginatorIdentifierOrKey, d.originatorKey, CMS_OriginatorPublicKey, 1)
} ASN1_CHOICE_END(CMS_OriginatorIdentifierOrKey)

ASN1_SEQUENCE(CMS_KeyAgreeRecipientInfo) = {
static int cms_kari_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
							void *exarg)
	{
	CMS_KeyAgreeRecipientInfo *kari = (CMS_KeyAgreeRecipientInfo *)*pval;
	if(operation == ASN1_OP_NEW_POST)
		{
		EVP_CIPHER_CTX_init(&kari->ctx);
		EVP_CIPHER_CTX_set_flags(&kari->ctx,
					EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
		kari->pctx = NULL;
		}
	else if(operation == ASN1_OP_FREE_POST)
		{
		if (kari->pctx)
			EVP_PKEY_CTX_free(kari->pctx);
		EVP_CIPHER_CTX_cleanup(&kari->ctx);
		}
	return 1;
	}

ASN1_SEQUENCE_cb(CMS_KeyAgreeRecipientInfo, cms_kari_cb) = {
	ASN1_SIMPLE(CMS_KeyAgreeRecipientInfo, version, LONG),
	ASN1_EXP(CMS_KeyAgreeRecipientInfo, originator, CMS_OriginatorIdentifierOrKey, 0),
	ASN1_EXP_OPT(CMS_KeyAgreeRecipientInfo, ukm, ASN1_OCTET_STRING, 1),
	ASN1_SIMPLE(CMS_KeyAgreeRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR),
	ASN1_SEQUENCE_OF(CMS_KeyAgreeRecipientInfo, recipientEncryptedKeys, CMS_RecipientEncryptedKey)
} ASN1_SEQUENCE_END(CMS_KeyAgreeRecipientInfo)
} ASN1_SEQUENCE_END_cb(CMS_KeyAgreeRecipientInfo, CMS_KeyAgreeRecipientInfo)

ASN1_SEQUENCE(CMS_KEKIdentifier) = {
	ASN1_SIMPLE(CMS_KEKIdentifier, keyIdentifier, ASN1_OCTET_STRING),
+102 −39
Original line number Diff line number Diff line
@@ -103,10 +103,23 @@ static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms)
	return cms_get0_enveloped(cms);
	}

static int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd)
int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd)
	{
	EVP_PKEY *pkey = ri->d.ktri->pkey;
	EVP_PKEY *pkey;
	int i;
	if (ri->type == CMS_RECIPINFO_TRANS)
		pkey = ri->d.ktri->pkey;
	else if (ri->type == CMS_RECIPINFO_AGREE)
		{
		EVP_PKEY_CTX *pctx = ri->d.kari->pctx;
		if (!pctx)
			return 0;
		pkey = EVP_PKEY_CTX_get0_pkey(pctx);
		if (!pkey)
			return 0;
		}
	else
		return 0;
	if (!pkey->ameth || !pkey->ameth->pkey_ctrl)
		return 1;
	i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_ENVELOPE, cmd, ri);
@@ -142,6 +155,8 @@ EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri)
	{
	if (ri->type == CMS_RECIPINFO_TRANS)
		return ri->d.ktri->pctx;
	else if (ri->type == CMS_RECIPINFO_AGREE)
		return ri->d.kari->pctx;
	return NULL;
	}

@@ -168,65 +183,43 @@ CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher)

/* 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.
 */
/* Initialise a ktri based on passed certificate and key */

CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
					X509 *recip, unsigned int flags)
static int cms_RecipientInfo_ktri_init(CMS_RecipientInfo *ri, X509 *recip,
				EVP_PKEY *pk, unsigned int flags)
	{
	CMS_RecipientInfo *ri = NULL;
	CMS_KeyTransRecipientInfo *ktri;
	CMS_EnvelopedData *env;
	EVP_PKEY *pk = NULL;
	int type;
	env = cms_get0_enveloped(cms);
	if (!env)
		goto err;

	/* Initialize recipient info */
	ri = M_ASN1_new_of(CMS_RecipientInfo);
	if (!ri)
		goto merr;

	/* Initialize and add key transport recipient info */
	int idtype;

	ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo);
	if (!ri->d.ktri)
		goto merr;
		return 0;
	ri->type = CMS_RECIPINFO_TRANS;

	ktri = ri->d.ktri;

	X509_check_purpose(recip, -1, -1);
	pk = X509_get_pubkey(recip);
	if (!pk)
		{
		CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
				CMS_R_ERROR_GETTING_PUBLIC_KEY);
		goto err;
		}
	CRYPTO_add(&recip->references, 1, CRYPTO_LOCK_X509);
	ktri->pkey = pk;
	ktri->recip = recip;

	if (flags & CMS_USE_KEYID)
		{
		ktri->version = 2;
		type = CMS_RECIPINFO_KEYIDENTIFIER;
		idtype = CMS_RECIPINFO_KEYIDENTIFIER;
		}
	else
		{
		ktri->version = 0;
		type = CMS_RECIPINFO_ISSUER_SERIAL;
		idtype = CMS_RECIPINFO_ISSUER_SERIAL;
		}

	/* Not a typo: RecipientIdentifier and SignerIdentifier are the
	 * same structure.
	 */

	if (!cms_set1_SignerIdentifier(ktri->rid, recip, type))
		goto err;
	if (!cms_set1_SignerIdentifier(ktri->rid, recip, idtype))
		return 0;

	CRYPTO_add(&recip->references, 1, CRYPTO_LOCK_X509);
	CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY);
	ktri->pkey = pk;
	ktri->recip = recip;

	if (flags & CMS_KEY_PARAM)
		{
@@ -234,14 +227,64 @@ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
		if (!ktri->pctx)
			return 0;
		if (EVP_PKEY_encrypt_init(ktri->pctx) <= 0)
			goto err;
			return 0;
		}
	else if (!cms_env_asn1_ctrl(ri, 0))
		return 0;
	return 1;
	}

/* Add a recipient certificate using appropriate type of RecipientInfo
 */

CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
					X509 *recip, unsigned int flags)
	{
	CMS_RecipientInfo *ri = NULL;
	CMS_EnvelopedData *env;
	EVP_PKEY *pk = NULL;
	env = cms_get0_enveloped(cms);
	if (!env)
		goto err;

	/* Initialize recipient info */
	ri = M_ASN1_new_of(CMS_RecipientInfo);
	if (!ri)
		goto merr;

	pk = X509_get_pubkey(recip);
	if (!pk)
		{
		CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
				CMS_R_ERROR_GETTING_PUBLIC_KEY);
		goto err;
		}

	switch (cms_pkey_get_ri_type(pk))
		{

		case CMS_RECIPINFO_TRANS:
		if (!cms_RecipientInfo_ktri_init(ri, recip, pk, flags))
			goto err;
		break;

		case CMS_RECIPINFO_AGREE:
		if (!cms_RecipientInfo_kari_init(ri, recip, pk, flags))
			goto err;
		break;

		default:
		CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
					CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
		goto err;

		}

	if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
		goto merr;

	EVP_PKEY_free(pk);

	return ri;

	merr:
@@ -249,6 +292,8 @@ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
	err:
	if (ri)
		M_ASN1_free_of(ri, CMS_RecipientInfo);
	if (pk)
		EVP_PKEY_free(pk);
	return NULL;

	}
@@ -850,6 +895,9 @@ int CMS_RecipientInfo_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
		case CMS_RECIPINFO_TRANS:
		return cms_RecipientInfo_ktri_encrypt(cms, ri);

		case CMS_RECIPINFO_AGREE:
		return cms_RecipientInfo_kari_encrypt(cms, ri);

		case CMS_RECIPINFO_KEK:
		return cms_RecipientInfo_kekri_encrypt(cms, ri);
		break;
@@ -988,3 +1036,18 @@ BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
	return NULL;

	}
/* Get RecipientInfo type (if any) supported by a key (public or private).
 * To retain compatibility with previous behaviour if the ctrl value isn't
 * supported we assume key transport.
 */
int cms_pkey_get_ri_type(EVP_PKEY *pk)
	{
	if (pk->ameth && pk->ameth->pkey_ctrl)
		{
		int i, r;
		i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_RI_TYPE, 0, &r);
		if (i > 0)
			return r;
		}
	return CMS_RECIPINFO_TRANS;
	}
+9 −1
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ static ERR_STRING_DATA CMS_str_functs[]=
{ERR_FUNC(CMS_F_CMS_ENVELOPEDDATA_CREATE),	"CMS_EnvelopedData_create"},
{ERR_FUNC(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO),	"cms_EnvelopedData_init_bio"},
{ERR_FUNC(CMS_F_CMS_ENVELOPED_DATA_INIT),	"CMS_ENVELOPED_DATA_INIT"},
{ERR_FUNC(CMS_F_CMS_ENV_ASN1_CTRL),	"CMS_ENV_ASN1_CTRL"},
{ERR_FUNC(CMS_F_CMS_ENV_ASN1_CTRL),	"cms_env_asn1_ctrl"},
{ERR_FUNC(CMS_F_CMS_FINAL),	"CMS_final"},
{ERR_FUNC(CMS_F_CMS_GET0_CERTIFICATE_CHOICES),	"CMS_GET0_CERTIFICATE_CHOICES"},
{ERR_FUNC(CMS_F_CMS_GET0_CONTENT),	"CMS_get0_content"},
@@ -116,6 +116,11 @@ static ERR_STRING_DATA CMS_str_functs[]=
{ERR_FUNC(CMS_F_CMS_RECEIPT_VERIFY),	"cms_Receipt_verify"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_DECRYPT),	"CMS_RecipientInfo_decrypt"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_ENCRYPT),	"CMS_RecipientInfo_encrypt"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KARI_ENCRYPT),	"cms_RecipientInfo_kari_encrypt"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ALG),	"CMS_RecipientInfo_kari_get0_alg"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ORIG_ID),	"CMS_RecipientInfo_kari_get0_orig_id"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_REKS),	"CMS_RecipientInfo_kari_get0_reks"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KARI_ORIG_ID_CMP),	"CMS_RecipientInfo_kari_orig_id_cmp"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT),	"CMS_RECIPIENTINFO_KEKRI_DECRYPT"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT),	"CMS_RECIPIENTINFO_KEKRI_ENCRYPT"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID),	"CMS_RecipientInfo_kekri_get0_id"},
@@ -130,6 +135,8 @@ static ERR_STRING_DATA CMS_str_functs[]=
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD),	"CMS_RecipientInfo_set0_password"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY),	"CMS_RecipientInfo_set0_pkey"},
{ERR_FUNC(CMS_F_CMS_SD_ASN1_CTRL),	"CMS_SD_ASN1_CTRL"},
{ERR_FUNC(CMS_F_CMS_SET1_IAS),	"cms_set1_ias"},
{ERR_FUNC(CMS_F_CMS_SET1_KEYID),	"cms_set1_keyid"},
{ERR_FUNC(CMS_F_CMS_SET1_SIGNERIDENTIFIER),	"cms_set1_SignerIdentifier"},
{ERR_FUNC(CMS_F_CMS_SET_DETACHED),	"CMS_set_detached"},
{ERR_FUNC(CMS_F_CMS_SIGN),	"CMS_sign"},
@@ -184,6 +191,7 @@ static ERR_STRING_DATA CMS_str_reasons[]=
{ERR_REASON(CMS_R_NOT_A_SIGNED_RECEIPT)  ,"not a signed receipt"},
{ERR_REASON(CMS_R_NOT_ENCRYPTED_DATA)    ,"not encrypted data"},
{ERR_REASON(CMS_R_NOT_KEK)               ,"not kek"},
{ERR_REASON(CMS_R_NOT_KEY_AGREEMENT)     ,"not key agreement"},
{ERR_REASON(CMS_R_NOT_KEY_TRANSPORT)     ,"not key transport"},
{ERR_REASON(CMS_R_NOT_PWRI)              ,"not pwri"},
{ERR_REASON(CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),"not supported for this key type"},
Loading