summaryrefslogtreecommitdiff
path: root/crypto/cms/cms_kari.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/cms/cms_kari.c')
-rw-r--r--crypto/cms/cms_kari.c93
1 files changed, 83 insertions, 10 deletions
diff --git a/crypto/cms/cms_kari.c b/crypto/cms/cms_kari.c
index 6b0a59ebde..3299e9b5f5 100644
--- a/crypto/cms/cms_kari.c
+++ b/crypto/cms/cms_kari.c
@@ -152,7 +152,7 @@ int CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek,
return -1;
}
-int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk)
+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;
@@ -161,9 +161,18 @@ int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk)
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:
@@ -171,6 +180,11 @@ int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk)
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)
@@ -283,10 +297,29 @@ static int cms_kari_create_ephemeral_key(CMS_KeyAgreeRecipientInfo *kari,
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 *pk, unsigned int flags)
+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;
@@ -321,12 +354,36 @@ int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip,
return 0;
}
- /* Create ephemeral key */
- if (!cms_kari_create_ephemeral_key(kari, pk))
- 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(pk);
- rek->pkey = pk;
+ EVP_PKEY_up_ref(recipPubKey);
+ rek->pkey = recipPubKey;
return 1;
}
@@ -336,14 +393,30 @@ static int cms_wrap_init(CMS_KeyAgreeRecipientInfo *kari,
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) {
+ 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.