diff options
author | Jung-uk Kim <jkim@FreeBSD.org> | 2015-10-23 19:46:02 +0000 |
---|---|---|
committer | Jung-uk Kim <jkim@FreeBSD.org> | 2015-10-23 19:46:02 +0000 |
commit | e9fcefce9bb70f20c272a996443928c5f6ab8cd8 (patch) | |
tree | ae816a5a768ec78af3610e509ca39507b33aa9f7 /crypto/cms | |
parent | c07d7b3a386974c338492659291008bed07948e6 (diff) | |
download | src-e9fcefce9bb70f20c272a996443928c5f6ab8cd8.tar.gz src-e9fcefce9bb70f20c272a996443928c5f6ab8cd8.zip |
Import OpenSSL 1.0.2d.vendor/openssl/1.0.2d
Notes
Notes:
svn path=/vendor-crypto/openssl/dist/; revision=289848
svn path=/vendor-crypto/openssl/1.0.2d/; revision=289849; tag=vendor/openssl/1.0.2d
Diffstat (limited to 'crypto/cms')
-rw-r--r-- | crypto/cms/Makefile | 49 | ||||
-rw-r--r-- | crypto/cms/cms.h | 52 | ||||
-rw-r--r-- | crypto/cms/cms_asn1.c | 86 | ||||
-rw-r--r-- | crypto/cms/cms_env.c | 320 | ||||
-rw-r--r-- | crypto/cms/cms_err.c | 18 | ||||
-rw-r--r-- | crypto/cms/cms_kari.c | 465 | ||||
-rw-r--r-- | crypto/cms/cms_lcl.h | 32 | ||||
-rw-r--r-- | crypto/cms/cms_lib.c | 59 | ||||
-rw-r--r-- | crypto/cms/cms_sd.c | 205 | ||||
-rw-r--r-- | crypto/cms/cms_smime.c | 54 |
10 files changed, 1153 insertions, 187 deletions
diff --git a/crypto/cms/Makefile b/crypto/cms/Makefile index b124b5dbf212..6f3a83202638 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) @@ -220,20 +220,39 @@ cms_io.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h cms_io.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h cms_io.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h cms.h cms_io.o: cms_io.c cms_lcl.h +cms_kari.o: ../../e_os.h ../../include/openssl/aes.h +cms_kari.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +cms_kari.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h +cms_kari.o: ../../include/openssl/cms.h ../../include/openssl/conf.h +cms_kari.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h +cms_kari.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +cms_kari.o: ../../include/openssl/ecdsa.h ../../include/openssl/err.h +cms_kari.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +cms_kari.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +cms_kari.o: ../../include/openssl/opensslconf.h +cms_kari.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +cms_kari.o: ../../include/openssl/pem.h ../../include/openssl/pem2.h +cms_kari.o: ../../include/openssl/pkcs7.h ../../include/openssl/rand.h +cms_kari.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h +cms_kari.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h +cms_kari.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h +cms_kari.o: ../../include/openssl/x509v3.h ../asn1/asn1_locl.h ../cryptlib.h +cms_kari.o: cms_kari.c cms_lcl.h cms_lib.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h cms_lib.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h -cms_lib.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h -cms_lib.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h -cms_lib.o: ../../include/openssl/ecdsa.h ../../include/openssl/err.h -cms_lib.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h -cms_lib.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h -cms_lib.o: ../../include/openssl/opensslconf.h ../../include/openssl/opensslv.h -cms_lib.o: ../../include/openssl/ossl_typ.h ../../include/openssl/pem.h -cms_lib.o: ../../include/openssl/pem2.h ../../include/openssl/pkcs7.h -cms_lib.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h -cms_lib.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h -cms_lib.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h cms.h -cms_lib.o: cms_lcl.h cms_lib.c +cms_lib.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h +cms_lib.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +cms_lib.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h +cms_lib.o: ../../include/openssl/err.h ../../include/openssl/evp.h +cms_lib.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +cms_lib.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h +cms_lib.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +cms_lib.o: ../../include/openssl/pem.h ../../include/openssl/pem2.h +cms_lib.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +cms_lib.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +cms_lib.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +cms_lib.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h +cms_lib.o: cms.h cms_lcl.h cms_lib.c cms_pwri.o: ../../e_os.h ../../include/openssl/aes.h cms_pwri.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h cms_pwri.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h @@ -283,4 +302,4 @@ cms_smime.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h cms_smime.o: ../../include/openssl/sha.h ../../include/openssl/stack.h cms_smime.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h cms_smime.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h -cms_smime.o: ../cryptlib.h cms_lcl.h cms_smime.c +cms_smime.o: ../asn1/asn1_locl.h ../cryptlib.h cms_lcl.h cms_smime.c diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h index a2281eda5b0a..e6c7f964bf48 100644 --- a/crypto/cms/cms.h +++ b/crypto/cms/cms.h @@ -72,9 +72,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) @@ -82,6 +85,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 @@ -111,6 +115,7 @@ DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo) # define CMS_REUSE_DIGEST 0x8000 # define CMS_USE_KEYID 0x10000 # define CMS_DEBUG_DECRYPT 0x20000 +# define CMS_KEY_PARAM 0x40000 const ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms); @@ -189,6 +194,7 @@ int CMS_decrypt_set1_password(CMS_ContentInfo *cms, STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms); int CMS_RecipientInfo_type(CMS_RecipientInfo *ri); +EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri); CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher); CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, X509 *recip, unsigned int flags); @@ -234,6 +240,7 @@ CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms, const EVP_CIPHER *kekciph); int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri); +int CMS_RecipientInfo_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri); int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, unsigned int flags); @@ -256,6 +263,8 @@ int CMS_SignedData_init(CMS_ContentInfo *cms); CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, X509 *signer, EVP_PKEY *pk, const EVP_MD *md, unsigned int flags); +EVP_PKEY_CTX *CMS_SignerInfo_get0_pkey_ctx(CMS_SignerInfo *si); +EVP_MD_CTX *CMS_SignerInfo_get0_md_ctx(CMS_SignerInfo *si); STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms); void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer); @@ -268,6 +277,7 @@ int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *certs, void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk, X509 **signer, X509_ALGOR **pdig, X509_ALGOR **psig); +ASN1_OCTET_STRING *CMS_SignerInfo_get0_signature(CMS_SignerInfo *si); int CMS_SignerInfo_sign(CMS_SignerInfo *si); int CMS_SignerInfo_verify(CMS_SignerInfo *si); int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain); @@ -331,8 +341,37 @@ 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); + +int CMS_SharedInfo_encode(unsigned char **pder, X509_ALGOR *kekalg, + ASN1_OCTET_STRING *ukm, int keylen); /* BEGIN ERROR CODES */ /* @@ -377,6 +416,7 @@ void ERR_load_CMS_strings(void); # define CMS_F_CMS_ENVELOPEDDATA_CREATE 124 # define CMS_F_CMS_ENVELOPEDDATA_INIT_BIO 125 # define CMS_F_CMS_ENVELOPED_DATA_INIT 126 +# define CMS_F_CMS_ENV_ASN1_CTRL 171 # define CMS_F_CMS_FINAL 127 # define CMS_F_CMS_GET0_CERTIFICATE_CHOICES 128 # define CMS_F_CMS_GET0_CONTENT 129 @@ -388,6 +428,12 @@ void ERR_load_CMS_strings(void); # define CMS_F_CMS_RECEIPTREQUEST_CREATE0 159 # 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 @@ -401,6 +447,9 @@ void ERR_load_CMS_strings(void); # define CMS_F_CMS_RECIPIENTINFO_SET0_KEY 144 # 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 @@ -452,6 +501,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 f9f267afdcd7..81a3407f1249 100644 --- a/crypto/cms/cms_asn1.c +++ b/crypto/cms/cms_asn1.c @@ -97,6 +97,8 @@ static int cms_si_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, EVP_PKEY_free(si->pkey); if (si->signer) X509_free(si->signer); + if (si->pctx) + EVP_MD_CTX_cleanup(&si->mctx); } return 1; } @@ -164,10 +166,21 @@ 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), @@ -180,13 +193,29 @@ 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), @@ -225,6 +254,8 @@ static int cms_ri_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, EVP_PKEY_free(ktri->pkey); if (ktri->recip) X509_free(ktri->recip); + if (ktri->pctx) + EVP_PKEY_CTX_free(ktri->pctx); } else if (ri->type == CMS_RECIPINFO_KEK) { CMS_KEKRecipientInfo *kekri = ri->d.kekri; if (kekri->key) { @@ -379,3 +410,50 @@ ASN1_SEQUENCE(CMS_Receipt) = { ASN1_SIMPLE(CMS_Receipt, signedContentIdentifier, ASN1_OCTET_STRING), ASN1_SIMPLE(CMS_Receipt, originatorSignatureValue, ASN1_OCTET_STRING) } ASN1_SEQUENCE_END(CMS_Receipt) + +/* + * Utilities to encode the CMS_SharedInfo structure used during key + * derivation. + */ + +typedef struct { + X509_ALGOR *keyInfo; + ASN1_OCTET_STRING *entityUInfo; + ASN1_OCTET_STRING *suppPubInfo; +} CMS_SharedInfo; + +ASN1_SEQUENCE(CMS_SharedInfo) = { + ASN1_SIMPLE(CMS_SharedInfo, keyInfo, X509_ALGOR), + ASN1_EXP_OPT(CMS_SharedInfo, entityUInfo, ASN1_OCTET_STRING, 0), + ASN1_EXP_OPT(CMS_SharedInfo, suppPubInfo, ASN1_OCTET_STRING, 2), +} ASN1_SEQUENCE_END(CMS_SharedInfo) + +int CMS_SharedInfo_encode(unsigned char **pder, X509_ALGOR *kekalg, + ASN1_OCTET_STRING *ukm, int keylen) +{ + union { + CMS_SharedInfo *pecsi; + ASN1_VALUE *a; + } intsi = { + NULL + }; + + ASN1_OCTET_STRING oklen; + unsigned char kl[4]; + CMS_SharedInfo ecsi; + + keylen <<= 3; + kl[0] = (keylen >> 24) & 0xff; + kl[1] = (keylen >> 16) & 0xff; + kl[2] = (keylen >> 8) & 0xff; + kl[3] = keylen & 0xff; + oklen.length = 4; + oklen.data = kl; + oklen.type = V_ASN1_OCTET_STRING; + oklen.flags = 0; + ecsi.keyInfo = kekalg; + ecsi.entityUInfo = ukm; + ecsi.suppPubInfo = &oklen; + intsi.pecsi = &ecsi; + return ASN1_item_i2d(intsi.a, pder, ASN1_ITEM_rptr(CMS_SharedInfo)); +} diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c index 1c3046ce9238..93c06cb00a8f 100644 --- a/crypto/cms/cms_env.c +++ b/crypto/cms/cms_env.c @@ -100,6 +100,36 @@ static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms) return cms_get0_enveloped(cms); } +int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd) +{ + 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); + if (i == -2) { + CMSerr(CMS_F_CMS_ENV_ASN1_CTRL, + CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); + return 0; + } + if (i <= 0) { + CMSerr(CMS_F_CMS_ENV_ASN1_CTRL, CMS_R_CTRL_FAILURE); + return 0; + } + return 1; +} + STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms) { CMS_EnvelopedData *env; @@ -114,6 +144,15 @@ int CMS_RecipientInfo_type(CMS_RecipientInfo *ri) return ri->type; } +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; +} + CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher) { CMS_ContentInfo *cms; @@ -137,19 +176,63 @@ CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher) /* Key Transport Recipient Info (KTRI) routines */ +/* Initialise a ktri based on passed certificate and key */ + +static int cms_RecipientInfo_ktri_init(CMS_RecipientInfo *ri, X509 *recip, + EVP_PKEY *pk, unsigned int flags) +{ + CMS_KeyTransRecipientInfo *ktri; + int idtype; + + ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo); + if (!ri->d.ktri) + return 0; + ri->type = CMS_RECIPINFO_TRANS; + + ktri = ri->d.ktri; + + if (flags & CMS_USE_KEYID) { + ktri->version = 2; + idtype = CMS_RECIPINFO_KEYIDENTIFIER; + } else { + ktri->version = 0; + idtype = CMS_RECIPINFO_ISSUER_SERIAL; + } + + /* + * Not a typo: RecipientIdentifier and SignerIdentifier are the same + * structure. + */ + + 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) { + ktri->pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL); + if (!ktri->pctx) + return 0; + if (EVP_PKEY_encrypt_init(ktri->pctx) <= 0) + return 0; + } else if (!cms_env_asn1_ctrl(ri, 0)) + return 0; + return 1; +} + /* - * Add a recipient certificate. For now only handle key transport. If we ever - * handle key agreement will need updating. + * 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_KeyTransRecipientInfo *ktri; CMS_EnvelopedData *env; EVP_PKEY *pk = NULL; - int i, type; env = cms_get0_enveloped(cms); if (!env) goto err; @@ -159,59 +242,36 @@ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, if (!ri) goto merr; - /* Initialize and add key transport recipient info */ - - ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo); - if (!ri->d.ktri) - goto merr; - 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; - if (env->version < 2) - env->version = 2; - type = CMS_RECIPINFO_KEYIDENTIFIER; - } else { - ktri->version = 0; - type = CMS_RECIPINFO_ISSUER_SERIAL; - } + switch (cms_pkey_get_ri_type(pk)) { - /* - * Not a typo: RecipientIdentifier and SignerIdentifier are the same - * structure. - */ + case CMS_RECIPINFO_TRANS: + if (!cms_RecipientInfo_ktri_init(ri, recip, pk, flags)) + goto err; + break; - if (!cms_set1_SignerIdentifier(ktri->rid, recip, type)) + 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 (pk->ameth && pk->ameth->pkey_ctrl) { - i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_ENVELOPE, 0, ri); - if (i == -2) { - CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, - CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); - goto err; - } - if (i <= 0) { - CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_CTRL_FAILURE); - goto err; - } } if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) goto merr; + EVP_PKEY_free(pk); + return ri; merr: @@ -219,6 +279,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; } @@ -288,7 +350,7 @@ static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms, { CMS_KeyTransRecipientInfo *ktri; CMS_EncryptedContentInfo *ec; - EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY_CTX *pctx; unsigned char *ek = NULL; size_t eklen; @@ -301,12 +363,19 @@ static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms, ktri = ri->d.ktri; ec = cms->d.envelopedData->encryptedContentInfo; - pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL); - if (!pctx) - return 0; + pctx = ktri->pctx; - if (EVP_PKEY_encrypt_init(pctx) <= 0) - goto err; + if (pctx) { + if (!cms_env_asn1_ctrl(ri, 0)) + goto err; + } else { + pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL); + if (!pctx) + return 0; + + if (EVP_PKEY_encrypt_init(pctx) <= 0) + goto err; + } if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT, EVP_PKEY_CTRL_CMS_ENCRYPT, 0, ri) <= 0) { @@ -333,8 +402,10 @@ static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms, ret = 1; err: - if (pctx) + if (pctx) { EVP_PKEY_CTX_free(pctx); + ktri->pctx = NULL; + } if (ek) OPENSSL_free(ek); return ret; @@ -347,7 +418,7 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri) { CMS_KeyTransRecipientInfo *ktri = ri->d.ktri; - EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY *pkey = ktri->pkey; unsigned char *ek = NULL; size_t eklen; int ret = 0; @@ -359,20 +430,23 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, return 0; } - pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL); - if (!pctx) + ktri->pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!ktri->pctx) return 0; - if (EVP_PKEY_decrypt_init(pctx) <= 0) + if (EVP_PKEY_decrypt_init(ktri->pctx) <= 0) goto err; - if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT, + if (!cms_env_asn1_ctrl(ri, 1)) + goto err; + + if (EVP_PKEY_CTX_ctrl(ktri->pctx, -1, EVP_PKEY_OP_DECRYPT, EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CTRL_ERROR); goto err; } - if (EVP_PKEY_decrypt(pctx, NULL, &eklen, + if (EVP_PKEY_decrypt(ktri->pctx, NULL, &eklen, ktri->encryptedKey->data, ktri->encryptedKey->length) <= 0) goto err; @@ -384,7 +458,7 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, goto err; } - if (EVP_PKEY_decrypt(pctx, ek, &eklen, + if (EVP_PKEY_decrypt(ktri->pctx, ek, &eklen, ktri->encryptedKey->data, ktri->encryptedKey->length) <= 0) { CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB); @@ -402,8 +476,10 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, ec->keylen = eklen; err: - if (pctx) - EVP_PKEY_CTX_free(pctx); + if (ktri->pctx) { + EVP_PKEY_CTX_free(ktri->pctx); + ktri->pctx = NULL; + } if (!ret && ek) OPENSSL_free(ek); @@ -745,12 +821,99 @@ int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri) } } +int CMS_RecipientInfo_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri) +{ + switch (ri->type) { + 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; + + case CMS_RECIPINFO_PASS: + return cms_RecipientInfo_pwri_crypt(cms, ri, 1); + break; + + default: + CMSerr(CMS_F_CMS_RECIPIENTINFO_ENCRYPT, + CMS_R_UNSUPPORTED_RECIPIENT_TYPE); + return 0; + } +} + +/* Check structures and fixup version numbers (if necessary) */ + +static void cms_env_set_originfo_version(CMS_EnvelopedData *env) +{ + CMS_OriginatorInfo *org = env->originatorInfo; + int i; + if (org == NULL) + return; + for (i = 0; i < sk_CMS_CertificateChoices_num(org->certificates); i++) { + CMS_CertificateChoices *cch; + cch = sk_CMS_CertificateChoices_value(org->certificates, i); + if (cch->type == CMS_CERTCHOICE_OTHER) { + env->version = 4; + return; + } else if (cch->type == CMS_CERTCHOICE_V2ACERT) { + if (env->version < 3) + env->version = 3; + } + } + + for (i = 0; i < sk_CMS_RevocationInfoChoice_num(org->crls); i++) { + CMS_RevocationInfoChoice *rch; + rch = sk_CMS_RevocationInfoChoice_value(org->crls, i); + if (rch->type == CMS_REVCHOICE_OTHER) { + env->version = 4; + return; + } + } +} + +static void cms_env_set_version(CMS_EnvelopedData *env) +{ + int i; + CMS_RecipientInfo *ri; + + /* + * Can't set version higher than 4 so if 4 or more already nothing to do. + */ + if (env->version >= 4) + return; + + cms_env_set_originfo_version(env); + + if (env->version >= 3) + return; + + for (i = 0; i < sk_CMS_RecipientInfo_num(env->recipientInfos); i++) { + ri = sk_CMS_RecipientInfo_value(env->recipientInfos, i); + if (ri->type == CMS_RECIPINFO_PASS || ri->type == CMS_RECIPINFO_OTHER) { + env->version = 3; + return; + } else if (ri->type != CMS_RECIPINFO_TRANS + || ri->d.ktri->version != 0) { + env->version = 2; + } + } + if (env->version == 2) + return; + if (env->originatorInfo || env->unprotectedAttrs) + env->version = 2; + env->version = 0; +} + BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) { CMS_EncryptedContentInfo *ec; STACK_OF(CMS_RecipientInfo) *rinfos; CMS_RecipientInfo *ri; - int i, r, ok = 0; + int i, ok = 0; BIO *ret; /* Get BIO first to set up key */ @@ -769,32 +932,13 @@ BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) { ri = sk_CMS_RecipientInfo_value(rinfos, i); - - switch (ri->type) { - case CMS_RECIPINFO_TRANS: - r = cms_RecipientInfo_ktri_encrypt(cms, ri); - break; - - case CMS_RECIPINFO_KEK: - r = cms_RecipientInfo_kekri_encrypt(cms, ri); - break; - - case CMS_RECIPINFO_PASS: - r = cms_RecipientInfo_pwri_crypt(cms, ri, 1); - break; - - default: - CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, - CMS_R_UNSUPPORTED_RECIPIENT_TYPE); - goto err; - } - - if (r <= 0) { + if (CMS_RecipientInfo_encrypt(cms, ri) <= 0) { CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, CMS_R_ERROR_SETTING_RECIPIENTINFO); goto err; } } + cms_env_set_version(cms->d.envelopedData); ok = 1; @@ -812,3 +956,19 @@ 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 faf2fccd3b8c..15572ea348c8 100644 --- a/crypto/cms/cms_err.c +++ b/crypto/cms/cms_err.c @@ -1,6 +1,6 @@ /* crypto/cms/cms_err.c */ /* ==================================================================== - * Copyright (c) 1999-2009 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-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 @@ -110,6 +110,7 @@ static ERR_STRING_DATA CMS_str_functs[] = { {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_FINAL), "CMS_final"}, {ERR_FUNC(CMS_F_CMS_GET0_CERTIFICATE_CHOICES), "CMS_GET0_CERTIFICATE_CHOICES"}, @@ -124,6 +125,17 @@ static ERR_STRING_DATA CMS_str_functs[] = { "CMS_ReceiptRequest_create0"}, {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), @@ -150,6 +162,9 @@ static ERR_STRING_DATA CMS_str_functs[] = { "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"}, @@ -221,6 +236,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), diff --git a/crypto/cms/cms_kari.c b/crypto/cms/cms_kari.c new file mode 100644 index 000000000000..2cfcdb29cd50 --- /dev/null +++ b/crypto/cms/cms_kari.c @@ -0,0 +1,465 @@ +/* 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) +DECLARE_ASN1_ITEM(CMS_RecipientKeyIdentifier) + +/* 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; + rek->rid->d.rKeyId = M_ASN1_new_of(CMS_RecipientKeyIdentifier); + if (rek->rid->d.rKeyId == NULL) + return 0; + 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 4f4c4c7434f3..20f2c25f5ae9 100644 --- a/crypto/cms/cms_lcl.h +++ b/crypto/cms/cms_lcl.h @@ -84,11 +84,9 @@ 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; @@ -138,6 +136,9 @@ struct CMS_SignerInfo_st { /* Signing certificate and key */ X509 *signer; EVP_PKEY *pkey; + /* Digest and public key context for alternative parameters */ + EVP_MD_CTX mctx; + EVP_PKEY_CTX *pctx; }; struct CMS_SignerIdentifier_st { @@ -194,6 +195,8 @@ struct CMS_KeyTransRecipientInfo_st { /* Recipient Key and cert */ X509 *recip; EVP_PKEY *pkey; + /* Public key context for this operation */ + EVP_PKEY_CTX *pctx; }; struct CMS_KeyAgreeRecipientInfo_st { @@ -202,6 +205,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 { @@ -221,6 +228,8 @@ struct CMS_OriginatorPublicKey_st { struct CMS_RecipientEncryptedKey_st { CMS_KeyAgreeRecipientIdentifier *rid; ASN1_OCTET_STRING *encryptedKey; + /* Public key associated with this recipient */ + EVP_PKEY *pkey; }; struct CMS_KeyAgreeRecipientIdentifier_st { @@ -394,6 +403,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); @@ -420,6 +436,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, @@ -432,6 +453,13 @@ 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 e93846168038..d6cb60d02d15 100644 --- a/crypto/cms/cms_lib.c +++ b/crypto/cms/cms_lib.c @@ -53,7 +53,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> @@ -593,3 +593,60 @@ 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 6daa2627dbab..721ffd5afb85 100644 --- a/crypto/cms/cms_sd.c +++ b/crypto/cms/cms_sd.c @@ -55,6 +55,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> @@ -197,27 +198,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: @@ -228,11 +215,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, @@ -255,23 +237,32 @@ 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)); - } 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); - } else + if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL) + return cms_ias_cert_cmp(sid->d.issuerAndSerialNumber, cert); + else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER) + return cms_keyid_cert_cmp(sid->d.subjectKeyIdentifier, cert); + else return -1; } +static int cms_sd_asn1_ctrl(CMS_SignerInfo *si, int cmd) +{ + EVP_PKEY *pkey = si->pkey; + int i; + if (!pkey->ameth || !pkey->ameth->pkey_ctrl) + return 1; + i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_SIGN, cmd, si); + if (i == -2) { + CMSerr(CMS_F_CMS_SD_ASN1_CTRL, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); + return 0; + } + if (i <= 0) { + CMSerr(CMS_F_CMS_SD_ASN1_CTRL, CMS_R_CTRL_FAILURE); + return 0; + } + return 1; +} + CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, X509 *signer, EVP_PKEY *pk, const EVP_MD *md, unsigned int flags) @@ -298,6 +289,8 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, si->pkey = pk; si->signer = signer; + EVP_MD_CTX_init(&si->mctx); + si->pctx = NULL; if (flags & CMS_USE_KEYID) { si->version = 3; @@ -350,19 +343,8 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, } } - if (pk->ameth && pk->ameth->pkey_ctrl) { - i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_SIGN, 0, si); - if (i == -2) { - CMSerr(CMS_F_CMS_ADD1_SIGNER, - CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); - goto err; - } - if (i <= 0) { - CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_CTRL_FAILURE); - goto err; - } - } - + if (!(flags & CMS_KEY_PARAM) && !cms_sd_asn1_ctrl(si, 0)) + goto err; if (!(flags & CMS_NOATTR)) { /* * Initialialize signed attributes strutucture so other attributes @@ -386,7 +368,8 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, if (flags & CMS_REUSE_DIGEST) { if (!cms_copy_messageDigest(cms, si)) goto err; - if (!(flags & CMS_PARTIAL) && !CMS_SignerInfo_sign(si)) + if (!(flags & (CMS_PARTIAL | CMS_KEY_PARAM)) && + !CMS_SignerInfo_sign(si)) goto err; } } @@ -397,6 +380,20 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, goto merr; } + if (flags & CMS_KEY_PARAM) { + if (flags & CMS_NOATTR) { + si->pctx = EVP_PKEY_CTX_new(si->pkey, NULL); + if (!si->pctx) + goto err; + if (EVP_PKEY_sign_init(si->pctx) <= 0) + goto err; + if (EVP_PKEY_CTX_set_signature_md(si->pctx, md) <= 0) + goto err; + } else if (EVP_DigestSignInit(&si->mctx, &si->pctx, md, NULL, pk) <= + 0) + goto err; + } + if (!sd->signerInfos) sd->signerInfos = sk_CMS_SignerInfo_new_null(); if (!sd->signerInfos || !sk_CMS_SignerInfo_push(sd->signerInfos, si)) @@ -443,6 +440,16 @@ static int cms_add1_signingTime(CMS_SignerInfo *si, ASN1_TIME *t) } +EVP_PKEY_CTX *CMS_SignerInfo_get0_pkey_ctx(CMS_SignerInfo *si) +{ + return si->pctx; +} + +EVP_MD_CTX *CMS_SignerInfo_get0_md_ctx(CMS_SignerInfo *si) +{ + return &si->mctx; +} + STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms) { CMS_SignedData *sd; @@ -561,11 +568,17 @@ void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk, *psig = si->signatureAlgorithm; } +ASN1_OCTET_STRING *CMS_SignerInfo_get0_signature(CMS_SignerInfo *si) +{ + return si->signature; +} + static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms, CMS_SignerInfo *si, BIO *chain) { EVP_MD_CTX mctx; int r = 0; + EVP_PKEY_CTX *pctx = NULL; EVP_MD_CTX_init(&mctx); if (!si->pkey) { @@ -575,6 +588,9 @@ static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms, if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm)) goto err; + /* Set SignerInfo algortihm details if we used custom parametsr */ + if (si->pctx && !cms_sd_asn1_ctrl(si, 0)) + goto err; /* * If any signed attributes calculate and add messageDigest attribute @@ -596,6 +612,23 @@ static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms, goto err; if (!CMS_SignerInfo_sign(si)) goto err; + } else if (si->pctx) { + unsigned char *sig; + size_t siglen; + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + pctx = si->pctx; + if (!EVP_DigestFinal_ex(&mctx, md, &mdlen)) + goto err; + siglen = EVP_PKEY_size(si->pkey); + sig = OPENSSL_malloc(siglen); + if (!sig) { + CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, ERR_R_MALLOC_FAILURE); + goto err; + } + if (EVP_PKEY_sign(pctx, sig, &siglen, md, mdlen) <= 0) + goto err; + ASN1_STRING_set0(si->signature, sig, siglen); } else { unsigned char *sig; unsigned int siglen; @@ -616,6 +649,8 @@ static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms, err: EVP_MD_CTX_cleanup(&mctx); + if (pctx) + EVP_PKEY_CTX_free(pctx); return r; } @@ -637,7 +672,7 @@ int cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain) int CMS_SignerInfo_sign(CMS_SignerInfo *si) { - EVP_MD_CTX mctx; + EVP_MD_CTX *mctx = &si->mctx; EVP_PKEY_CTX *pctx; unsigned char *abuf = NULL; int alen; @@ -648,15 +683,18 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si) if (md == NULL) return 0; - EVP_MD_CTX_init(&mctx); - if (CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1) < 0) { if (!cms_add1_signingTime(si, NULL)) goto err; } - if (EVP_DigestSignInit(&mctx, &pctx, md, NULL, si->pkey) <= 0) - goto err; + if (si->pctx) + pctx = si->pctx; + else { + EVP_MD_CTX_init(mctx); + if (EVP_DigestSignInit(mctx, &pctx, md, NULL, si->pkey) <= 0) + goto err; + } if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, EVP_PKEY_CTRL_CMS_SIGN, 0, si) <= 0) { @@ -668,15 +706,15 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si) ASN1_ITEM_rptr(CMS_Attributes_Sign)); if (!abuf) goto err; - if (EVP_DigestSignUpdate(&mctx, abuf, alen) <= 0) + if (EVP_DigestSignUpdate(mctx, abuf, alen) <= 0) goto err; - if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0) + if (EVP_DigestSignFinal(mctx, NULL, &siglen) <= 0) goto err; OPENSSL_free(abuf); abuf = OPENSSL_malloc(siglen); if (!abuf) goto err; - if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0) + if (EVP_DigestSignFinal(mctx, abuf, &siglen) <= 0) goto err; if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, @@ -685,7 +723,7 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si) goto err; } - EVP_MD_CTX_cleanup(&mctx); + EVP_MD_CTX_cleanup(mctx); ASN1_STRING_set0(si->signature, abuf, siglen); @@ -694,15 +732,14 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si) err: if (abuf) OPENSSL_free(abuf); - EVP_MD_CTX_cleanup(&mctx); + EVP_MD_CTX_cleanup(mctx); return 0; } int CMS_SignerInfo_verify(CMS_SignerInfo *si) { - EVP_MD_CTX mctx; - EVP_PKEY_CTX *pctx; + EVP_MD_CTX *mctx = &si->mctx; unsigned char *abuf = NULL; int alen, r = -1; const EVP_MD *md = NULL; @@ -715,26 +752,29 @@ int CMS_SignerInfo_verify(CMS_SignerInfo *si) md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm); if (md == NULL) return -1; - EVP_MD_CTX_init(&mctx); - if (EVP_DigestVerifyInit(&mctx, &pctx, md, NULL, si->pkey) <= 0) + EVP_MD_CTX_init(mctx); + if (EVP_DigestVerifyInit(mctx, &si->pctx, md, NULL, si->pkey) <= 0) + goto err; + + if (!cms_sd_asn1_ctrl(si, 1)) goto err; alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs, &abuf, ASN1_ITEM_rptr(CMS_Attributes_Verify)); if (!abuf) goto err; - r = EVP_DigestVerifyUpdate(&mctx, abuf, alen); + r = EVP_DigestVerifyUpdate(mctx, abuf, alen); OPENSSL_free(abuf); if (r <= 0) { r = -1; goto err; } - r = EVP_DigestVerifyFinal(&mctx, + r = EVP_DigestVerifyFinal(mctx, si->signature->data, si->signature->length); if (r <= 0) CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_VERIFICATION_FAILURE); err: - EVP_MD_CTX_cleanup(&mctx); + EVP_MD_CTX_cleanup(mctx); return r; } @@ -773,7 +813,10 @@ int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain) { ASN1_OCTET_STRING *os = NULL; EVP_MD_CTX mctx; + EVP_PKEY_CTX *pkctx = NULL; int r = -1; + unsigned char mval[EVP_MAX_MD_SIZE]; + unsigned int mlen; EVP_MD_CTX_init(&mctx); /* If we have any signed attributes look for messageDigest value */ if (CMS_signed_get_attr_count(si) >= 0) { @@ -790,16 +833,15 @@ int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain) if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm)) goto err; + if (EVP_DigestFinal_ex(&mctx, mval, &mlen) <= 0) { + CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT, + CMS_R_UNABLE_TO_FINALIZE_CONTEXT); + goto err; + } + /* If messageDigest found compare it */ if (os) { - unsigned char mval[EVP_MAX_MD_SIZE]; - unsigned int mlen; - if (EVP_DigestFinal_ex(&mctx, mval, &mlen) <= 0) { - CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT, - CMS_R_UNABLE_TO_FINALIZE_CONTEXT); - goto err; - } if (mlen != (unsigned int)os->length) { CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT, CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH); @@ -813,8 +855,17 @@ int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain) } else r = 1; } else { - r = EVP_VerifyFinal(&mctx, si->signature->data, - si->signature->length, si->pkey); + const EVP_MD *md = EVP_MD_CTX_md(&mctx); + pkctx = EVP_PKEY_CTX_new(si->pkey, NULL); + if (EVP_PKEY_verify_init(pkctx) <= 0) + goto err; + if (EVP_PKEY_CTX_set_signature_md(pkctx, md) <= 0) + goto err; + si->pctx = pkctx; + if (!cms_sd_asn1_ctrl(si, 1)) + goto err; + r = EVP_PKEY_verify(pkctx, si->signature->data, + si->signature->length, mval, mlen); if (r <= 0) { CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT, CMS_R_VERIFICATION_FAILURE); @@ -823,6 +874,8 @@ int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain) } err: + if (pkctx) + EVP_PKEY_CTX_free(pkctx); EVP_MD_CTX_cleanup(&mctx); return r; diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index 8b37560821ad..5522a376acb6 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -59,6 +59,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) { @@ -373,7 +374,7 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, tmpin = BIO_new_mem_buf(ptr, len); if (tmpin == NULL) { CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE); - return 0; + goto err2; } } else tmpin = dcont; @@ -404,6 +405,7 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, else BIO_free_all(cmsbio); + err2: if (cms_certs) sk_X509_pop_free(cms_certs, X509_free); if (crls) @@ -567,25 +569,63 @@ 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 debug = 0, ri_match = 0; + int i, r, ri_type; + int debug = 0, match_ri = 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; - ri_match = 1; + match_ri = 1; + 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); CMS_RecipientInfo_set0_pkey(ri, NULL); @@ -613,7 +653,7 @@ int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) } } /* If no cert and not debugging always return success */ - if (ri_match && !cert && !debug) { + if (match_ri && !cert && !debug) { ERR_clear_error(); return 1; } |