diff options
Diffstat (limited to 'crypto/cms/cms_kari.c')
-rw-r--r-- | crypto/cms/cms_kari.c | 93 |
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. |