summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2013-07-17 14:36:39 +0100
committerDr. Stephen Henson <steve@openssl.org>2013-10-01 14:01:18 +0100
commit8c798690ce6092ba33eb4f7505c3c036cce20e8c (patch)
treec9a06d6af1da2e5a896d0f08478b36591ce26b15
parentea6bf266577e3a0bbc85c241686508f88b10881f (diff)
downloadopenssl-new-8c798690ce6092ba33eb4f7505c3c036cce20e8c.tar.gz
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. (cherry picked from commit 17c2764d2e6fc5a010ad3c12662068689ed2ad17)
-rw-r--r--crypto/cms/Makefile4
-rw-r--r--crypto/cms/cms.h38
-rw-r--r--crypto/cms/cms_asn1.c40
-rw-r--r--crypto/cms/cms_env.c141
-rw-r--r--crypto/cms/cms_err.c10
-rw-r--r--crypto/cms/cms_kari.c480
-rw-r--r--crypto/cms/cms_lcl.h26
-rw-r--r--crypto/cms/cms_lib.c61
-rw-r--r--crypto/cms/cms_sd.c46
-rw-r--r--crypto/cms/cms_smime.c48
-rw-r--r--crypto/evp/evp.h1
-rw-r--r--crypto/stack/safestack.h22
12 files changed, 824 insertions, 93 deletions
diff --git a/crypto/cms/Makefile b/crypto/cms/Makefile
index 9820adb212..f17ae347a9 100644
--- a/crypto/cms/Makefile
+++ b/crypto/cms/Makefile
@@ -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)
diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h
index 1624b79ebc..f644cbfbc4 100644
--- a/crypto/cms/cms.h
+++ b/crypto/cms/cms.h
@@ -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
diff --git a/crypto/cms/cms_asn1.c b/crypto/cms/cms_asn1.c
index 6a692cdb1d..7d79db221a 100644
--- a/crypto/cms/cms_asn1.c
+++ b/crypto/cms/cms_asn1.c
@@ -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),
diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c
index cef825be2b..8c6d91f3c8 100644
--- a/crypto/cms/cms_env.c
+++ b/crypto/cms/cms_env.c
@@ -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;
+ }
diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c
index 35aca59335..5d9f685113 100644
--- a/crypto/cms/cms_err.c
+++ b/crypto/cms/cms_err.c
@@ -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"},
diff --git a/crypto/cms/cms_kari.c b/crypto/cms/cms_kari.c
new file mode 100644
index 0000000000..2451f0f23f
--- /dev/null
+++ b/crypto/cms/cms_kari.c
@@ -0,0 +1,480 @@
+/* crypto/cms/cms_kari.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2013 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include "cryptlib.h"
+#include <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#include <openssl/rand.h>
+#include <openssl/aes.h>
+#include "cms_lcl.h"
+#include "asn1_locl.h"
+
+DECLARE_ASN1_ITEM(CMS_KeyAgreeRecipientInfo)
+DECLARE_ASN1_ITEM(CMS_RecipientEncryptedKey)
+DECLARE_ASN1_ITEM(CMS_OriginatorPublicKey)
+
+/* Key Agreement Recipient Info (KARI) routines */
+
+int CMS_RecipientInfo_kari_get0_alg(CMS_RecipientInfo *ri,
+ X509_ALGOR **palg,
+ ASN1_OCTET_STRING **pukm)
+ {
+ if (ri->type != CMS_RECIPINFO_AGREE)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ALG,
+ CMS_R_NOT_KEY_AGREEMENT);
+ return 0;
+ }
+ if (palg)
+ *palg = ri->d.kari->keyEncryptionAlgorithm;
+ if (pukm)
+ *pukm = ri->d.kari->ukm;
+ return 1;
+ }
+
+/* Retrieve recipient encrypted keys from a kari */
+
+STACK_OF(CMS_RecipientEncryptedKey) *CMS_RecipientInfo_kari_get0_reks(CMS_RecipientInfo *ri)
+ {
+ if (ri->type != CMS_RECIPINFO_AGREE)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_REKS,
+ CMS_R_NOT_KEY_AGREEMENT);
+ return NULL;
+ }
+ return ri->d.kari->recipientEncryptedKeys;
+ }
+
+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)
+ {
+ CMS_OriginatorIdentifierOrKey *oik;
+ if (ri->type != CMS_RECIPINFO_AGREE)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ORIG_ID,
+ CMS_R_NOT_KEY_AGREEMENT);
+ return 0;
+ }
+ oik = ri->d.kari->originator;
+ if (issuer)
+ *issuer = NULL;
+ if (sno)
+ *sno = NULL;
+ if (keyid)
+ *keyid = NULL;
+ if (pubalg)
+ *pubalg = NULL;
+ if (pubkey)
+ *pubkey = NULL;
+ if (oik->type == CMS_OIK_ISSUER_SERIAL)
+ {
+ if (issuer)
+ *issuer = oik->d.issuerAndSerialNumber->issuer;
+ if (sno)
+ *sno = oik->d.issuerAndSerialNumber->serialNumber;
+ }
+ else if (oik->type == CMS_OIK_KEYIDENTIFIER)
+ {
+ if (keyid)
+ *keyid = oik->d.subjectKeyIdentifier;
+ }
+ else if (oik->type == CMS_OIK_PUBKEY)
+ {
+ if (pubalg)
+ *pubalg = oik->d.originatorKey->algorithm;
+ if (pubkey)
+ *pubkey = oik->d.originatorKey->publicKey;
+ }
+ else
+ return 0;
+ return 1;
+ }
+
+int CMS_RecipientInfo_kari_orig_id_cmp(CMS_RecipientInfo *ri, X509 *cert)
+ {
+ CMS_OriginatorIdentifierOrKey *oik;
+ if (ri->type != CMS_RECIPINFO_AGREE)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_ORIG_ID_CMP,
+ CMS_R_NOT_KEY_AGREEMENT);
+ return -2;
+ }
+ oik = ri->d.kari->originator;
+ if (oik->type == CMS_OIK_ISSUER_SERIAL)
+ return cms_ias_cert_cmp(oik->d.issuerAndSerialNumber, cert);
+ else if (oik->type == CMS_OIK_KEYIDENTIFIER)
+ return cms_keyid_cert_cmp(oik->d.subjectKeyIdentifier, cert);
+ return -1;
+ }
+
+int CMS_RecipientEncryptedKey_get0_id(CMS_RecipientEncryptedKey *rek,
+ ASN1_OCTET_STRING **keyid,
+ ASN1_GENERALIZEDTIME **tm,
+ CMS_OtherKeyAttribute **other,
+ X509_NAME **issuer, ASN1_INTEGER **sno)
+ {
+ CMS_KeyAgreeRecipientIdentifier *rid = rek->rid;
+ if (rid->type == CMS_REK_ISSUER_SERIAL)
+ {
+ if (issuer)
+ *issuer = rid->d.issuerAndSerialNumber->issuer;
+ if (sno)
+ *sno = rid->d.issuerAndSerialNumber->serialNumber;
+ if (keyid)
+ *keyid = NULL;
+ if (tm)
+ *tm = NULL;
+ if (other)
+ *other = NULL;
+ }
+ else if (rid->type == CMS_REK_KEYIDENTIFIER)
+ {
+ if (keyid)
+ *keyid = rid->d.rKeyId->subjectKeyIdentifier;
+ if (tm)
+ *tm = rid->d.rKeyId->date;
+ if (other)
+ *other = rid->d.rKeyId->other;
+ if (issuer)
+ *issuer = NULL;
+ if (sno)
+ *sno = NULL;
+ }
+ else
+ return 0;
+ return 1;
+ }
+
+int CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek,
+ X509 *cert)
+ {
+ CMS_KeyAgreeRecipientIdentifier *rid = rek->rid;
+ if (rid->type == CMS_REK_ISSUER_SERIAL)
+ return cms_ias_cert_cmp(rid->d.issuerAndSerialNumber, cert);
+ else if (rid->type == CMS_REK_KEYIDENTIFIER)
+ return cms_keyid_cert_cmp(rid->d.rKeyId->subjectKeyIdentifier, cert);
+ else
+ return -1;
+ }
+
+int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk)
+ {
+ EVP_PKEY_CTX *pctx;
+ CMS_KeyAgreeRecipientInfo *kari = ri->d.kari;
+ if (kari->pctx)
+ {
+ EVP_PKEY_CTX_free(kari->pctx);
+ kari->pctx = NULL;
+ }
+ if (!pk)
+ return 1;
+ pctx = EVP_PKEY_CTX_new(pk, NULL);
+ if (!pctx || !EVP_PKEY_derive_init(pctx))
+ goto err;
+ kari->pctx = pctx;
+ return 1;
+ err:
+ if (pctx)
+ EVP_PKEY_CTX_free(pctx);
+ return 0;
+ }
+
+EVP_CIPHER_CTX *CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri)
+ {
+ if (ri->type == CMS_RECIPINFO_AGREE)
+ return &ri->d.kari->ctx;
+ return NULL;
+ }
+
+/* Derive KEK and decrypt/encrypt with it to produce either the
+ * original CEK or the encrypted CEK.
+ */
+
+static int cms_kek_cipher(unsigned char **pout, size_t *poutlen,
+ const unsigned char *in, size_t inlen,
+ CMS_KeyAgreeRecipientInfo *kari, int enc)
+ {
+ /* Key encryption key */
+ unsigned char kek[EVP_MAX_KEY_LENGTH];
+ size_t keklen;
+ int rv = 0;
+ unsigned char *out = NULL;
+ int outlen;
+ keklen = EVP_CIPHER_CTX_key_length(&kari->ctx);
+ if (keklen > EVP_MAX_KEY_LENGTH)
+ return 0;
+ /* Derive KEK */
+ if (EVP_PKEY_derive(kari->pctx, kek, &keklen) <= 0)
+ goto err;
+ /* Set KEK in context */
+ if (!EVP_CipherInit_ex(&kari->ctx, NULL, NULL, kek, NULL, enc))
+ goto err;
+ /* obtain output length of ciphered key */
+ if (!EVP_CipherUpdate(&kari->ctx, NULL, &outlen, in, inlen))
+ goto err;
+ out = OPENSSL_malloc(outlen);
+ if (!out)
+ goto err;
+ if (!EVP_CipherUpdate(&kari->ctx, out, &outlen, in, inlen))
+ goto err;
+ *pout = out;
+ *poutlen = (size_t)outlen;
+ rv = 1;
+
+ err:
+ OPENSSL_cleanse(kek, keklen);
+ if (!rv && out)
+ OPENSSL_free(out);
+ EVP_CIPHER_CTX_cleanup(&kari->ctx);
+ EVP_PKEY_CTX_free(kari->pctx);
+ kari->pctx = NULL;
+ return rv;
+ }
+
+int CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
+ CMS_RecipientEncryptedKey *rek)
+ {
+ int rv = 0;
+ unsigned char *enckey = NULL, *cek = NULL;
+ size_t enckeylen;
+ size_t ceklen;
+ CMS_EncryptedContentInfo *ec;
+ enckeylen = rek->encryptedKey->length;
+ enckey = rek->encryptedKey->data;
+ /* Setup all parameters to derive KEK */
+ if (!cms_env_asn1_ctrl(ri, 1))
+ goto err;
+ /* Attempt to decrypt CEK */
+ if (!cms_kek_cipher(&cek, &ceklen, enckey, enckeylen, ri->d.kari, 0))
+ goto err;
+ ec = cms->d.envelopedData->encryptedContentInfo;
+ if (ec->key)
+ {
+ OPENSSL_cleanse(ec->key, ec->keylen);
+ OPENSSL_free(ec->key);
+ }
+ ec->key = cek;
+ ec->keylen = ceklen;
+ cek = NULL;
+ rv = 1;
+ err:
+ if (cek)
+ OPENSSL_free(cek);
+ return rv;
+ }
+
+/* Create ephemeral key and initialise context based on it */
+static int cms_kari_create_ephemeral_key(CMS_KeyAgreeRecipientInfo *kari,
+ EVP_PKEY *pk)
+ {
+ EVP_PKEY_CTX *pctx = NULL;
+ EVP_PKEY *ekey = NULL;
+ int rv = 0;
+ pctx = EVP_PKEY_CTX_new(pk, NULL);
+ if (!pctx)
+ goto err;
+ if (EVP_PKEY_keygen_init(pctx) <= 0)
+ goto err;
+ if (EVP_PKEY_keygen(pctx, &ekey) <= 0)
+ goto err;
+ EVP_PKEY_CTX_free(pctx);
+ pctx = EVP_PKEY_CTX_new(ekey, NULL);
+ if (!pctx)
+ goto err;
+ if (EVP_PKEY_derive_init(pctx) <= 0)
+ goto err;
+ kari->pctx = pctx;
+ rv = 1;
+ err:
+ if (!rv && pctx)
+ EVP_PKEY_CTX_free(pctx);
+ if (ekey)
+ EVP_PKEY_free(ekey);
+ return rv;
+ }
+
+/* Initialise a ktri based on passed certificate and key */
+
+int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip,
+ EVP_PKEY *pk, unsigned int flags)
+ {
+ CMS_KeyAgreeRecipientInfo *kari;
+ CMS_RecipientEncryptedKey *rek = NULL;
+
+ ri->d.kari = M_ASN1_new_of(CMS_KeyAgreeRecipientInfo);
+ if (!ri->d.kari)
+ return 0;
+ ri->type = CMS_RECIPINFO_AGREE;
+
+ kari = ri->d.kari;
+ kari->version = 3;
+
+ rek = M_ASN1_new_of(CMS_RecipientEncryptedKey);
+ if (!sk_CMS_RecipientEncryptedKey_push(kari->recipientEncryptedKeys, rek))
+ {
+ M_ASN1_free_of(rek, CMS_RecipientEncryptedKey);
+ return 0;
+ }
+
+ if (flags & CMS_USE_KEYID)
+ {
+ rek->rid->type = CMS_REK_KEYIDENTIFIER;
+ if (!cms_set1_keyid(&rek->rid->d.rKeyId->subjectKeyIdentifier, recip))
+ return 0;
+ }
+ else
+ {
+ rek->rid->type = CMS_REK_ISSUER_SERIAL;
+ if (!cms_set1_ias(&rek->rid->d.issuerAndSerialNumber, recip))
+ return 0;
+ }
+
+ /* Create ephemeral key */
+ if (!cms_kari_create_ephemeral_key(kari, pk))
+ return 0;
+
+ CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY);
+ rek->pkey = pk;
+ return 1;
+ }
+
+static int cms_wrap_init(CMS_KeyAgreeRecipientInfo *kari,
+ const EVP_CIPHER *cipher)
+ {
+ EVP_CIPHER_CTX *ctx = &kari->ctx;
+ const EVP_CIPHER *kekcipher;
+ int keylen = EVP_CIPHER_key_length(cipher);
+ /* If a suitable wrap algorithm is already set nothing to do */
+ kekcipher = EVP_CIPHER_CTX_cipher(ctx);
+
+ if (kekcipher)
+ {
+ if (EVP_CIPHER_CTX_mode(ctx) != EVP_CIPH_WRAP_MODE)
+ return 0;
+ return 1;
+ }
+ /* Pick a cipher based on content encryption cipher. If it is
+ * DES3 use DES3 wrap otherwise use AES wrap similar to key
+ * size.
+ */
+ if (EVP_CIPHER_type(cipher) == NID_des_ede3_cbc)
+ kekcipher = EVP_des_ede3_wrap();
+ else if (keylen <= 16)
+ kekcipher = EVP_aes_128_wrap();
+ else if (keylen <= 24)
+ kekcipher = EVP_aes_192_wrap();
+ else
+ kekcipher = EVP_aes_256_wrap();
+ return EVP_EncryptInit_ex(ctx, kekcipher, NULL, NULL, NULL);
+ }
+
+/* Encrypt content key in key agreement recipient info */
+
+int cms_RecipientInfo_kari_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
+ {
+ CMS_KeyAgreeRecipientInfo *kari;
+ CMS_EncryptedContentInfo *ec;
+ CMS_RecipientEncryptedKey *rek;
+ STACK_OF(CMS_RecipientEncryptedKey) *reks;
+ int i;
+
+ if (ri->type != CMS_RECIPINFO_AGREE)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_ENCRYPT,
+ CMS_R_NOT_KEY_AGREEMENT);
+ return 0;
+ }
+ kari = ri->d.kari;
+ reks = kari->recipientEncryptedKeys;
+ ec = cms->d.envelopedData->encryptedContentInfo;
+ /* Initialise wrap algorithm parameters */
+ if (!cms_wrap_init(kari, ec->cipher))
+ return 0;
+ /* If no orignator key set up initialise for ephemeral key
+ * the public key ASN1 structure will set the actual public
+ * key value.
+ */
+ if (kari->originator->type == -1)
+ {
+ CMS_OriginatorIdentifierOrKey *oik = kari->originator;
+ oik->type = CMS_OIK_PUBKEY;
+ oik->d.originatorKey = M_ASN1_new_of(CMS_OriginatorPublicKey);
+ if (!oik->d.originatorKey)
+ return 0;
+ }
+ /* Initialise KDF algorithm */
+ if (!cms_env_asn1_ctrl(ri, 0))
+ return 0;
+ /* For each rek, derive KEK, encrypt CEK */
+ for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++)
+ {
+ unsigned char *enckey;
+ size_t enckeylen;
+ rek = sk_CMS_RecipientEncryptedKey_value(reks, i);
+ if (EVP_PKEY_derive_set_peer(kari->pctx, rek->pkey) <= 0)
+ return 0;
+ if (!cms_kek_cipher(&enckey, &enckeylen, ec->key, ec->keylen,
+ kari, 1))
+ return 0;
+ ASN1_STRING_set0(rek->encryptedKey, enckey, enckeylen);
+ }
+
+ return 1;
+
+ }
diff --git a/crypto/cms/cms_lcl.h b/crypto/cms/cms_lcl.h
index b107cd2d76..7385eaba75 100644
--- a/crypto/cms/cms_lcl.h
+++ b/crypto/cms/cms_lcl.h
@@ -83,10 +83,8 @@ typedef struct CMS_KeyTransRecipientInfo_st CMS_KeyTransRecipientInfo;
typedef struct CMS_OriginatorPublicKey_st CMS_OriginatorPublicKey;
typedef struct CMS_OriginatorIdentifierOrKey_st CMS_OriginatorIdentifierOrKey;
typedef struct CMS_KeyAgreeRecipientInfo_st CMS_KeyAgreeRecipientInfo;
-typedef struct CMS_OtherKeyAttribute_st CMS_OtherKeyAttribute;
typedef struct CMS_RecipientKeyIdentifier_st CMS_RecipientKeyIdentifier;
typedef struct CMS_KeyAgreeRecipientIdentifier_st CMS_KeyAgreeRecipientIdentifier;
-typedef struct CMS_RecipientEncryptedKey_st CMS_RecipientEncryptedKey;
typedef struct CMS_KEKIdentifier_st CMS_KEKIdentifier;
typedef struct CMS_KEKRecipientInfo_st CMS_KEKRecipientInfo;
typedef struct CMS_PasswordRecipientInfo_st CMS_PasswordRecipientInfo;
@@ -216,6 +214,10 @@ struct CMS_KeyAgreeRecipientInfo_st
ASN1_OCTET_STRING *ukm;
X509_ALGOR *keyEncryptionAlgorithm;
STACK_OF(CMS_RecipientEncryptedKey) *recipientEncryptedKeys;
+ /* Public key context associated with current operation */
+ EVP_PKEY_CTX *pctx;
+ /* Cipher context for CEK wrapping */
+ EVP_CIPHER_CTX ctx;
};
struct CMS_OriginatorIdentifierOrKey_st
@@ -238,6 +240,8 @@ struct CMS_RecipientEncryptedKey_st
{
CMS_KeyAgreeRecipientIdentifier *rid;
ASN1_OCTET_STRING *encryptedKey;
+ /* Public key associated with this recipient */
+ EVP_PKEY *pkey;
};
struct CMS_KeyAgreeRecipientIdentifier_st
@@ -431,6 +435,13 @@ DECLARE_ASN1_ALLOC_FUNCTIONS(CMS_IssuerAndSerialNumber)
#define CMS_RECIPINFO_ISSUER_SERIAL 0
#define CMS_RECIPINFO_KEYIDENTIFIER 1
+#define CMS_REK_ISSUER_SERIAL 0
+#define CMS_REK_KEYIDENTIFIER 1
+
+#define CMS_OIK_ISSUER_SERIAL 0
+#define CMS_OIK_KEYIDENTIFIER 1
+#define CMS_OIK_PUBKEY 2
+
BIO *cms_content_bio(CMS_ContentInfo *cms);
CMS_ContentInfo *cms_Data_create(void);
@@ -455,6 +466,11 @@ BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm);
int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain,
X509_ALGOR *mdalg);
+int cms_ias_cert_cmp(CMS_IssuerAndSerialNumber *ias, X509 *cert);
+int cms_keyid_cert_cmp(ASN1_OCTET_STRING *keyid, X509 *cert);
+int cms_set1_ias(CMS_IssuerAndSerialNumber **pias, X509 *cert);
+int cms_set1_keyid(ASN1_OCTET_STRING **pkeyid, X509 *cert);
+
BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec);
BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms);
int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
@@ -467,6 +483,12 @@ ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si);
BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms);
CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms);
+int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd);
+int cms_pkey_get_ri_type(EVP_PKEY *pk);
+/* KARI routines */
+int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip,
+ EVP_PKEY *pk, unsigned int flags);
+int cms_RecipientInfo_kari_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
/* PWRI routines */
int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
diff --git a/crypto/cms/cms_lib.c b/crypto/cms/cms_lib.c
index b62d1bfac0..ab57f0f4a1 100644
--- a/crypto/cms/cms_lib.c
+++ b/crypto/cms/cms_lib.c
@@ -52,7 +52,7 @@
*/
#include <openssl/asn1t.h>
-#include <openssl/x509.h>
+#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
@@ -622,3 +622,62 @@ STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms)
}
return crls;
}
+
+int cms_ias_cert_cmp(CMS_IssuerAndSerialNumber *ias, X509 *cert)
+ {
+ int ret;
+ ret = X509_NAME_cmp(ias->issuer, X509_get_issuer_name(cert));
+ if (ret)
+ return ret;
+ return ASN1_INTEGER_cmp(ias->serialNumber, X509_get_serialNumber(cert));
+ }
+
+int cms_keyid_cert_cmp(ASN1_OCTET_STRING *keyid, X509 *cert)
+ {
+ X509_check_purpose(cert, -1, -1);
+ if (!cert->skid)
+ return -1;
+ return ASN1_OCTET_STRING_cmp(keyid, cert->skid);
+ }
+
+int cms_set1_ias(CMS_IssuerAndSerialNumber **pias, X509 *cert)
+ {
+ CMS_IssuerAndSerialNumber *ias;
+ ias = M_ASN1_new_of(CMS_IssuerAndSerialNumber);
+ if (!ias)
+ goto err;
+ if (!X509_NAME_set(&ias->issuer, X509_get_issuer_name(cert)))
+ goto err;
+ if (!ASN1_STRING_copy(ias->serialNumber, X509_get_serialNumber(cert)))
+ goto err;
+ if (*pias)
+ M_ASN1_free_of(*pias, CMS_IssuerAndSerialNumber);
+ *pias = ias;
+ return 1;
+ err:
+ if (ias)
+ M_ASN1_free_of(ias, CMS_IssuerAndSerialNumber);
+ CMSerr(CMS_F_CMS_SET1_IAS, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+int cms_set1_keyid(ASN1_OCTET_STRING **pkeyid, X509 *cert)
+ {
+ ASN1_OCTET_STRING *keyid = NULL;
+ X509_check_purpose(cert, -1, -1);
+ if (!cert->skid)
+ {
+ CMSerr(CMS_F_CMS_SET1_KEYID, CMS_R_CERTIFICATE_HAS_NO_KEYID);
+ return 0;
+ }
+ keyid = ASN1_STRING_dup(cert->skid);
+ if (!keyid)
+ {
+ CMSerr(CMS_F_CMS_SET1_KEYID, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ if (*pkeyid)
+ ASN1_OCTET_STRING_free(*pkeyid);
+ *pkeyid = keyid;
+ return 1;
+ }
diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c
index 25af94136a..16bdaf890d 100644
--- a/crypto/cms/cms_sd.c
+++ b/crypto/cms/cms_sd.c
@@ -54,6 +54,7 @@
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
+#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/cms.h>
@@ -212,29 +213,13 @@ int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type)
switch(type)
{
case CMS_SIGNERINFO_ISSUER_SERIAL:
- sid->d.issuerAndSerialNumber =
- M_ASN1_new_of(CMS_IssuerAndSerialNumber);
- if (!sid->d.issuerAndSerialNumber)
- goto merr;
- if (!X509_NAME_set(&sid->d.issuerAndSerialNumber->issuer,
- X509_get_issuer_name(cert)))
- goto merr;
- if (!ASN1_STRING_copy(
- sid->d.issuerAndSerialNumber->serialNumber,
- X509_get_serialNumber(cert)))
- goto merr;
+ if (!cms_set1_ias(&sid->d.issuerAndSerialNumber, cert))
+ return 0;
break;
case CMS_SIGNERINFO_KEYIDENTIFIER:
- if (!cert->skid)
- {
- CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER,
- CMS_R_CERTIFICATE_HAS_NO_KEYID);
+ if (!cms_set1_keyid(&sid->d.subjectKeyIdentifier, cert))
return 0;
- }
- sid->d.subjectKeyIdentifier = ASN1_STRING_dup(cert->skid);
- if (!sid->d.subjectKeyIdentifier)
- goto merr;
break;
default:
@@ -245,11 +230,6 @@ int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type)
sid->type = type;
return 1;
-
- merr:
- CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, ERR_R_MALLOC_FAILURE);
- return 0;
-
}
int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid,
@@ -275,24 +255,10 @@ int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid,
int cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert)
{
- int ret;
if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL)
- {
- ret = X509_NAME_cmp(sid->d.issuerAndSerialNumber->issuer,
- X509_get_issuer_name(cert));
- if (ret)
- return ret;
- return ASN1_INTEGER_cmp(sid->d.issuerAndSerialNumber->serialNumber,
- X509_get_serialNumber(cert));
- }
+ return cms_ias_cert_cmp(sid->d.issuerAndSerialNumber, cert);
else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
- {
- X509_check_purpose(cert, -1, -1);
- if (!cert->skid)
- return -1;
- return ASN1_OCTET_STRING_cmp(sid->d.subjectKeyIdentifier,
- cert->skid);
- }
+ return cms_keyid_cert_cmp(sid->d.subjectKeyIdentifier, cert);
else
return -1;
}
diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c
index 8c56e3a852..204595b908 100644
--- a/crypto/cms/cms_smime.c
+++ b/crypto/cms/cms_smime.c
@@ -58,6 +58,7 @@
#include <openssl/err.h>
#include <openssl/cms.h>
#include "cms_lcl.h"
+#include "asn1_locl.h"
static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
{
@@ -606,24 +607,65 @@ CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
return NULL;
}
+static int cms_kari_set1_pkey(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
+ EVP_PKEY *pk, X509 *cert)
+ {
+ int i;
+ STACK_OF(CMS_RecipientEncryptedKey) *reks;
+ CMS_RecipientEncryptedKey *rek;
+ reks = CMS_RecipientInfo_kari_get0_reks(ri);
+ if (!cert)
+ return 0;
+ for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++)
+ {
+ int rv;
+ rek = sk_CMS_RecipientEncryptedKey_value(reks, i);
+ if (CMS_RecipientEncryptedKey_cert_cmp(rek, cert))
+ continue;
+ CMS_RecipientInfo_kari_set0_pkey(ri, pk);
+ rv = CMS_RecipientInfo_kari_decrypt(cms, ri, rek);
+ CMS_RecipientInfo_kari_set0_pkey(ri, NULL);
+ if (rv > 0)
+ return 1;
+ return -1;
+ }
+ return 0;
+ }
+
int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
{
STACK_OF(CMS_RecipientInfo) *ris;
CMS_RecipientInfo *ri;
- int i, r;
+ int i, r, ri_type;
int debug = 0;
ris = CMS_get0_RecipientInfos(cms);
if (ris)
debug = cms->d.envelopedData->encryptedContentInfo->debug;
+ ri_type = cms_pkey_get_ri_type(pk);
+ if (ri_type == CMS_RECIPINFO_NONE)
+ {
+ CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY,
+ CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
+ return 0;
+ }
+
for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
{
ri = sk_CMS_RecipientInfo_value(ris, i);
- if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS)
+ if (CMS_RecipientInfo_type(ri) != ri_type)
continue;
+ if (ri_type == CMS_RECIPINFO_AGREE)
+ {
+ r = cms_kari_set1_pkey(cms, ri, pk, cert);
+ if (r > 0)
+ return 1;
+ if (r < 0)
+ return 0;
+ }
/* If we have a cert try matching RecipientInfo
* otherwise try them all.
*/
- if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0))
+ else if (!cert || !CMS_RecipientInfo_ktri_cert_cmp(ri, cert))
{
CMS_RecipientInfo_set0_pkey(ri, pk);
r = CMS_RecipientInfo_decrypt(cms, ri);
diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h
index ad30f58fbf..e330075dd7 100644
--- a/crypto/evp/evp.h
+++ b/crypto/evp/evp.h
@@ -1020,6 +1020,7 @@ void EVP_PBE_cleanup(void);
#define ASN1_PKEY_CTRL_DEFAULT_MD_NID 0x3
#define ASN1_PKEY_CTRL_CMS_SIGN 0x5
#define ASN1_PKEY_CTRL_CMS_ENVELOPE 0x7
+#define ASN1_PKEY_CTRL_CMS_RI_TYPE 0x8
int EVP_PKEY_asn1_get_count(void);
const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx);
diff --git a/crypto/stack/safestack.h b/crypto/stack/safestack.h
index ea3aa0d800..076d001d80 100644
--- a/crypto/stack/safestack.h
+++ b/crypto/stack/safestack.h
@@ -491,6 +491,28 @@ DECLARE_SPECIAL_STACK_OF(OPENSSL_BLOCK, void)
#define sk_CMS_CertificateChoices_sort(st) SKM_sk_sort(CMS_CertificateChoices, (st))
#define sk_CMS_CertificateChoices_is_sorted(st) SKM_sk_is_sorted(CMS_CertificateChoices, (st))
+#define sk_CMS_RecipientEncryptedKey_new(cmp) SKM_sk_new(CMS_RecipientEncryptedKey, (cmp))
+#define sk_CMS_RecipientEncryptedKey_new_null() SKM_sk_new_null(CMS_RecipientEncryptedKey)
+#define sk_CMS_RecipientEncryptedKey_free(st) SKM_sk_free(CMS_RecipientEncryptedKey, (st))
+#define sk_CMS_RecipientEncryptedKey_num(st) SKM_sk_num(CMS_RecipientEncryptedKey, (st))
+#define sk_CMS_RecipientEncryptedKey_value(st, i) SKM_sk_value(CMS_RecipientEncryptedKey, (st), (i))
+#define sk_CMS_RecipientEncryptedKey_set(st, i, val) SKM_sk_set(CMS_RecipientEncryptedKey, (st), (i), (val))
+#define sk_CMS_RecipientEncryptedKey_zero(st) SKM_sk_zero(CMS_RecipientEncryptedKey, (st))
+#define sk_CMS_RecipientEncryptedKey_push(st, val) SKM_sk_push(CMS_RecipientEncryptedKey, (st), (val))
+#define sk_CMS_RecipientEncryptedKey_unshift(st, val) SKM_sk_unshift(CMS_RecipientEncryptedKey, (st), (val))
+#define sk_CMS_RecipientEncryptedKey_find(st, val) SKM_sk_find(CMS_RecipientEncryptedKey, (st), (val))
+#define sk_CMS_RecipientEncryptedKey_find_ex(st, val) SKM_sk_find_ex(CMS_RecipientEncryptedKey, (st), (val))
+#define sk_CMS_RecipientEncryptedKey_delete(st, i) SKM_sk_delete(CMS_RecipientEncryptedKey, (st), (i))
+#define sk_CMS_RecipientEncryptedKey_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_RecipientEncryptedKey, (st), (ptr))
+#define sk_CMS_RecipientEncryptedKey_insert(st, val, i) SKM_sk_insert(CMS_RecipientEncryptedKey, (st), (val), (i))
+#define sk_CMS_RecipientEncryptedKey_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_RecipientEncryptedKey, (st), (cmp))
+#define sk_CMS_RecipientEncryptedKey_dup(st) SKM_sk_dup(CMS_RecipientEncryptedKey, st)
+#define sk_CMS_RecipientEncryptedKey_pop_free(st, free_func) SKM_sk_pop_free(CMS_RecipientEncryptedKey, (st), (free_func))
+#define sk_CMS_RecipientEncryptedKey_shift(st) SKM_sk_shift(CMS_RecipientEncryptedKey, (st))
+#define sk_CMS_RecipientEncryptedKey_pop(st) SKM_sk_pop(CMS_RecipientEncryptedKey, (st))
+#define sk_CMS_RecipientEncryptedKey_sort(st) SKM_sk_sort(CMS_RecipientEncryptedKey, (st))
+#define sk_CMS_RecipientEncryptedKey_is_sorted(st) SKM_sk_is_sorted(CMS_RecipientEncryptedKey, (st))
+
#define sk_CMS_RecipientInfo_new(cmp) SKM_sk_new(CMS_RecipientInfo, (cmp))
#define sk_CMS_RecipientInfo_new_null() SKM_sk_new_null(CMS_RecipientInfo)
#define sk_CMS_RecipientInfo_free(st) SKM_sk_free(CMS_RecipientInfo, (st))