xref: /third_party/openssl/crypto/cms/cms_ec.c (revision e1051a39)
1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2006-2023 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <assert.h>
11e1051a39Sopenharmony_ci#include <limits.h>
12e1051a39Sopenharmony_ci#include <openssl/cms.h>
13e1051a39Sopenharmony_ci#include <openssl/err.h>
14e1051a39Sopenharmony_ci#include <openssl/decoder.h>
15e1051a39Sopenharmony_ci#include "internal/sizes.h"
16e1051a39Sopenharmony_ci#include "crypto/evp.h"
17e1051a39Sopenharmony_ci#include "cms_local.h"
18e1051a39Sopenharmony_ci
19e1051a39Sopenharmony_cistatic EVP_PKEY *pkey_type2param(int ptype, const void *pval,
20e1051a39Sopenharmony_ci                                 OSSL_LIB_CTX *libctx, const char *propq)
21e1051a39Sopenharmony_ci{
22e1051a39Sopenharmony_ci    EVP_PKEY *pkey = NULL;
23e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pctx = NULL;
24e1051a39Sopenharmony_ci    OSSL_DECODER_CTX *ctx = NULL;
25e1051a39Sopenharmony_ci
26e1051a39Sopenharmony_ci    if (ptype == V_ASN1_SEQUENCE) {
27e1051a39Sopenharmony_ci        const ASN1_STRING *pstr = pval;
28e1051a39Sopenharmony_ci        const unsigned char *pm = pstr->data;
29e1051a39Sopenharmony_ci        size_t pmlen = (size_t)pstr->length;
30e1051a39Sopenharmony_ci        int selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS;
31e1051a39Sopenharmony_ci
32e1051a39Sopenharmony_ci        ctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, "EC",
33e1051a39Sopenharmony_ci                                            selection, libctx, propq);
34e1051a39Sopenharmony_ci        if (ctx == NULL)
35e1051a39Sopenharmony_ci            goto err;
36e1051a39Sopenharmony_ci
37e1051a39Sopenharmony_ci        if (!OSSL_DECODER_from_data(ctx, &pm, &pmlen)) {
38e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_DECODE_ERROR);
39e1051a39Sopenharmony_ci            goto err;
40e1051a39Sopenharmony_ci        }
41e1051a39Sopenharmony_ci        OSSL_DECODER_CTX_free(ctx);
42e1051a39Sopenharmony_ci        return pkey;
43e1051a39Sopenharmony_ci    } else if (ptype == V_ASN1_OBJECT) {
44e1051a39Sopenharmony_ci        const ASN1_OBJECT *poid = pval;
45e1051a39Sopenharmony_ci        char groupname[OSSL_MAX_NAME_SIZE];
46e1051a39Sopenharmony_ci
47e1051a39Sopenharmony_ci        /* type == V_ASN1_OBJECT => the parameters are given by an asn1 OID */
48e1051a39Sopenharmony_ci        pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
49e1051a39Sopenharmony_ci        if (pctx == NULL || EVP_PKEY_paramgen_init(pctx) <= 0)
50e1051a39Sopenharmony_ci            goto err;
51e1051a39Sopenharmony_ci        if (OBJ_obj2txt(groupname, sizeof(groupname), poid, 0) <= 0
52e1051a39Sopenharmony_ci                || EVP_PKEY_CTX_set_group_name(pctx, groupname) <= 0) {
53e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_DECODE_ERROR);
54e1051a39Sopenharmony_ci            goto err;
55e1051a39Sopenharmony_ci        }
56e1051a39Sopenharmony_ci        if (EVP_PKEY_paramgen(pctx, &pkey) <= 0)
57e1051a39Sopenharmony_ci            goto err;
58e1051a39Sopenharmony_ci        EVP_PKEY_CTX_free(pctx);
59e1051a39Sopenharmony_ci        return pkey;
60e1051a39Sopenharmony_ci    }
61e1051a39Sopenharmony_ci
62e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_CMS, CMS_R_DECODE_ERROR);
63e1051a39Sopenharmony_ci    return NULL;
64e1051a39Sopenharmony_ci
65e1051a39Sopenharmony_ci err:
66e1051a39Sopenharmony_ci    EVP_PKEY_free(pkey);
67e1051a39Sopenharmony_ci    EVP_PKEY_CTX_free(pctx);
68e1051a39Sopenharmony_ci    OSSL_DECODER_CTX_free(ctx);
69e1051a39Sopenharmony_ci    return NULL;
70e1051a39Sopenharmony_ci}
71e1051a39Sopenharmony_ci
72e1051a39Sopenharmony_cistatic int ecdh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
73e1051a39Sopenharmony_ci                                X509_ALGOR *alg, ASN1_BIT_STRING *pubkey)
74e1051a39Sopenharmony_ci{
75e1051a39Sopenharmony_ci    const ASN1_OBJECT *aoid;
76e1051a39Sopenharmony_ci    int atype;
77e1051a39Sopenharmony_ci    const void *aval;
78e1051a39Sopenharmony_ci    int rv = 0;
79e1051a39Sopenharmony_ci    EVP_PKEY *pkpeer = NULL;
80e1051a39Sopenharmony_ci    const unsigned char *p;
81e1051a39Sopenharmony_ci    int plen;
82e1051a39Sopenharmony_ci
83e1051a39Sopenharmony_ci    X509_ALGOR_get0(&aoid, &atype, &aval, alg);
84e1051a39Sopenharmony_ci    if (OBJ_obj2nid(aoid) != NID_X9_62_id_ecPublicKey)
85e1051a39Sopenharmony_ci        goto err;
86e1051a39Sopenharmony_ci
87e1051a39Sopenharmony_ci    /* If absent parameters get group from main key */
88e1051a39Sopenharmony_ci    if (atype == V_ASN1_UNDEF || atype == V_ASN1_NULL) {
89e1051a39Sopenharmony_ci        EVP_PKEY *pk;
90e1051a39Sopenharmony_ci
91e1051a39Sopenharmony_ci        pk = EVP_PKEY_CTX_get0_pkey(pctx);
92e1051a39Sopenharmony_ci        if (pk == NULL)
93e1051a39Sopenharmony_ci            goto err;
94e1051a39Sopenharmony_ci
95e1051a39Sopenharmony_ci        pkpeer = EVP_PKEY_new();
96e1051a39Sopenharmony_ci        if (pkpeer == NULL)
97e1051a39Sopenharmony_ci            goto err;
98e1051a39Sopenharmony_ci        if (!EVP_PKEY_copy_parameters(pkpeer, pk))
99e1051a39Sopenharmony_ci            goto err;
100e1051a39Sopenharmony_ci    } else {
101e1051a39Sopenharmony_ci        pkpeer = pkey_type2param(atype, aval,
102e1051a39Sopenharmony_ci                                 EVP_PKEY_CTX_get0_libctx(pctx),
103e1051a39Sopenharmony_ci                                 EVP_PKEY_CTX_get0_propq(pctx));
104e1051a39Sopenharmony_ci        if (pkpeer == NULL)
105e1051a39Sopenharmony_ci            goto err;
106e1051a39Sopenharmony_ci    }
107e1051a39Sopenharmony_ci    /* We have parameters now set public key */
108e1051a39Sopenharmony_ci    plen = ASN1_STRING_length(pubkey);
109e1051a39Sopenharmony_ci    p = ASN1_STRING_get0_data(pubkey);
110e1051a39Sopenharmony_ci    if (p == NULL || plen == 0)
111e1051a39Sopenharmony_ci        goto err;
112e1051a39Sopenharmony_ci
113e1051a39Sopenharmony_ci    if (!EVP_PKEY_set1_encoded_public_key(pkpeer, p, plen))
114e1051a39Sopenharmony_ci        goto err;
115e1051a39Sopenharmony_ci
116e1051a39Sopenharmony_ci    if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
117e1051a39Sopenharmony_ci        rv = 1;
118e1051a39Sopenharmony_ci err:
119e1051a39Sopenharmony_ci    EVP_PKEY_free(pkpeer);
120e1051a39Sopenharmony_ci    return rv;
121e1051a39Sopenharmony_ci}
122e1051a39Sopenharmony_ci
123e1051a39Sopenharmony_ci/* Set KDF parameters based on KDF NID */
124e1051a39Sopenharmony_cistatic int ecdh_cms_set_kdf_param(EVP_PKEY_CTX *pctx, int eckdf_nid)
125e1051a39Sopenharmony_ci{
126e1051a39Sopenharmony_ci    int kdf_nid, kdfmd_nid, cofactor;
127e1051a39Sopenharmony_ci    const EVP_MD *kdf_md;
128e1051a39Sopenharmony_ci
129e1051a39Sopenharmony_ci    if (eckdf_nid == NID_undef)
130e1051a39Sopenharmony_ci        return 0;
131e1051a39Sopenharmony_ci
132e1051a39Sopenharmony_ci    /* Lookup KDF type, cofactor mode and digest */
133e1051a39Sopenharmony_ci    if (!OBJ_find_sigid_algs(eckdf_nid, &kdfmd_nid, &kdf_nid))
134e1051a39Sopenharmony_ci        return 0;
135e1051a39Sopenharmony_ci
136e1051a39Sopenharmony_ci    if (kdf_nid == NID_dh_std_kdf)
137e1051a39Sopenharmony_ci        cofactor = 0;
138e1051a39Sopenharmony_ci    else if (kdf_nid == NID_dh_cofactor_kdf)
139e1051a39Sopenharmony_ci        cofactor = 1;
140e1051a39Sopenharmony_ci    else
141e1051a39Sopenharmony_ci        return 0;
142e1051a39Sopenharmony_ci
143e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_set_ecdh_cofactor_mode(pctx, cofactor) <= 0)
144e1051a39Sopenharmony_ci        return 0;
145e1051a39Sopenharmony_ci
146e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, EVP_PKEY_ECDH_KDF_X9_63) <= 0)
147e1051a39Sopenharmony_ci        return 0;
148e1051a39Sopenharmony_ci
149e1051a39Sopenharmony_ci    kdf_md = EVP_get_digestbynid(kdfmd_nid);
150e1051a39Sopenharmony_ci    if (!kdf_md)
151e1051a39Sopenharmony_ci        return 0;
152e1051a39Sopenharmony_ci
153e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0)
154e1051a39Sopenharmony_ci        return 0;
155e1051a39Sopenharmony_ci    return 1;
156e1051a39Sopenharmony_ci}
157e1051a39Sopenharmony_ci
158e1051a39Sopenharmony_cistatic int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
159e1051a39Sopenharmony_ci{
160e1051a39Sopenharmony_ci    int rv = 0;
161e1051a39Sopenharmony_ci    X509_ALGOR *alg, *kekalg = NULL;
162e1051a39Sopenharmony_ci    ASN1_OCTET_STRING *ukm;
163e1051a39Sopenharmony_ci    const unsigned char *p;
164e1051a39Sopenharmony_ci    unsigned char *der = NULL;
165e1051a39Sopenharmony_ci    int plen, keylen;
166e1051a39Sopenharmony_ci    EVP_CIPHER *kekcipher = NULL;
167e1051a39Sopenharmony_ci    EVP_CIPHER_CTX *kekctx;
168e1051a39Sopenharmony_ci    char name[OSSL_MAX_NAME_SIZE];
169e1051a39Sopenharmony_ci
170e1051a39Sopenharmony_ci    if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
171e1051a39Sopenharmony_ci        return 0;
172e1051a39Sopenharmony_ci
173e1051a39Sopenharmony_ci    if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(alg->algorithm))) {
174e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR);
175e1051a39Sopenharmony_ci        return 0;
176e1051a39Sopenharmony_ci    }
177e1051a39Sopenharmony_ci
178e1051a39Sopenharmony_ci    if (alg->parameter->type != V_ASN1_SEQUENCE)
179e1051a39Sopenharmony_ci        return 0;
180e1051a39Sopenharmony_ci
181e1051a39Sopenharmony_ci    p = alg->parameter->value.sequence->data;
182e1051a39Sopenharmony_ci    plen = alg->parameter->value.sequence->length;
183e1051a39Sopenharmony_ci    kekalg = d2i_X509_ALGOR(NULL, &p, plen);
184e1051a39Sopenharmony_ci    if (kekalg == NULL)
185e1051a39Sopenharmony_ci        goto err;
186e1051a39Sopenharmony_ci    kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
187e1051a39Sopenharmony_ci    if (kekctx == NULL)
188e1051a39Sopenharmony_ci        goto err;
189e1051a39Sopenharmony_ci    OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0);
190e1051a39Sopenharmony_ci    kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery);
191e1051a39Sopenharmony_ci    if (kekcipher == NULL || EVP_CIPHER_get_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
192e1051a39Sopenharmony_ci        goto err;
193e1051a39Sopenharmony_ci    if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL))
194e1051a39Sopenharmony_ci        goto err;
195e1051a39Sopenharmony_ci    if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0)
196e1051a39Sopenharmony_ci        goto err;
197e1051a39Sopenharmony_ci
198e1051a39Sopenharmony_ci    keylen = EVP_CIPHER_CTX_get_key_length(kekctx);
199e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0)
200e1051a39Sopenharmony_ci        goto err;
201e1051a39Sopenharmony_ci
202e1051a39Sopenharmony_ci    plen = CMS_SharedInfo_encode(&der, kekalg, ukm, keylen);
203e1051a39Sopenharmony_ci
204e1051a39Sopenharmony_ci    if (plen <= 0)
205e1051a39Sopenharmony_ci        goto err;
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, der, plen) <= 0)
208e1051a39Sopenharmony_ci        goto err;
209e1051a39Sopenharmony_ci    der = NULL;
210e1051a39Sopenharmony_ci
211e1051a39Sopenharmony_ci    rv = 1;
212e1051a39Sopenharmony_ci err:
213e1051a39Sopenharmony_ci    EVP_CIPHER_free(kekcipher);
214e1051a39Sopenharmony_ci    X509_ALGOR_free(kekalg);
215e1051a39Sopenharmony_ci    OPENSSL_free(der);
216e1051a39Sopenharmony_ci    return rv;
217e1051a39Sopenharmony_ci}
218e1051a39Sopenharmony_ci
219e1051a39Sopenharmony_cistatic int ecdh_cms_decrypt(CMS_RecipientInfo *ri)
220e1051a39Sopenharmony_ci{
221e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pctx;
222e1051a39Sopenharmony_ci
223e1051a39Sopenharmony_ci    pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
224e1051a39Sopenharmony_ci    if (pctx == NULL)
225e1051a39Sopenharmony_ci        return 0;
226e1051a39Sopenharmony_ci    /* See if we need to set peer key */
227e1051a39Sopenharmony_ci    if (!EVP_PKEY_CTX_get0_peerkey(pctx)) {
228e1051a39Sopenharmony_ci        X509_ALGOR *alg;
229e1051a39Sopenharmony_ci        ASN1_BIT_STRING *pubkey;
230e1051a39Sopenharmony_ci
231e1051a39Sopenharmony_ci        if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey,
232e1051a39Sopenharmony_ci                                                 NULL, NULL, NULL))
233e1051a39Sopenharmony_ci            return 0;
234e1051a39Sopenharmony_ci        if (alg == NULL || pubkey == NULL)
235e1051a39Sopenharmony_ci            return 0;
236e1051a39Sopenharmony_ci        if (!ecdh_cms_set_peerkey(pctx, alg, pubkey)) {
237e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_PEER_KEY_ERROR);
238e1051a39Sopenharmony_ci            return 0;
239e1051a39Sopenharmony_ci        }
240e1051a39Sopenharmony_ci    }
241e1051a39Sopenharmony_ci    /* Set ECDH derivation parameters and initialise unwrap context */
242e1051a39Sopenharmony_ci    if (!ecdh_cms_set_shared_info(pctx, ri)) {
243e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_SHARED_INFO_ERROR);
244e1051a39Sopenharmony_ci        return 0;
245e1051a39Sopenharmony_ci    }
246e1051a39Sopenharmony_ci    return 1;
247e1051a39Sopenharmony_ci}
248e1051a39Sopenharmony_ci
249e1051a39Sopenharmony_cistatic int ecdh_cms_encrypt(CMS_RecipientInfo *ri)
250e1051a39Sopenharmony_ci{
251e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pctx;
252e1051a39Sopenharmony_ci    EVP_PKEY *pkey;
253e1051a39Sopenharmony_ci    EVP_CIPHER_CTX *ctx;
254e1051a39Sopenharmony_ci    int keylen;
255e1051a39Sopenharmony_ci    X509_ALGOR *talg, *wrap_alg = NULL;
256e1051a39Sopenharmony_ci    const ASN1_OBJECT *aoid;
257e1051a39Sopenharmony_ci    ASN1_BIT_STRING *pubkey;
258e1051a39Sopenharmony_ci    ASN1_STRING *wrap_str;
259e1051a39Sopenharmony_ci    ASN1_OCTET_STRING *ukm;
260e1051a39Sopenharmony_ci    unsigned char *penc = NULL;
261e1051a39Sopenharmony_ci    int penclen;
262e1051a39Sopenharmony_ci    int rv = 0;
263e1051a39Sopenharmony_ci    int ecdh_nid, kdf_type, kdf_nid, wrap_nid;
264e1051a39Sopenharmony_ci    const EVP_MD *kdf_md;
265e1051a39Sopenharmony_ci
266e1051a39Sopenharmony_ci    pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
267e1051a39Sopenharmony_ci    if (pctx == NULL)
268e1051a39Sopenharmony_ci        return 0;
269e1051a39Sopenharmony_ci    /* Get ephemeral key */
270e1051a39Sopenharmony_ci    pkey = EVP_PKEY_CTX_get0_pkey(pctx);
271e1051a39Sopenharmony_ci    if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey,
272e1051a39Sopenharmony_ci                                             NULL, NULL, NULL))
273e1051a39Sopenharmony_ci        goto err;
274e1051a39Sopenharmony_ci    X509_ALGOR_get0(&aoid, NULL, NULL, talg);
275e1051a39Sopenharmony_ci    /* Is everything uninitialised? */
276e1051a39Sopenharmony_ci    if (aoid == OBJ_nid2obj(NID_undef)) {
277e1051a39Sopenharmony_ci        /* Set the key */
278e1051a39Sopenharmony_ci        size_t enckeylen;
279e1051a39Sopenharmony_ci
280e1051a39Sopenharmony_ci        enckeylen = EVP_PKEY_get1_encoded_public_key(pkey, &penc);
281e1051a39Sopenharmony_ci        if (enckeylen > INT_MAX || enckeylen == 0)
282e1051a39Sopenharmony_ci            goto err;
283e1051a39Sopenharmony_ci        ASN1_STRING_set0(pubkey, penc, (int)enckeylen);
284e1051a39Sopenharmony_ci        pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
285e1051a39Sopenharmony_ci        pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
286e1051a39Sopenharmony_ci
287e1051a39Sopenharmony_ci        penc = NULL;
288e1051a39Sopenharmony_ci        (void)X509_ALGOR_set0(talg, OBJ_nid2obj(NID_X9_62_id_ecPublicKey),
289e1051a39Sopenharmony_ci                              V_ASN1_UNDEF, NULL); /* cannot fail */
290e1051a39Sopenharmony_ci    }
291e1051a39Sopenharmony_ci
292e1051a39Sopenharmony_ci    /* See if custom parameters set */
293e1051a39Sopenharmony_ci    kdf_type = EVP_PKEY_CTX_get_ecdh_kdf_type(pctx);
294e1051a39Sopenharmony_ci    if (kdf_type <= 0)
295e1051a39Sopenharmony_ci        goto err;
296e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_get_ecdh_kdf_md(pctx, &kdf_md) <= 0)
297e1051a39Sopenharmony_ci        goto err;
298e1051a39Sopenharmony_ci    ecdh_nid = EVP_PKEY_CTX_get_ecdh_cofactor_mode(pctx);
299e1051a39Sopenharmony_ci    if (ecdh_nid < 0)
300e1051a39Sopenharmony_ci        goto err;
301e1051a39Sopenharmony_ci    else if (ecdh_nid == 0)
302e1051a39Sopenharmony_ci        ecdh_nid = NID_dh_std_kdf;
303e1051a39Sopenharmony_ci    else if (ecdh_nid == 1)
304e1051a39Sopenharmony_ci        ecdh_nid = NID_dh_cofactor_kdf;
305e1051a39Sopenharmony_ci
306e1051a39Sopenharmony_ci    if (kdf_type == EVP_PKEY_ECDH_KDF_NONE) {
307e1051a39Sopenharmony_ci        kdf_type = EVP_PKEY_ECDH_KDF_X9_63;
308e1051a39Sopenharmony_ci        if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, kdf_type) <= 0)
309e1051a39Sopenharmony_ci            goto err;
310e1051a39Sopenharmony_ci    } else
311e1051a39Sopenharmony_ci        /* Unknown KDF */
312e1051a39Sopenharmony_ci        goto err;
313e1051a39Sopenharmony_ci    if (kdf_md == NULL) {
314e1051a39Sopenharmony_ci        /* Fixme later for better MD */
315e1051a39Sopenharmony_ci        kdf_md = EVP_sha1();
316e1051a39Sopenharmony_ci        if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0)
317e1051a39Sopenharmony_ci            goto err;
318e1051a39Sopenharmony_ci    }
319e1051a39Sopenharmony_ci
320e1051a39Sopenharmony_ci    if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm))
321e1051a39Sopenharmony_ci        goto err;
322e1051a39Sopenharmony_ci
323e1051a39Sopenharmony_ci    /* Lookup NID for KDF+cofactor+digest */
324e1051a39Sopenharmony_ci
325e1051a39Sopenharmony_ci    if (!OBJ_find_sigid_by_algs(&kdf_nid, EVP_MD_get_type(kdf_md), ecdh_nid))
326e1051a39Sopenharmony_ci        goto err;
327e1051a39Sopenharmony_ci    /* Get wrap NID */
328e1051a39Sopenharmony_ci    ctx = CMS_RecipientInfo_kari_get0_ctx(ri);
329e1051a39Sopenharmony_ci    wrap_nid = EVP_CIPHER_CTX_get_type(ctx);
330e1051a39Sopenharmony_ci    keylen = EVP_CIPHER_CTX_get_key_length(ctx);
331e1051a39Sopenharmony_ci
332e1051a39Sopenharmony_ci    /* Package wrap algorithm in an AlgorithmIdentifier */
333e1051a39Sopenharmony_ci
334e1051a39Sopenharmony_ci    wrap_alg = X509_ALGOR_new();
335e1051a39Sopenharmony_ci    if (wrap_alg == NULL)
336e1051a39Sopenharmony_ci        goto err;
337e1051a39Sopenharmony_ci    wrap_alg->algorithm = OBJ_nid2obj(wrap_nid);
338e1051a39Sopenharmony_ci    wrap_alg->parameter = ASN1_TYPE_new();
339e1051a39Sopenharmony_ci    if (wrap_alg->parameter == NULL)
340e1051a39Sopenharmony_ci        goto err;
341e1051a39Sopenharmony_ci    if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0)
342e1051a39Sopenharmony_ci        goto err;
343e1051a39Sopenharmony_ci    if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) {
344e1051a39Sopenharmony_ci        ASN1_TYPE_free(wrap_alg->parameter);
345e1051a39Sopenharmony_ci        wrap_alg->parameter = NULL;
346e1051a39Sopenharmony_ci    }
347e1051a39Sopenharmony_ci
348e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0)
349e1051a39Sopenharmony_ci        goto err;
350e1051a39Sopenharmony_ci
351e1051a39Sopenharmony_ci    penclen = CMS_SharedInfo_encode(&penc, wrap_alg, ukm, keylen);
352e1051a39Sopenharmony_ci
353e1051a39Sopenharmony_ci    if (penclen <= 0)
354e1051a39Sopenharmony_ci        goto err;
355e1051a39Sopenharmony_ci
356e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, penc, penclen) <= 0)
357e1051a39Sopenharmony_ci        goto err;
358e1051a39Sopenharmony_ci    penc = NULL;
359e1051a39Sopenharmony_ci
360e1051a39Sopenharmony_ci    /*
361e1051a39Sopenharmony_ci     * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter
362e1051a39Sopenharmony_ci     * of another AlgorithmIdentifier.
363e1051a39Sopenharmony_ci     */
364e1051a39Sopenharmony_ci    penclen = i2d_X509_ALGOR(wrap_alg, &penc);
365e1051a39Sopenharmony_ci    if (penclen <= 0)
366e1051a39Sopenharmony_ci        goto err;
367e1051a39Sopenharmony_ci    wrap_str = ASN1_STRING_new();
368e1051a39Sopenharmony_ci    if (wrap_str == NULL)
369e1051a39Sopenharmony_ci        goto err;
370e1051a39Sopenharmony_ci    ASN1_STRING_set0(wrap_str, penc, penclen);
371e1051a39Sopenharmony_ci    penc = NULL;
372e1051a39Sopenharmony_ci    X509_ALGOR_set0(talg, OBJ_nid2obj(kdf_nid), V_ASN1_SEQUENCE, wrap_str);
373e1051a39Sopenharmony_ci
374e1051a39Sopenharmony_ci    rv = 1;
375e1051a39Sopenharmony_ci
376e1051a39Sopenharmony_ci err:
377e1051a39Sopenharmony_ci    OPENSSL_free(penc);
378e1051a39Sopenharmony_ci    X509_ALGOR_free(wrap_alg);
379e1051a39Sopenharmony_ci    return rv;
380e1051a39Sopenharmony_ci}
381e1051a39Sopenharmony_ci
382e1051a39Sopenharmony_ciint ossl_cms_ecdh_envelope(CMS_RecipientInfo *ri, int decrypt)
383e1051a39Sopenharmony_ci{
384e1051a39Sopenharmony_ci    assert(decrypt == 0 || decrypt == 1);
385e1051a39Sopenharmony_ci
386e1051a39Sopenharmony_ci    if (decrypt == 1)
387e1051a39Sopenharmony_ci        return ecdh_cms_decrypt(ri);
388e1051a39Sopenharmony_ci
389e1051a39Sopenharmony_ci    if (decrypt == 0)
390e1051a39Sopenharmony_ci        return ecdh_cms_encrypt(ri);
391e1051a39Sopenharmony_ci
392e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
393e1051a39Sopenharmony_ci    return 0;
394e1051a39Sopenharmony_ci}
395e1051a39Sopenharmony_ci
396e1051a39Sopenharmony_ci/* ECDSA and DSA implementation is the same */
397e1051a39Sopenharmony_ciint ossl_cms_ecdsa_dsa_sign(CMS_SignerInfo *si, int verify)
398e1051a39Sopenharmony_ci{
399e1051a39Sopenharmony_ci    assert(verify == 0 || verify == 1);
400e1051a39Sopenharmony_ci
401e1051a39Sopenharmony_ci    if (verify == 0) {
402e1051a39Sopenharmony_ci        int snid, hnid;
403e1051a39Sopenharmony_ci        X509_ALGOR *alg1, *alg2;
404e1051a39Sopenharmony_ci        EVP_PKEY *pkey = si->pkey;
405e1051a39Sopenharmony_ci
406e1051a39Sopenharmony_ci        CMS_SignerInfo_get0_algs(si, NULL, NULL, &alg1, &alg2);
407e1051a39Sopenharmony_ci        if (alg1 == NULL || alg1->algorithm == NULL)
408e1051a39Sopenharmony_ci            return -1;
409e1051a39Sopenharmony_ci        hnid = OBJ_obj2nid(alg1->algorithm);
410e1051a39Sopenharmony_ci        if (hnid == NID_undef)
411e1051a39Sopenharmony_ci            return -1;
412e1051a39Sopenharmony_ci        if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_get_id(pkey)))
413e1051a39Sopenharmony_ci            return -1;
414e1051a39Sopenharmony_ci        X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
415e1051a39Sopenharmony_ci    }
416e1051a39Sopenharmony_ci    return 1;
417e1051a39Sopenharmony_ci}
418