2 * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
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
10 #include <openssl/core_names.h>
11 #include <openssl/objects.h>
12 #include <openssl/params.h>
13 #include <openssl/err.h>
14 #include "crypto/bn.h"
15 #include "crypto/ec.h"
18 #include "internal/param_build_set.h"
20 /* Mapping between a flag and a name */
21 static const OSSL_ITEM encoding_nameid_map
[] = {
22 { OPENSSL_EC_EXPLICIT_CURVE
, OSSL_PKEY_EC_ENCODING_EXPLICIT
},
23 { OPENSSL_EC_NAMED_CURVE
, OSSL_PKEY_EC_ENCODING_GROUP
},
26 int ec_encoding_name2id(const char *name
)
30 /* Return the default value if there is no name */
32 return OPENSSL_EC_NAMED_CURVE
;
34 for (i
= 0, sz
= OSSL_NELEM(encoding_nameid_map
); i
< sz
; i
++) {
35 if (strcasecmp(name
, encoding_nameid_map
[i
].ptr
) == 0)
36 return encoding_nameid_map
[i
].id
;
41 static char *ec_param_encoding_id2name(int id
)
45 for (i
= 0, sz
= OSSL_NELEM(encoding_nameid_map
); i
< sz
; i
++) {
46 if (id
== (int)encoding_nameid_map
[i
].id
)
47 return encoding_nameid_map
[i
].ptr
;
52 int ec_group_todata(const EC_GROUP
*group
, OSSL_PARAM_BLD
*tmpl
,
53 OSSL_PARAM params
[], OSSL_LIB_CTX
*libctx
,
55 BN_CTX
*bnctx
, unsigned char **genbuf
)
57 int ret
= 0, curve_nid
, encoding_flag
;
58 const char *field_type
, *encoding_name
;
59 const BIGNUM
*cofactor
, *order
;
60 BIGNUM
*p
= NULL
, *a
= NULL
, *b
= NULL
;
61 point_conversion_form_t genform
;
62 const EC_POINT
*genpt
;
63 unsigned char *seed
= NULL
;
64 size_t genbuf_len
, seed_len
;
67 ERR_raise(ERR_LIB_EC
,EC_R_PASSED_NULL_PARAMETER
);
71 encoding_flag
= EC_GROUP_get_asn1_flag(group
) & OPENSSL_EC_NAMED_CURVE
;
72 encoding_name
= ec_param_encoding_id2name(encoding_flag
);
73 if (encoding_name
== NULL
74 || !ossl_param_build_set_utf8_string(tmpl
, params
,
75 OSSL_PKEY_PARAM_EC_ENCODING
,
77 ERR_raise(ERR_LIB_EC
, EC_R_INVALID_ENCODING
);
81 curve_nid
= EC_GROUP_get_curve_name(group
);
82 if (curve_nid
== NID_undef
) {
84 int fid
= EC_GROUP_get_field_type(group
);
86 if (fid
== NID_X9_62_prime_field
) {
87 field_type
= SN_X9_62_prime_field
;
88 } else if (fid
== NID_X9_62_characteristic_two_field
) {
89 field_type
= SN_X9_62_characteristic_two_field
;
91 ERR_raise(ERR_LIB_EC
, EC_R_INVALID_FIELD
);
95 p
= BN_CTX_get(bnctx
);
96 a
= BN_CTX_get(bnctx
);
97 b
= BN_CTX_get(bnctx
);
99 ERR_raise(ERR_LIB_EC
, ERR_R_MALLOC_FAILURE
);
103 if (!EC_GROUP_get_curve(group
, p
, a
, b
, bnctx
)) {
104 ERR_raise(ERR_LIB_EC
, EC_R_INVALID_CURVE
);
108 order
= EC_GROUP_get0_order(group
);
110 ERR_raise(ERR_LIB_EC
, EC_R_INVALID_GROUP_ORDER
);
113 genpt
= EC_GROUP_get0_generator(group
);
115 ERR_raise(ERR_LIB_EC
, EC_R_INVALID_GENERATOR
);
118 genform
= EC_GROUP_get_point_conversion_form(group
);
119 genbuf_len
= EC_POINT_point2buf(group
, genpt
, genform
, genbuf
, bnctx
);
120 if (genbuf_len
== 0) {
121 ERR_raise(ERR_LIB_EC
, EC_R_INVALID_GENERATOR
);
125 if (!ossl_param_build_set_utf8_string(tmpl
, params
,
126 OSSL_PKEY_PARAM_EC_FIELD_TYPE
,
128 || !ossl_param_build_set_bn(tmpl
, params
, OSSL_PKEY_PARAM_EC_P
, p
)
129 || !ossl_param_build_set_bn(tmpl
, params
, OSSL_PKEY_PARAM_EC_A
, a
)
130 || !ossl_param_build_set_bn(tmpl
, params
, OSSL_PKEY_PARAM_EC_B
, b
)
131 || !ossl_param_build_set_bn(tmpl
, params
, OSSL_PKEY_PARAM_EC_ORDER
,
133 || !ossl_param_build_set_octet_string(tmpl
, params
,
134 OSSL_PKEY_PARAM_EC_GENERATOR
,
135 *genbuf
, genbuf_len
)) {
136 ERR_raise(ERR_LIB_EC
, ERR_R_MALLOC_FAILURE
);
140 cofactor
= EC_GROUP_get0_cofactor(group
);
142 && !ossl_param_build_set_bn(tmpl
, params
,
143 OSSL_PKEY_PARAM_EC_COFACTOR
, cofactor
)) {
144 ERR_raise(ERR_LIB_EC
, ERR_R_MALLOC_FAILURE
);
148 seed
= EC_GROUP_get0_seed(group
);
149 seed_len
= EC_GROUP_get_seed_len(group
);
152 && !ossl_param_build_set_octet_string(tmpl
, params
,
153 OSSL_PKEY_PARAM_EC_SEED
,
155 ERR_raise(ERR_LIB_EC
, ERR_R_MALLOC_FAILURE
);
158 #ifdef OPENSSL_NO_EC2M
159 if (fid
== NID_X9_62_characteristic_two_field
) {
160 ERR_raise(ERR_LIB_EC
, EC_R_GF2M_NOT_SUPPORTED
);
166 const char *curve_name
= ec_curve_nid2name(curve_nid
);
168 if (curve_name
== NULL
169 || !ossl_param_build_set_utf8_string(tmpl
, params
,
170 OSSL_PKEY_PARAM_GROUP_NAME
,
172 ERR_raise(ERR_LIB_EC
, EC_R_INVALID_CURVE
);
182 * The intention with the "backend" source file is to offer backend support
183 * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider
184 * implementations alike.
186 int ec_set_ecdh_cofactor_mode(EC_KEY
*ec
, int mode
)
188 const EC_GROUP
*ecg
= EC_KEY_get0_group(ec
);
189 const BIGNUM
*cofactor
;
191 * mode can be only 0 for disable, or 1 for enable here.
193 * This is in contrast with the same parameter on an ECDH EVP_PKEY_CTX that
194 * also supports mode == -1 with the meaning of "reset to the default for
195 * the associated key".
197 if (mode
< 0 || mode
> 1)
200 if ((cofactor
= EC_GROUP_get0_cofactor(ecg
)) == NULL
)
203 /* ECDH cofactor mode has no effect if cofactor is 1 */
204 if (BN_is_one(cofactor
))
208 EC_KEY_set_flags(ec
, EC_FLAG_COFACTOR_ECDH
);
210 EC_KEY_clear_flags(ec
, EC_FLAG_COFACTOR_ECDH
);
216 * Callers of ec_key_fromdata MUST make sure that ec_key_params_fromdata has
217 * been called before!
219 * This function only gets the bare keypair, domain parameters and other
220 * parameters are treated separately, and domain parameters are required to
223 int ec_key_fromdata(EC_KEY
*ec
, const OSSL_PARAM params
[], int include_private
)
225 const OSSL_PARAM
*param_priv_key
= NULL
, *param_pub_key
= NULL
;
227 BIGNUM
*priv_key
= NULL
;
228 unsigned char *pub_key
= NULL
;
230 const EC_GROUP
*ecg
= NULL
;
231 EC_POINT
*pub_point
= NULL
;
234 ecg
= EC_KEY_get0_group(ec
);
239 OSSL_PARAM_locate_const(params
, OSSL_PKEY_PARAM_PUB_KEY
);
242 OSSL_PARAM_locate_const(params
, OSSL_PKEY_PARAM_PRIV_KEY
);
244 ctx
= BN_CTX_new_ex(ec_key_get_libctx(ec
));
248 if (param_pub_key
!= NULL
)
249 if (!OSSL_PARAM_get_octet_string(param_pub_key
,
250 (void **)&pub_key
, 0, &pub_key_len
)
251 || (pub_point
= EC_POINT_new(ecg
)) == NULL
252 || !EC_POINT_oct2point(ecg
, pub_point
, pub_key
, pub_key_len
, ctx
))
255 if (param_priv_key
!= NULL
&& include_private
) {
260 * Key import/export should never leak the bit length of the secret
263 * For this reason, on export we use padded BIGNUMs with fixed length.
265 * When importing we also should make sure that, even if short lived,
266 * the newly created BIGNUM is marked with the BN_FLG_CONSTTIME flag as
267 * soon as possible, so that any processing of this BIGNUM might opt for
268 * constant time implementations in the backend.
270 * Setting the BN_FLG_CONSTTIME flag alone is never enough, we also have
271 * to preallocate the BIGNUM internal buffer to a fixed public size big
272 * enough that operations performed during the processing never trigger
273 * a realloc which would leak the size of the scalar through memory
279 * The order of the large prime subgroup of the curve is our choice for
280 * a fixed public size, as that is generally the upper bound for
281 * generating a private key in EC cryptosystems and should fit all valid
284 * For padding on export we just use the bit length of the order
285 * converted to bytes (rounding up).
287 * For preallocating the BIGNUM storage we look at the number of "words"
288 * required for the internal representation of the order, and we
289 * preallocate 2 extra "words" in case any of the subsequent processing
290 * might temporarily overflow the order length.
292 order
= EC_GROUP_get0_order(ecg
);
293 if (order
== NULL
|| BN_is_zero(order
))
296 fixed_words
= bn_get_top(order
) + 2;
298 if ((priv_key
= BN_secure_new()) == NULL
)
300 if (bn_wexpand(priv_key
, fixed_words
) == NULL
)
302 BN_set_flags(priv_key
, BN_FLG_CONSTTIME
);
304 if (!OSSL_PARAM_get_BN(param_priv_key
, &priv_key
))
309 && !EC_KEY_set_private_key(ec
, priv_key
))
312 if (pub_point
!= NULL
313 && !EC_KEY_set_public_key(ec
, pub_point
))
320 BN_clear_free(priv_key
);
321 OPENSSL_free(pub_key
);
322 EC_POINT_free(pub_point
);
326 int ec_group_fromdata(EC_KEY
*ec
, const OSSL_PARAM params
[])
329 EC_GROUP
*group
= NULL
;
334 group
= EC_GROUP_new_from_params(params
, ec_key_get_libctx(ec
),
335 ec_key_get0_propq(ec
));
337 if (!EC_KEY_set_group(ec
, group
))
341 * TODO(3.0): if the group has changed, should we invalidate the private and
346 EC_GROUP_free(group
);
350 int ec_key_otherparams_fromdata(EC_KEY
*ec
, const OSSL_PARAM params
[])
357 p
= OSSL_PARAM_locate_const(params
, OSSL_PKEY_PARAM_USE_COFACTOR_ECDH
);
361 if (!OSSL_PARAM_get_int(p
, &mode
)
362 || !ec_set_ecdh_cofactor_mode(ec
, mode
))