xref: /openssl/crypto/evp/ec_ctrl.c (revision 87e4e9c4)
1 /*
2  * Copyright 2020-2021 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     return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_TYPE_GEN,
287                              EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID,
288                              nid, NULL);
289 }
290 
291 /*
292  * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
293  * simply because that's easier.
294  */
EVP_PKEY_CTX_set_ec_param_enc(EVP_PKEY_CTX * ctx,int param_enc)295 int EVP_PKEY_CTX_set_ec_param_enc(EVP_PKEY_CTX *ctx, int param_enc)
296 {
297     return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_TYPE_GEN,
298                              EVP_PKEY_CTRL_EC_PARAM_ENC, param_enc, NULL);
299 }
300 #endif
301