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