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