1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2006-2021 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/*
11e1051a39Sopenharmony_ci * ECDH and ECDSA low level APIs are deprecated for public use, but still ok
12e1051a39Sopenharmony_ci * for internal use.
13e1051a39Sopenharmony_ci */
14e1051a39Sopenharmony_ci#include "internal/deprecated.h"
15e1051a39Sopenharmony_ci
16e1051a39Sopenharmony_ci#include <stdio.h>
17e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
18e1051a39Sopenharmony_ci#include <openssl/asn1t.h>
19e1051a39Sopenharmony_ci#include <openssl/x509.h>
20e1051a39Sopenharmony_ci#include <openssl/ec.h>
21e1051a39Sopenharmony_ci#include "ec_local.h"
22e1051a39Sopenharmony_ci#include <openssl/evp.h>
23e1051a39Sopenharmony_ci#include "crypto/evp.h"
24e1051a39Sopenharmony_ci
25e1051a39Sopenharmony_ci/* EC pkey context structure */
26e1051a39Sopenharmony_ci
27e1051a39Sopenharmony_citypedef struct {
28e1051a39Sopenharmony_ci    /* Key and paramgen group */
29e1051a39Sopenharmony_ci    EC_GROUP *gen_group;
30e1051a39Sopenharmony_ci    /* message digest */
31e1051a39Sopenharmony_ci    const EVP_MD *md;
32e1051a39Sopenharmony_ci    /* Duplicate key if custom cofactor needed */
33e1051a39Sopenharmony_ci    EC_KEY *co_key;
34e1051a39Sopenharmony_ci    /* Cofactor mode */
35e1051a39Sopenharmony_ci    signed char cofactor_mode;
36e1051a39Sopenharmony_ci    /* KDF (if any) to use for ECDH */
37e1051a39Sopenharmony_ci    char kdf_type;
38e1051a39Sopenharmony_ci    /* Message digest to use for key derivation */
39e1051a39Sopenharmony_ci    const EVP_MD *kdf_md;
40e1051a39Sopenharmony_ci    /* User key material */
41e1051a39Sopenharmony_ci    unsigned char *kdf_ukm;
42e1051a39Sopenharmony_ci    size_t kdf_ukmlen;
43e1051a39Sopenharmony_ci    /* KDF output length */
44e1051a39Sopenharmony_ci    size_t kdf_outlen;
45e1051a39Sopenharmony_ci} EC_PKEY_CTX;
46e1051a39Sopenharmony_ci
47e1051a39Sopenharmony_cistatic int pkey_ec_init(EVP_PKEY_CTX *ctx)
48e1051a39Sopenharmony_ci{
49e1051a39Sopenharmony_ci    EC_PKEY_CTX *dctx;
50e1051a39Sopenharmony_ci
51e1051a39Sopenharmony_ci    if ((dctx = OPENSSL_zalloc(sizeof(*dctx))) == NULL) {
52e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
53e1051a39Sopenharmony_ci        return 0;
54e1051a39Sopenharmony_ci    }
55e1051a39Sopenharmony_ci
56e1051a39Sopenharmony_ci    dctx->cofactor_mode = -1;
57e1051a39Sopenharmony_ci    dctx->kdf_type = EVP_PKEY_ECDH_KDF_NONE;
58e1051a39Sopenharmony_ci    ctx->data = dctx;
59e1051a39Sopenharmony_ci    return 1;
60e1051a39Sopenharmony_ci}
61e1051a39Sopenharmony_ci
62e1051a39Sopenharmony_cistatic int pkey_ec_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
63e1051a39Sopenharmony_ci{
64e1051a39Sopenharmony_ci    EC_PKEY_CTX *dctx, *sctx;
65e1051a39Sopenharmony_ci    if (!pkey_ec_init(dst))
66e1051a39Sopenharmony_ci        return 0;
67e1051a39Sopenharmony_ci    sctx = src->data;
68e1051a39Sopenharmony_ci    dctx = dst->data;
69e1051a39Sopenharmony_ci    if (sctx->gen_group) {
70e1051a39Sopenharmony_ci        dctx->gen_group = EC_GROUP_dup(sctx->gen_group);
71e1051a39Sopenharmony_ci        if (!dctx->gen_group)
72e1051a39Sopenharmony_ci            return 0;
73e1051a39Sopenharmony_ci    }
74e1051a39Sopenharmony_ci    dctx->md = sctx->md;
75e1051a39Sopenharmony_ci
76e1051a39Sopenharmony_ci    if (sctx->co_key) {
77e1051a39Sopenharmony_ci        dctx->co_key = EC_KEY_dup(sctx->co_key);
78e1051a39Sopenharmony_ci        if (!dctx->co_key)
79e1051a39Sopenharmony_ci            return 0;
80e1051a39Sopenharmony_ci    }
81e1051a39Sopenharmony_ci    dctx->kdf_type = sctx->kdf_type;
82e1051a39Sopenharmony_ci    dctx->kdf_md = sctx->kdf_md;
83e1051a39Sopenharmony_ci    dctx->kdf_outlen = sctx->kdf_outlen;
84e1051a39Sopenharmony_ci    if (sctx->kdf_ukm) {
85e1051a39Sopenharmony_ci        dctx->kdf_ukm = OPENSSL_memdup(sctx->kdf_ukm, sctx->kdf_ukmlen);
86e1051a39Sopenharmony_ci        if (!dctx->kdf_ukm)
87e1051a39Sopenharmony_ci            return 0;
88e1051a39Sopenharmony_ci    } else
89e1051a39Sopenharmony_ci        dctx->kdf_ukm = NULL;
90e1051a39Sopenharmony_ci    dctx->kdf_ukmlen = sctx->kdf_ukmlen;
91e1051a39Sopenharmony_ci    return 1;
92e1051a39Sopenharmony_ci}
93e1051a39Sopenharmony_ci
94e1051a39Sopenharmony_cistatic void pkey_ec_cleanup(EVP_PKEY_CTX *ctx)
95e1051a39Sopenharmony_ci{
96e1051a39Sopenharmony_ci    EC_PKEY_CTX *dctx = ctx->data;
97e1051a39Sopenharmony_ci    if (dctx != NULL) {
98e1051a39Sopenharmony_ci        EC_GROUP_free(dctx->gen_group);
99e1051a39Sopenharmony_ci        EC_KEY_free(dctx->co_key);
100e1051a39Sopenharmony_ci        OPENSSL_free(dctx->kdf_ukm);
101e1051a39Sopenharmony_ci        OPENSSL_free(dctx);
102e1051a39Sopenharmony_ci        ctx->data = NULL;
103e1051a39Sopenharmony_ci    }
104e1051a39Sopenharmony_ci}
105e1051a39Sopenharmony_ci
106e1051a39Sopenharmony_cistatic int pkey_ec_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
107e1051a39Sopenharmony_ci                        const unsigned char *tbs, size_t tbslen)
108e1051a39Sopenharmony_ci{
109e1051a39Sopenharmony_ci    int ret, type;
110e1051a39Sopenharmony_ci    unsigned int sltmp;
111e1051a39Sopenharmony_ci    EC_PKEY_CTX *dctx = ctx->data;
112e1051a39Sopenharmony_ci    /*
113e1051a39Sopenharmony_ci     * Discard const. Its marked as const because this may be a cached copy of
114e1051a39Sopenharmony_ci     * the "real" key. These calls don't make any modifications that need to
115e1051a39Sopenharmony_ci     * be reflected back in the "original" key.
116e1051a39Sopenharmony_ci     */
117e1051a39Sopenharmony_ci    EC_KEY *ec = (EC_KEY *)EVP_PKEY_get0_EC_KEY(ctx->pkey);
118e1051a39Sopenharmony_ci    const int sig_sz = ECDSA_size(ec);
119e1051a39Sopenharmony_ci
120e1051a39Sopenharmony_ci    /* ensure cast to size_t is safe */
121e1051a39Sopenharmony_ci    if (!ossl_assert(sig_sz > 0))
122e1051a39Sopenharmony_ci        return 0;
123e1051a39Sopenharmony_ci
124e1051a39Sopenharmony_ci    if (sig == NULL) {
125e1051a39Sopenharmony_ci        *siglen = (size_t)sig_sz;
126e1051a39Sopenharmony_ci        return 1;
127e1051a39Sopenharmony_ci    }
128e1051a39Sopenharmony_ci
129e1051a39Sopenharmony_ci    if (*siglen < (size_t)sig_sz) {
130e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_BUFFER_TOO_SMALL);
131e1051a39Sopenharmony_ci        return 0;
132e1051a39Sopenharmony_ci    }
133e1051a39Sopenharmony_ci
134e1051a39Sopenharmony_ci    type = (dctx->md != NULL) ? EVP_MD_get_type(dctx->md) : NID_sha1;
135e1051a39Sopenharmony_ci
136e1051a39Sopenharmony_ci    ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec);
137e1051a39Sopenharmony_ci
138e1051a39Sopenharmony_ci    if (ret <= 0)
139e1051a39Sopenharmony_ci        return ret;
140e1051a39Sopenharmony_ci    *siglen = (size_t)sltmp;
141e1051a39Sopenharmony_ci    return 1;
142e1051a39Sopenharmony_ci}
143e1051a39Sopenharmony_ci
144e1051a39Sopenharmony_cistatic int pkey_ec_verify(EVP_PKEY_CTX *ctx,
145e1051a39Sopenharmony_ci                          const unsigned char *sig, size_t siglen,
146e1051a39Sopenharmony_ci                          const unsigned char *tbs, size_t tbslen)
147e1051a39Sopenharmony_ci{
148e1051a39Sopenharmony_ci    int ret, type;
149e1051a39Sopenharmony_ci    EC_PKEY_CTX *dctx = ctx->data;
150e1051a39Sopenharmony_ci    /*
151e1051a39Sopenharmony_ci     * Discard const. Its marked as const because this may be a cached copy of
152e1051a39Sopenharmony_ci     * the "real" key. These calls don't make any modifications that need to
153e1051a39Sopenharmony_ci     * be reflected back in the "original" key.
154e1051a39Sopenharmony_ci     */
155e1051a39Sopenharmony_ci    EC_KEY *ec = (EC_KEY *)EVP_PKEY_get0_EC_KEY(ctx->pkey);
156e1051a39Sopenharmony_ci
157e1051a39Sopenharmony_ci    if (dctx->md)
158e1051a39Sopenharmony_ci        type = EVP_MD_get_type(dctx->md);
159e1051a39Sopenharmony_ci    else
160e1051a39Sopenharmony_ci        type = NID_sha1;
161e1051a39Sopenharmony_ci
162e1051a39Sopenharmony_ci    ret = ECDSA_verify(type, tbs, tbslen, sig, siglen, ec);
163e1051a39Sopenharmony_ci
164e1051a39Sopenharmony_ci    return ret;
165e1051a39Sopenharmony_ci}
166e1051a39Sopenharmony_ci
167e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_EC
168e1051a39Sopenharmony_cistatic int pkey_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
169e1051a39Sopenharmony_ci{
170e1051a39Sopenharmony_ci    int ret;
171e1051a39Sopenharmony_ci    size_t outlen;
172e1051a39Sopenharmony_ci    const EC_POINT *pubkey = NULL;
173e1051a39Sopenharmony_ci    EC_KEY *eckey;
174e1051a39Sopenharmony_ci    const EC_KEY *eckeypub;
175e1051a39Sopenharmony_ci    EC_PKEY_CTX *dctx = ctx->data;
176e1051a39Sopenharmony_ci
177e1051a39Sopenharmony_ci    if (ctx->pkey == NULL || ctx->peerkey == NULL) {
178e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_KEYS_NOT_SET);
179e1051a39Sopenharmony_ci        return 0;
180e1051a39Sopenharmony_ci    }
181e1051a39Sopenharmony_ci    eckeypub = EVP_PKEY_get0_EC_KEY(ctx->peerkey);
182e1051a39Sopenharmony_ci    if (eckeypub == NULL) {
183e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_KEYS_NOT_SET);
184e1051a39Sopenharmony_ci        return 0;
185e1051a39Sopenharmony_ci    }
186e1051a39Sopenharmony_ci
187e1051a39Sopenharmony_ci    eckey = dctx->co_key ? dctx->co_key
188e1051a39Sopenharmony_ci                         : (EC_KEY *)EVP_PKEY_get0_EC_KEY(ctx->pkey);
189e1051a39Sopenharmony_ci
190e1051a39Sopenharmony_ci    if (!key) {
191e1051a39Sopenharmony_ci        const EC_GROUP *group;
192e1051a39Sopenharmony_ci        group = EC_KEY_get0_group(eckey);
193e1051a39Sopenharmony_ci
194e1051a39Sopenharmony_ci        if (group == NULL)
195e1051a39Sopenharmony_ci            return 0;
196e1051a39Sopenharmony_ci        *keylen = (EC_GROUP_get_degree(group) + 7) / 8;
197e1051a39Sopenharmony_ci        return 1;
198e1051a39Sopenharmony_ci    }
199e1051a39Sopenharmony_ci    pubkey = EC_KEY_get0_public_key(eckeypub);
200e1051a39Sopenharmony_ci
201e1051a39Sopenharmony_ci    /*
202e1051a39Sopenharmony_ci     * NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is not
203e1051a39Sopenharmony_ci     * an error, the result is truncated.
204e1051a39Sopenharmony_ci     */
205e1051a39Sopenharmony_ci
206e1051a39Sopenharmony_ci    outlen = *keylen;
207e1051a39Sopenharmony_ci
208e1051a39Sopenharmony_ci    ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0);
209e1051a39Sopenharmony_ci    if (ret <= 0)
210e1051a39Sopenharmony_ci        return 0;
211e1051a39Sopenharmony_ci    *keylen = ret;
212e1051a39Sopenharmony_ci    return 1;
213e1051a39Sopenharmony_ci}
214e1051a39Sopenharmony_ci
215e1051a39Sopenharmony_cistatic int pkey_ec_kdf_derive(EVP_PKEY_CTX *ctx,
216e1051a39Sopenharmony_ci                              unsigned char *key, size_t *keylen)
217e1051a39Sopenharmony_ci{
218e1051a39Sopenharmony_ci    EC_PKEY_CTX *dctx = ctx->data;
219e1051a39Sopenharmony_ci    unsigned char *ktmp = NULL;
220e1051a39Sopenharmony_ci    size_t ktmplen;
221e1051a39Sopenharmony_ci    int rv = 0;
222e1051a39Sopenharmony_ci    if (dctx->kdf_type == EVP_PKEY_ECDH_KDF_NONE)
223e1051a39Sopenharmony_ci        return pkey_ec_derive(ctx, key, keylen);
224e1051a39Sopenharmony_ci    if (!key) {
225e1051a39Sopenharmony_ci        *keylen = dctx->kdf_outlen;
226e1051a39Sopenharmony_ci        return 1;
227e1051a39Sopenharmony_ci    }
228e1051a39Sopenharmony_ci    if (*keylen != dctx->kdf_outlen)
229e1051a39Sopenharmony_ci        return 0;
230e1051a39Sopenharmony_ci    if (!pkey_ec_derive(ctx, NULL, &ktmplen))
231e1051a39Sopenharmony_ci        return 0;
232e1051a39Sopenharmony_ci    if ((ktmp = OPENSSL_malloc(ktmplen)) == NULL) {
233e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
234e1051a39Sopenharmony_ci        return 0;
235e1051a39Sopenharmony_ci    }
236e1051a39Sopenharmony_ci    if (!pkey_ec_derive(ctx, ktmp, &ktmplen))
237e1051a39Sopenharmony_ci        goto err;
238e1051a39Sopenharmony_ci    /* Do KDF stuff */
239e1051a39Sopenharmony_ci    if (!ossl_ecdh_kdf_X9_63(key, *keylen, ktmp, ktmplen,
240e1051a39Sopenharmony_ci                             dctx->kdf_ukm, dctx->kdf_ukmlen, dctx->kdf_md,
241e1051a39Sopenharmony_ci                             ctx->libctx, ctx->propquery))
242e1051a39Sopenharmony_ci        goto err;
243e1051a39Sopenharmony_ci    rv = 1;
244e1051a39Sopenharmony_ci
245e1051a39Sopenharmony_ci err:
246e1051a39Sopenharmony_ci    OPENSSL_clear_free(ktmp, ktmplen);
247e1051a39Sopenharmony_ci    return rv;
248e1051a39Sopenharmony_ci}
249e1051a39Sopenharmony_ci#endif
250e1051a39Sopenharmony_ci
251e1051a39Sopenharmony_cistatic int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
252e1051a39Sopenharmony_ci{
253e1051a39Sopenharmony_ci    EC_PKEY_CTX *dctx = ctx->data;
254e1051a39Sopenharmony_ci    EC_GROUP *group;
255e1051a39Sopenharmony_ci    switch (type) {
256e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
257e1051a39Sopenharmony_ci        group = EC_GROUP_new_by_curve_name(p1);
258e1051a39Sopenharmony_ci        if (group == NULL) {
259e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, EC_R_INVALID_CURVE);
260e1051a39Sopenharmony_ci            return 0;
261e1051a39Sopenharmony_ci        }
262e1051a39Sopenharmony_ci        EC_GROUP_free(dctx->gen_group);
263e1051a39Sopenharmony_ci        dctx->gen_group = group;
264e1051a39Sopenharmony_ci        return 1;
265e1051a39Sopenharmony_ci
266e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_EC_PARAM_ENC:
267e1051a39Sopenharmony_ci        if (!dctx->gen_group) {
268e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, EC_R_NO_PARAMETERS_SET);
269e1051a39Sopenharmony_ci            return 0;
270e1051a39Sopenharmony_ci        }
271e1051a39Sopenharmony_ci        EC_GROUP_set_asn1_flag(dctx->gen_group, p1);
272e1051a39Sopenharmony_ci        return 1;
273e1051a39Sopenharmony_ci
274e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_EC
275e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_EC_ECDH_COFACTOR:
276e1051a39Sopenharmony_ci        if (p1 == -2) {
277e1051a39Sopenharmony_ci            if (dctx->cofactor_mode != -1)
278e1051a39Sopenharmony_ci                return dctx->cofactor_mode;
279e1051a39Sopenharmony_ci            else {
280e1051a39Sopenharmony_ci                const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ctx->pkey);
281e1051a39Sopenharmony_ci                return EC_KEY_get_flags(ec_key) & EC_FLAG_COFACTOR_ECDH ? 1 : 0;
282e1051a39Sopenharmony_ci            }
283e1051a39Sopenharmony_ci        } else if (p1 < -1 || p1 > 1)
284e1051a39Sopenharmony_ci            return -2;
285e1051a39Sopenharmony_ci        dctx->cofactor_mode = p1;
286e1051a39Sopenharmony_ci        if (p1 != -1) {
287e1051a39Sopenharmony_ci            EC_KEY *ec_key = (EC_KEY *)EVP_PKEY_get0_EC_KEY(ctx->pkey);
288e1051a39Sopenharmony_ci
289e1051a39Sopenharmony_ci            /*
290e1051a39Sopenharmony_ci             * We discarded the "const" above. This will only work if the key is
291e1051a39Sopenharmony_ci             * a "real" legacy key, and not a cached copy of a provided key
292e1051a39Sopenharmony_ci             */
293e1051a39Sopenharmony_ci            if (evp_pkey_is_provided(ctx->pkey)) {
294e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_EC, ERR_R_UNSUPPORTED);
295e1051a39Sopenharmony_ci                return 0;
296e1051a39Sopenharmony_ci            }
297e1051a39Sopenharmony_ci            if (!ec_key->group)
298e1051a39Sopenharmony_ci                return -2;
299e1051a39Sopenharmony_ci            /* If cofactor is 1 cofactor mode does nothing */
300e1051a39Sopenharmony_ci            if (BN_is_one(ec_key->group->cofactor))
301e1051a39Sopenharmony_ci                return 1;
302e1051a39Sopenharmony_ci            if (!dctx->co_key) {
303e1051a39Sopenharmony_ci                dctx->co_key = EC_KEY_dup(ec_key);
304e1051a39Sopenharmony_ci                if (!dctx->co_key)
305e1051a39Sopenharmony_ci                    return 0;
306e1051a39Sopenharmony_ci            }
307e1051a39Sopenharmony_ci            if (p1)
308e1051a39Sopenharmony_ci                EC_KEY_set_flags(dctx->co_key, EC_FLAG_COFACTOR_ECDH);
309e1051a39Sopenharmony_ci            else
310e1051a39Sopenharmony_ci                EC_KEY_clear_flags(dctx->co_key, EC_FLAG_COFACTOR_ECDH);
311e1051a39Sopenharmony_ci        } else {
312e1051a39Sopenharmony_ci            EC_KEY_free(dctx->co_key);
313e1051a39Sopenharmony_ci            dctx->co_key = NULL;
314e1051a39Sopenharmony_ci        }
315e1051a39Sopenharmony_ci        return 1;
316e1051a39Sopenharmony_ci#endif
317e1051a39Sopenharmony_ci
318e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_EC_KDF_TYPE:
319e1051a39Sopenharmony_ci        if (p1 == -2)
320e1051a39Sopenharmony_ci            return dctx->kdf_type;
321e1051a39Sopenharmony_ci        if (p1 != EVP_PKEY_ECDH_KDF_NONE && p1 != EVP_PKEY_ECDH_KDF_X9_63)
322e1051a39Sopenharmony_ci            return -2;
323e1051a39Sopenharmony_ci        dctx->kdf_type = p1;
324e1051a39Sopenharmony_ci        return 1;
325e1051a39Sopenharmony_ci
326e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_EC_KDF_MD:
327e1051a39Sopenharmony_ci        dctx->kdf_md = p2;
328e1051a39Sopenharmony_ci        return 1;
329e1051a39Sopenharmony_ci
330e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_GET_EC_KDF_MD:
331e1051a39Sopenharmony_ci        *(const EVP_MD **)p2 = dctx->kdf_md;
332e1051a39Sopenharmony_ci        return 1;
333e1051a39Sopenharmony_ci
334e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_EC_KDF_OUTLEN:
335e1051a39Sopenharmony_ci        if (p1 <= 0)
336e1051a39Sopenharmony_ci            return -2;
337e1051a39Sopenharmony_ci        dctx->kdf_outlen = (size_t)p1;
338e1051a39Sopenharmony_ci        return 1;
339e1051a39Sopenharmony_ci
340e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN:
341e1051a39Sopenharmony_ci        *(int *)p2 = dctx->kdf_outlen;
342e1051a39Sopenharmony_ci        return 1;
343e1051a39Sopenharmony_ci
344e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_EC_KDF_UKM:
345e1051a39Sopenharmony_ci        OPENSSL_free(dctx->kdf_ukm);
346e1051a39Sopenharmony_ci        dctx->kdf_ukm = p2;
347e1051a39Sopenharmony_ci        if (p2)
348e1051a39Sopenharmony_ci            dctx->kdf_ukmlen = p1;
349e1051a39Sopenharmony_ci        else
350e1051a39Sopenharmony_ci            dctx->kdf_ukmlen = 0;
351e1051a39Sopenharmony_ci        return 1;
352e1051a39Sopenharmony_ci
353e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_GET_EC_KDF_UKM:
354e1051a39Sopenharmony_ci        *(unsigned char **)p2 = dctx->kdf_ukm;
355e1051a39Sopenharmony_ci        return dctx->kdf_ukmlen;
356e1051a39Sopenharmony_ci
357e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_MD:
358e1051a39Sopenharmony_ci        if (EVP_MD_get_type((const EVP_MD *)p2) != NID_sha1 &&
359e1051a39Sopenharmony_ci            EVP_MD_get_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 &&
360e1051a39Sopenharmony_ci            EVP_MD_get_type((const EVP_MD *)p2) != NID_sha224 &&
361e1051a39Sopenharmony_ci            EVP_MD_get_type((const EVP_MD *)p2) != NID_sha256 &&
362e1051a39Sopenharmony_ci            EVP_MD_get_type((const EVP_MD *)p2) != NID_sha384 &&
363e1051a39Sopenharmony_ci            EVP_MD_get_type((const EVP_MD *)p2) != NID_sha512 &&
364e1051a39Sopenharmony_ci            EVP_MD_get_type((const EVP_MD *)p2) != NID_sha3_224 &&
365e1051a39Sopenharmony_ci            EVP_MD_get_type((const EVP_MD *)p2) != NID_sha3_256 &&
366e1051a39Sopenharmony_ci            EVP_MD_get_type((const EVP_MD *)p2) != NID_sha3_384 &&
367e1051a39Sopenharmony_ci            EVP_MD_get_type((const EVP_MD *)p2) != NID_sha3_512 &&
368e1051a39Sopenharmony_ci            EVP_MD_get_type((const EVP_MD *)p2) != NID_sm3) {
369e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, EC_R_INVALID_DIGEST_TYPE);
370e1051a39Sopenharmony_ci            return 0;
371e1051a39Sopenharmony_ci        }
372e1051a39Sopenharmony_ci        dctx->md = p2;
373e1051a39Sopenharmony_ci        return 1;
374e1051a39Sopenharmony_ci
375e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_GET_MD:
376e1051a39Sopenharmony_ci        *(const EVP_MD **)p2 = dctx->md;
377e1051a39Sopenharmony_ci        return 1;
378e1051a39Sopenharmony_ci
379e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_PEER_KEY:
380e1051a39Sopenharmony_ci        /* Default behaviour is OK */
381e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_DIGESTINIT:
382e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_PKCS7_SIGN:
383e1051a39Sopenharmony_ci    case EVP_PKEY_CTRL_CMS_SIGN:
384e1051a39Sopenharmony_ci        return 1;
385e1051a39Sopenharmony_ci
386e1051a39Sopenharmony_ci    default:
387e1051a39Sopenharmony_ci        return -2;
388e1051a39Sopenharmony_ci
389e1051a39Sopenharmony_ci    }
390e1051a39Sopenharmony_ci}
391e1051a39Sopenharmony_ci
392e1051a39Sopenharmony_cistatic int pkey_ec_ctrl_str(EVP_PKEY_CTX *ctx,
393e1051a39Sopenharmony_ci                            const char *type, const char *value)
394e1051a39Sopenharmony_ci{
395e1051a39Sopenharmony_ci    if (strcmp(type, "ec_paramgen_curve") == 0) {
396e1051a39Sopenharmony_ci        int nid;
397e1051a39Sopenharmony_ci        nid = EC_curve_nist2nid(value);
398e1051a39Sopenharmony_ci        if (nid == NID_undef)
399e1051a39Sopenharmony_ci            nid = OBJ_sn2nid(value);
400e1051a39Sopenharmony_ci        if (nid == NID_undef)
401e1051a39Sopenharmony_ci            nid = OBJ_ln2nid(value);
402e1051a39Sopenharmony_ci        if (nid == NID_undef) {
403e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, EC_R_INVALID_CURVE);
404e1051a39Sopenharmony_ci            return 0;
405e1051a39Sopenharmony_ci        }
406e1051a39Sopenharmony_ci        return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
407e1051a39Sopenharmony_ci    } else if (strcmp(type, "ec_param_enc") == 0) {
408e1051a39Sopenharmony_ci        int param_enc;
409e1051a39Sopenharmony_ci        if (strcmp(value, "explicit") == 0)
410e1051a39Sopenharmony_ci            param_enc = 0;
411e1051a39Sopenharmony_ci        else if (strcmp(value, "named_curve") == 0)
412e1051a39Sopenharmony_ci            param_enc = OPENSSL_EC_NAMED_CURVE;
413e1051a39Sopenharmony_ci        else
414e1051a39Sopenharmony_ci            return -2;
415e1051a39Sopenharmony_ci        return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc);
416e1051a39Sopenharmony_ci    } else if (strcmp(type, "ecdh_kdf_md") == 0) {
417e1051a39Sopenharmony_ci        const EVP_MD *md;
418e1051a39Sopenharmony_ci        if ((md = EVP_get_digestbyname(value)) == NULL) {
419e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, EC_R_INVALID_DIGEST);
420e1051a39Sopenharmony_ci            return 0;
421e1051a39Sopenharmony_ci        }
422e1051a39Sopenharmony_ci        return EVP_PKEY_CTX_set_ecdh_kdf_md(ctx, md);
423e1051a39Sopenharmony_ci    } else if (strcmp(type, "ecdh_cofactor_mode") == 0) {
424e1051a39Sopenharmony_ci        int co_mode;
425e1051a39Sopenharmony_ci        co_mode = atoi(value);
426e1051a39Sopenharmony_ci        return EVP_PKEY_CTX_set_ecdh_cofactor_mode(ctx, co_mode);
427e1051a39Sopenharmony_ci    }
428e1051a39Sopenharmony_ci
429e1051a39Sopenharmony_ci    return -2;
430e1051a39Sopenharmony_ci}
431e1051a39Sopenharmony_ci
432e1051a39Sopenharmony_cistatic int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
433e1051a39Sopenharmony_ci{
434e1051a39Sopenharmony_ci    EC_KEY *ec = NULL;
435e1051a39Sopenharmony_ci    EC_PKEY_CTX *dctx = ctx->data;
436e1051a39Sopenharmony_ci    int ret;
437e1051a39Sopenharmony_ci
438e1051a39Sopenharmony_ci    if (dctx->gen_group == NULL) {
439e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_NO_PARAMETERS_SET);
440e1051a39Sopenharmony_ci        return 0;
441e1051a39Sopenharmony_ci    }
442e1051a39Sopenharmony_ci    ec = EC_KEY_new();
443e1051a39Sopenharmony_ci    if (ec == NULL)
444e1051a39Sopenharmony_ci        return 0;
445e1051a39Sopenharmony_ci    if (!(ret = EC_KEY_set_group(ec, dctx->gen_group))
446e1051a39Sopenharmony_ci        || !ossl_assert(ret = EVP_PKEY_assign_EC_KEY(pkey, ec)))
447e1051a39Sopenharmony_ci        EC_KEY_free(ec);
448e1051a39Sopenharmony_ci    return ret;
449e1051a39Sopenharmony_ci}
450e1051a39Sopenharmony_ci
451e1051a39Sopenharmony_cistatic int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
452e1051a39Sopenharmony_ci{
453e1051a39Sopenharmony_ci    EC_KEY *ec = NULL;
454e1051a39Sopenharmony_ci    EC_PKEY_CTX *dctx = ctx->data;
455e1051a39Sopenharmony_ci    int ret;
456e1051a39Sopenharmony_ci
457e1051a39Sopenharmony_ci    if (ctx->pkey == NULL && dctx->gen_group == NULL) {
458e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_NO_PARAMETERS_SET);
459e1051a39Sopenharmony_ci        return 0;
460e1051a39Sopenharmony_ci    }
461e1051a39Sopenharmony_ci    ec = EC_KEY_new();
462e1051a39Sopenharmony_ci    if (ec == NULL)
463e1051a39Sopenharmony_ci        return 0;
464e1051a39Sopenharmony_ci    if (!ossl_assert(EVP_PKEY_assign_EC_KEY(pkey, ec))) {
465e1051a39Sopenharmony_ci        EC_KEY_free(ec);
466e1051a39Sopenharmony_ci        return 0;
467e1051a39Sopenharmony_ci    }
468e1051a39Sopenharmony_ci    /* Note: if error is returned, we count on caller to free pkey->pkey.ec */
469e1051a39Sopenharmony_ci    if (ctx->pkey != NULL)
470e1051a39Sopenharmony_ci        ret = EVP_PKEY_copy_parameters(pkey, ctx->pkey);
471e1051a39Sopenharmony_ci    else
472e1051a39Sopenharmony_ci        ret = EC_KEY_set_group(ec, dctx->gen_group);
473e1051a39Sopenharmony_ci
474e1051a39Sopenharmony_ci    return ret ? EC_KEY_generate_key(ec) : 0;
475e1051a39Sopenharmony_ci}
476e1051a39Sopenharmony_ci
477e1051a39Sopenharmony_cistatic const EVP_PKEY_METHOD ec_pkey_meth = {
478e1051a39Sopenharmony_ci    EVP_PKEY_EC,
479e1051a39Sopenharmony_ci    0,
480e1051a39Sopenharmony_ci    pkey_ec_init,
481e1051a39Sopenharmony_ci    pkey_ec_copy,
482e1051a39Sopenharmony_ci    pkey_ec_cleanup,
483e1051a39Sopenharmony_ci
484e1051a39Sopenharmony_ci    0,
485e1051a39Sopenharmony_ci    pkey_ec_paramgen,
486e1051a39Sopenharmony_ci
487e1051a39Sopenharmony_ci    0,
488e1051a39Sopenharmony_ci    pkey_ec_keygen,
489e1051a39Sopenharmony_ci
490e1051a39Sopenharmony_ci    0,
491e1051a39Sopenharmony_ci    pkey_ec_sign,
492e1051a39Sopenharmony_ci
493e1051a39Sopenharmony_ci    0,
494e1051a39Sopenharmony_ci    pkey_ec_verify,
495e1051a39Sopenharmony_ci
496e1051a39Sopenharmony_ci    0, 0,
497e1051a39Sopenharmony_ci
498e1051a39Sopenharmony_ci    0, 0, 0, 0,
499e1051a39Sopenharmony_ci
500e1051a39Sopenharmony_ci    0,
501e1051a39Sopenharmony_ci    0,
502e1051a39Sopenharmony_ci
503e1051a39Sopenharmony_ci    0,
504e1051a39Sopenharmony_ci    0,
505e1051a39Sopenharmony_ci
506e1051a39Sopenharmony_ci    0,
507e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_EC
508e1051a39Sopenharmony_ci    pkey_ec_kdf_derive,
509e1051a39Sopenharmony_ci#else
510e1051a39Sopenharmony_ci    0,
511e1051a39Sopenharmony_ci#endif
512e1051a39Sopenharmony_ci    pkey_ec_ctrl,
513e1051a39Sopenharmony_ci    pkey_ec_ctrl_str
514e1051a39Sopenharmony_ci};
515e1051a39Sopenharmony_ci
516e1051a39Sopenharmony_ciconst EVP_PKEY_METHOD *ossl_ec_pkey_method(void)
517e1051a39Sopenharmony_ci{
518e1051a39Sopenharmony_ci    return &ec_pkey_meth;
519e1051a39Sopenharmony_ci}
520