xref: /freebsd/crypto/openssl/crypto/evp/ec_ctrl.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include "internal/deprecated.h"
11 
12 #include <openssl/core_names.h>
13 #include <openssl/err.h>
14 #include <openssl/ec.h>
15 #include "crypto/evp.h"
16 #include "crypto/ec.h"
17 
18 /*
19  * This file is meant to contain functions to provide EVP_PKEY support for EC
20  * keys.
21  */
22 
evp_pkey_ctx_getset_ecdh_param_checks(const EVP_PKEY_CTX * ctx)23 static ossl_inline int evp_pkey_ctx_getset_ecdh_param_checks(const EVP_PKEY_CTX *ctx)
24 {
25     if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
26         ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
27         /* Uses the same return values as EVP_PKEY_CTX_ctrl */
28         return -2;
29     }
30 
31     /* If key type not EC return error */
32     if (evp_pkey_ctx_is_legacy(ctx)
33         && ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_EC)
34         return -1;
35 
36     return 1;
37 }
38 
EVP_PKEY_CTX_set_ecdh_cofactor_mode(EVP_PKEY_CTX * ctx,int cofactor_mode)39 int EVP_PKEY_CTX_set_ecdh_cofactor_mode(EVP_PKEY_CTX *ctx, int cofactor_mode)
40 {
41     int ret;
42     OSSL_PARAM params[2], *p = params;
43 
44     ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
45     if (ret != 1)
46         return ret;
47 
48     /*
49      * Valid input values are:
50      *  * 0 for disable
51      *  * 1 for enable
52      *  * -1 for reset to default for associated priv key
53      */
54     if (cofactor_mode < -1 || cofactor_mode > 1) {
55         /* Uses the same return value of pkey_ec_ctrl() */
56         return -2;
57     }
58 
59     *p++ = OSSL_PARAM_construct_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE,
60         &cofactor_mode);
61     *p++ = OSSL_PARAM_construct_end();
62 
63     ret = evp_pkey_ctx_set_params_strict(ctx, params);
64     if (ret == -2)
65         ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
66     return ret;
67 }
68 
EVP_PKEY_CTX_get_ecdh_cofactor_mode(EVP_PKEY_CTX * ctx)69 int EVP_PKEY_CTX_get_ecdh_cofactor_mode(EVP_PKEY_CTX *ctx)
70 {
71     int ret, mode;
72     OSSL_PARAM params[2], *p = params;
73 
74     ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
75     if (ret != 1)
76         return ret;
77 
78     *p++ = OSSL_PARAM_construct_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE,
79         &mode);
80     *p++ = OSSL_PARAM_construct_end();
81 
82     ret = evp_pkey_ctx_get_params_strict(ctx, params);
83 
84     switch (ret) {
85     case -2:
86         ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
87         break;
88     case 1:
89         ret = mode;
90         if (mode < 0 || mode > 1) {
91             /*
92              * The provider should return either 0 or 1, any other value is a
93              * provider error.
94              */
95             ret = -1;
96         }
97         break;
98     default:
99         ret = -1;
100         break;
101     }
102 
103     return ret;
104 }
105 
106 /*
107  * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
108  * simply because that's easier.
109  */
EVP_PKEY_CTX_set_ecdh_kdf_type(EVP_PKEY_CTX * ctx,int kdf)110 int EVP_PKEY_CTX_set_ecdh_kdf_type(EVP_PKEY_CTX *ctx, int kdf)
111 {
112     return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,
113         EVP_PKEY_CTRL_EC_KDF_TYPE, kdf, NULL);
114 }
115 
116 /*
117  * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
118  * simply because that's easier.
119  */
EVP_PKEY_CTX_get_ecdh_kdf_type(EVP_PKEY_CTX * ctx)120 int EVP_PKEY_CTX_get_ecdh_kdf_type(EVP_PKEY_CTX *ctx)
121 {
122     return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,
123         EVP_PKEY_CTRL_EC_KDF_TYPE, -2, NULL);
124 }
125 
126 /*
127  * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
128  * simply because that's easier.
129  */
EVP_PKEY_CTX_set_ecdh_kdf_md(EVP_PKEY_CTX * ctx,const EVP_MD * md)130 int EVP_PKEY_CTX_set_ecdh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
131 {
132     return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,
133         EVP_PKEY_CTRL_EC_KDF_MD, 0, (void *)(md));
134 }
135 
136 /*
137  * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
138  * simply because that's easier.
139  */
EVP_PKEY_CTX_get_ecdh_kdf_md(EVP_PKEY_CTX * ctx,const EVP_MD ** pmd)140 int EVP_PKEY_CTX_get_ecdh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD **pmd)
141 {
142     return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,
143         EVP_PKEY_CTRL_GET_EC_KDF_MD, 0, (void *)(pmd));
144 }
145 
EVP_PKEY_CTX_set_ecdh_kdf_outlen(EVP_PKEY_CTX * ctx,int outlen)146 int EVP_PKEY_CTX_set_ecdh_kdf_outlen(EVP_PKEY_CTX *ctx, int outlen)
147 {
148     int ret;
149     size_t len = outlen;
150     OSSL_PARAM params[2], *p = params;
151 
152     ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
153     if (ret != 1)
154         return ret;
155 
156     if (outlen <= 0) {
157         /*
158          * This would ideally be -1 or 0, but we have to retain compatibility
159          * with legacy behaviour of EVP_PKEY_CTX_ctrl() which returned -2 if
160          * in <= 0
161          */
162         return -2;
163     }
164 
165     *p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN,
166         &len);
167     *p++ = OSSL_PARAM_construct_end();
168 
169     ret = evp_pkey_ctx_set_params_strict(ctx, params);
170     if (ret == -2)
171         ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
172     return ret;
173 }
174 
EVP_PKEY_CTX_get_ecdh_kdf_outlen(EVP_PKEY_CTX * ctx,int * plen)175 int EVP_PKEY_CTX_get_ecdh_kdf_outlen(EVP_PKEY_CTX *ctx, int *plen)
176 {
177     size_t len = UINT_MAX;
178     int ret;
179     OSSL_PARAM params[2], *p = params;
180 
181     ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
182     if (ret != 1)
183         return ret;
184 
185     *p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN,
186         &len);
187     *p++ = OSSL_PARAM_construct_end();
188 
189     ret = evp_pkey_ctx_get_params_strict(ctx, params);
190 
191     switch (ret) {
192     case -2:
193         ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
194         break;
195     case 1:
196         if (len <= INT_MAX)
197             *plen = (int)len;
198         else
199             ret = -1;
200         break;
201     default:
202         ret = -1;
203         break;
204     }
205 
206     return ret;
207 }
208 
EVP_PKEY_CTX_set0_ecdh_kdf_ukm(EVP_PKEY_CTX * ctx,unsigned char * ukm,int len)209 int EVP_PKEY_CTX_set0_ecdh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char *ukm, int len)
210 {
211     int ret;
212     OSSL_PARAM params[2], *p = params;
213 
214     ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
215     if (ret != 1)
216         return ret;
217 
218     *p++ = OSSL_PARAM_construct_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM,
219         /*
220          * Cast away the const. This is read
221          * only so should be safe
222          */
223         (void *)ukm,
224         (size_t)len);
225     *p++ = OSSL_PARAM_construct_end();
226 
227     ret = evp_pkey_ctx_set_params_strict(ctx, params);
228 
229     switch (ret) {
230     case -2:
231         ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
232         break;
233     case 1:
234         OPENSSL_free(ukm);
235         break;
236     }
237 
238     return ret;
239 }
240 
241 #ifndef OPENSSL_NO_DEPRECATED_3_0
EVP_PKEY_CTX_get0_ecdh_kdf_ukm(EVP_PKEY_CTX * ctx,unsigned char ** pukm)242 int EVP_PKEY_CTX_get0_ecdh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **pukm)
243 {
244     size_t ukmlen;
245     int ret;
246     OSSL_PARAM params[2], *p = params;
247 
248     ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
249     if (ret != 1)
250         return ret;
251 
252     *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_EXCHANGE_PARAM_KDF_UKM,
253         (void **)pukm, 0);
254     *p++ = OSSL_PARAM_construct_end();
255 
256     ret = evp_pkey_ctx_get_params_strict(ctx, params);
257 
258     switch (ret) {
259     case -2:
260         ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
261         break;
262     case 1:
263         ret = -1;
264         ukmlen = params[0].return_size;
265         if (ukmlen <= INT_MAX)
266             ret = (int)ukmlen;
267         break;
268     default:
269         ret = -1;
270         break;
271     }
272 
273     return ret;
274 }
275 #endif
276 
277 #ifndef FIPS_MODULE
278 /*
279  * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
280  * simply because that's easier.
281  * ASN1_OBJECT (which would be converted to text internally)?
282  */
EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX * ctx,int nid)283 int EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid)
284 {
285     int keytype = nid == EVP_PKEY_SM2 ? EVP_PKEY_SM2 : EVP_PKEY_EC;
286 
287     return EVP_PKEY_CTX_ctrl(ctx, keytype, EVP_PKEY_OP_TYPE_GEN,
288         EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID,
289         nid, NULL);
290 }
291 
292 /*
293  * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
294  * simply because that's easier.
295  */
EVP_PKEY_CTX_set_ec_param_enc(EVP_PKEY_CTX * ctx,int param_enc)296 int EVP_PKEY_CTX_set_ec_param_enc(EVP_PKEY_CTX *ctx, int param_enc)
297 {
298     return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_TYPE_GEN,
299         EVP_PKEY_CTRL_EC_PARAM_ENC, param_enc, NULL);
300 }
301 #endif
302