mirror of
https://github.com/QuasarApp/openssl.git
synced 2025-05-09 07:59:44 +00:00
... and only *define* them in the source files that need them. Use DEFINE_OR_DECLARE which is set appropriately for internal builds and not non-deprecated builds. Deprecate stack-of-block Better documentation Move some ASN1 struct typedefs to types.h Update ParseC to handle this. Most of all, ParseC needed to be more consistent. The handlers are "recursive", in so far that they are called again and again until they terminate, which depends entirely on what the "massager" returns. There's a comment at the beginning of ParseC that explains how that works. {Richard Levtte} Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com> Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/10669)
538 lines
16 KiB
C
538 lines
16 KiB
C
/*
|
|
* Copyright 2013-2020 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include "internal/cryptlib.h"
|
|
#include <openssl/asn1t.h>
|
|
#include <openssl/pem.h>
|
|
#include <openssl/x509v3.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/cms.h>
|
|
#include <openssl/aes.h>
|
|
#include "cms_local.h"
|
|
#include "crypto/asn1.h"
|
|
|
|
DEFINE_STACK_OF(CMS_RecipientEncryptedKey)
|
|
|
|
/* 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_and_peer(CMS_RecipientInfo *ri, EVP_PKEY *pk, X509 *peer)
|
|
{
|
|
EVP_PKEY_CTX *pctx;
|
|
CMS_KeyAgreeRecipientInfo *kari = ri->d.kari;
|
|
|
|
EVP_PKEY_CTX_free(kari->pctx);
|
|
kari->pctx = NULL;
|
|
if (pk == NULL)
|
|
return 1;
|
|
|
|
pctx = EVP_PKEY_CTX_new(pk, NULL);
|
|
if (pctx == NULL || EVP_PKEY_derive_init(pctx) <= 0)
|
|
goto err;
|
|
|
|
if (peer != NULL) {
|
|
EVP_PKEY *pub_pkey = X509_get0_pubkey(peer);
|
|
|
|
if (EVP_PKEY_derive_set_peer(pctx, pub_pkey) <= 0)
|
|
goto err;
|
|
}
|
|
|
|
kari->pctx = pctx;
|
|
return 1;
|
|
err:
|
|
EVP_PKEY_CTX_free(pctx);
|
|
return 0;
|
|
}
|
|
|
|
int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk)
|
|
{
|
|
return CMS_RecipientInfo_kari_set0_pkey_and_peer(ri, pk, NULL);
|
|
}
|
|
|
|
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 == NULL)
|
|
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)
|
|
OPENSSL_free(out);
|
|
EVP_CIPHER_CTX_reset(kari->ctx);
|
|
/* FIXME: WHY IS kari->pctx freed here? /RL */
|
|
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;
|
|
|
|
{
|
|
/*
|
|
* TODO(3.0) Remove this when we have functionality to deserialize
|
|
* parameters in EVP_PKEY form from an X509_ALGOR.
|
|
* This is needed to be able to replace the EC_KEY specific decoding
|
|
* that happens in ecdh_cms_set_peerkey() (crypto/ec/ec_ameth.c)
|
|
*
|
|
* THIS IS TEMPORARY
|
|
*/
|
|
EVP_PKEY_CTX *pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
|
EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(pctx);
|
|
|
|
EVP_PKEY_get0(pkey);
|
|
if (EVP_PKEY_id(pkey) == EVP_PKEY_NONE) {
|
|
CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_DECRYPT,
|
|
CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
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;
|
|
OPENSSL_clear_free(ec->key, ec->keylen);
|
|
ec->key = cek;
|
|
ec->keylen = ceklen;
|
|
cek = NULL;
|
|
rv = 1;
|
|
err:
|
|
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 == NULL)
|
|
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 == NULL)
|
|
goto err;
|
|
if (EVP_PKEY_derive_init(pctx) <= 0)
|
|
goto err;
|
|
kari->pctx = pctx;
|
|
rv = 1;
|
|
err:
|
|
if (!rv)
|
|
EVP_PKEY_CTX_free(pctx);
|
|
EVP_PKEY_free(ekey);
|
|
return rv;
|
|
}
|
|
|
|
/* Set originator private key and initialise context based on it */
|
|
static int cms_kari_set_originator_private_key(CMS_KeyAgreeRecipientInfo *kari, EVP_PKEY *originatorPrivKey )
|
|
{
|
|
EVP_PKEY_CTX *pctx = NULL;
|
|
int rv = 0;
|
|
|
|
pctx = EVP_PKEY_CTX_new(originatorPrivKey, NULL);
|
|
if (pctx == NULL)
|
|
goto err;
|
|
if (EVP_PKEY_derive_init(pctx) <= 0)
|
|
goto err;
|
|
|
|
kari->pctx = pctx;
|
|
rv = 1;
|
|
err:
|
|
if (rv == 0)
|
|
EVP_PKEY_CTX_free(pctx);
|
|
return rv;
|
|
}
|
|
|
|
/* Initialise a kari based on passed certificate and key */
|
|
|
|
int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip, EVP_PKEY *recipPubKey, X509 * originator, EVP_PKEY *originatorPrivKey, 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 (rek == NULL)
|
|
return 0;
|
|
|
|
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;
|
|
}
|
|
|
|
if (originatorPrivKey == NULL && originator == NULL) {
|
|
/* Create ephemeral key */
|
|
if (!cms_kari_create_ephemeral_key(kari, recipPubKey))
|
|
return 0;
|
|
} else {
|
|
/* Use originator key */
|
|
CMS_OriginatorIdentifierOrKey *oik = ri->d.kari->originator;
|
|
|
|
if (originatorPrivKey == NULL && originator == NULL)
|
|
return 0;
|
|
|
|
if (flags & CMS_USE_ORIGINATOR_KEYID) {
|
|
oik->type = CMS_OIK_KEYIDENTIFIER;
|
|
oik->d.subjectKeyIdentifier = ASN1_OCTET_STRING_new();
|
|
if (oik->d.subjectKeyIdentifier == NULL)
|
|
return 0;
|
|
if (!cms_set1_keyid(&oik->d.subjectKeyIdentifier, originator))
|
|
return 0;
|
|
} else {
|
|
oik->type = CMS_REK_ISSUER_SERIAL;
|
|
if (!cms_set1_ias(&oik->d.issuerAndSerialNumber, originator))
|
|
return 0;
|
|
}
|
|
|
|
if (!cms_kari_set_originator_private_key(kari, originatorPrivKey))
|
|
return 0;
|
|
}
|
|
|
|
EVP_PKEY_up_ref(recipPubKey);
|
|
rek->pkey = recipPubKey;
|
|
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);
|
|
int ret;
|
|
|
|
/* If a suitable wrap algorithm is already set nothing to do */
|
|
kekcipher = EVP_CIPHER_CTX_cipher(ctx);
|
|
if (kekcipher != NULL) {
|
|
if (EVP_CIPHER_CTX_mode(ctx) != EVP_CIPH_WRAP_MODE)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
else if (cipher != NULL
|
|
&& (EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_GET_WRAP_CIPHER)) {
|
|
ret = EVP_CIPHER_meth_get_ctrl(cipher)(NULL, EVP_CTRL_GET_WRAP_CIPHER,
|
|
0, &kekcipher);
|
|
if (ret <= 0)
|
|
return 0;
|
|
|
|
if (kekcipher != NULL) {
|
|
if (EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
|
|
return 0;
|
|
|
|
return EVP_EncryptInit_ex(ctx, kekcipher, NULL, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Pick a cipher based on content encryption cipher. If it is DES3 use
|
|
* DES3 wrap otherwise use AES wrap similar to key size.
|
|
*/
|
|
#ifndef OPENSSL_NO_DES
|
|
if (EVP_CIPHER_type(cipher) == NID_des_ede3_cbc)
|
|
kekcipher = EVP_des_ede3_wrap();
|
|
else
|
|
#endif
|
|
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(const CMS_ContentInfo *cms,
|
|
CMS_RecipientInfo *ri)
|
|
{
|
|
CMS_KeyAgreeRecipientInfo *kari;
|
|
CMS_EncryptedContentInfo *ec;
|
|
CMS_RecipientEncryptedKey *rek;
|
|
STACK_OF(CMS_RecipientEncryptedKey) *reks;
|
|
int i;
|
|
|
|
{
|
|
/*
|
|
* TODO(3.0) Remove this when we have figured out all the details
|
|
* need to set up encryption right. With legacy keys, a *lot* is
|
|
* happening in the CMS specific EVP_PKEY_ASN1_METHOD functions,
|
|
* such as automatically setting a default KDF type, KDF digest,
|
|
* all that kind of stuff.
|
|
* With EVP_SIGNATURE, setting a default digest is done by getting
|
|
* the default MD for the key, and then inject that back into the
|
|
* signature implementation... we could do something similar with
|
|
* CMS, possibly using CMS specific OSSL_PARAM keys, just like we
|
|
* have for certain AlgorithmIdentifier retrievals.
|
|
*
|
|
* THIS IS TEMPORARY
|
|
*/
|
|
EVP_PKEY_CTX *pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
|
EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(pctx);
|
|
|
|
EVP_PKEY_get0(pkey);
|
|
if (EVP_PKEY_id(pkey) == EVP_PKEY_NONE) {
|
|
CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_ENCRYPT,
|
|
CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
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 originator 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;
|
|
|
|
}
|