Branch data Line data Source code
1 : : /*
2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License").
5 : : * You may not use this file except in compliance with the License.
6 : : * A copy of the License is located at
7 : : *
8 : : * http://aws.amazon.com/apache2.0
9 : : *
10 : : * or in the "license" file accompanying this file. This file is distributed
11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 : : * express or implied. See the License for the specific language governing
13 : : * permissions and limitations under the License.
14 : : */
15 : :
16 : : #include "crypto/s2n_ecc_evp.h"
17 : :
18 : : #include <openssl/ecdh.h>
19 : : #include <openssl/evp.h>
20 : : #if defined(OPENSSL_IS_AWSLC)
21 : : #include <openssl/mem.h>
22 : : #endif
23 : :
24 : : #include <stdint.h>
25 : :
26 : : #include "crypto/s2n_fips.h"
27 : : #include "crypto/s2n_libcrypto.h"
28 : : #include "tls/s2n_connection.h"
29 : : #include "tls/s2n_ecc_preferences.h"
30 : : #include "tls/s2n_tls_parameters.h"
31 : : #include "utils/s2n_mem.h"
32 : : #include "utils/s2n_safety.h"
33 : :
34 : : #define TLS_EC_CURVE_TYPE_NAMED 3
35 : :
36 : : DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY *, EVP_PKEY_free);
37 : : DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY_CTX *, EVP_PKEY_CTX_free);
38 : : DEFINE_POINTER_CLEANUP_FUNC(EC_KEY *, EC_KEY_free);
39 : :
40 : : #if !EVP_APIS_SUPPORTED
41 : : DEFINE_POINTER_CLEANUP_FUNC(EC_POINT *, EC_POINT_free);
42 : : #endif
43 : :
44 : : #if EVP_APIS_SUPPORTED
45 : : static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
46 : : #else
47 : : static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out);
48 : : static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length);
49 : : static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key);
50 : : #endif
51 : : static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
52 : : static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
53 : : static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret);
54 : : static int s2n_ecc_evp_generate_key_noop(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
55 : :
56 : : /* IANA values can be found here: https://tools.ietf.org/html/rfc8446#appendix-B.3.1.4 */
57 : :
58 : : const struct s2n_ecc_named_curve s2n_ecc_curve_secp256r1 = {
59 : : .iana_id = TLS_EC_CURVE_SECP_256_R1,
60 : : .libcrypto_nid = NID_X9_62_prime256v1,
61 : : .name = "secp256r1",
62 : : .share_size = SECP256R1_SHARE_SIZE,
63 : : .generate_key = s2n_ecc_evp_generate_key_nist_curves,
64 : : };
65 : :
66 : : const struct s2n_ecc_named_curve s2n_ecc_curve_secp384r1 = {
67 : : .iana_id = TLS_EC_CURVE_SECP_384_R1,
68 : : .libcrypto_nid = NID_secp384r1,
69 : : .name = "secp384r1",
70 : : .share_size = SECP384R1_SHARE_SIZE,
71 : : .generate_key = s2n_ecc_evp_generate_key_nist_curves,
72 : : };
73 : :
74 : : const struct s2n_ecc_named_curve s2n_ecc_curve_secp521r1 = {
75 : : .iana_id = TLS_EC_CURVE_SECP_521_R1,
76 : : .libcrypto_nid = NID_secp521r1,
77 : : .name = "secp521r1",
78 : : .share_size = SECP521R1_SHARE_SIZE,
79 : : .generate_key = s2n_ecc_evp_generate_key_nist_curves,
80 : : };
81 : :
82 : : #if EVP_APIS_SUPPORTED
83 : : const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = {
84 : : .iana_id = TLS_EC_CURVE_ECDH_X25519,
85 : : .libcrypto_nid = NID_X25519,
86 : : .name = "x25519",
87 : : .share_size = X25519_SHARE_SIZE,
88 : : .generate_key = s2n_ecc_evp_generate_key_x25519,
89 : : };
90 : : #else
91 : : const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = { 0 };
92 : : #endif
93 : :
94 : : /* A fake / unsupported curve for use in triggering retries
95 : : * during testing.
96 : : */
97 : : const struct s2n_ecc_named_curve s2n_unsupported_curve = {
98 : : .iana_id = 0,
99 : : .name = "unsupported",
100 : : .libcrypto_nid = NID_X9_62_prime256v1,
101 : : .share_size = SECP256R1_SHARE_SIZE,
102 : : .generate_key = s2n_ecc_evp_generate_key_nist_curves,
103 : : };
104 : :
105 : : const struct s2n_ecc_named_curve s2n_ecc_curve_none = {
106 : : .iana_id = 0,
107 : : .name = "none",
108 : : .libcrypto_nid = 0,
109 : : .share_size = 0,
110 : : .generate_key = s2n_ecc_evp_generate_key_noop,
111 : : };
112 : :
113 : : /* All curves that s2n supports. New curves MUST be added here.
114 : : * This list is a super set of all the curves present in s2n_ecc_preferences list.
115 : : */
116 : : const struct s2n_ecc_named_curve *const s2n_all_supported_curves_list[] = {
117 : : &s2n_ecc_curve_secp256r1,
118 : : &s2n_ecc_curve_secp384r1,
119 : : #if EVP_APIS_SUPPORTED
120 : : &s2n_ecc_curve_x25519,
121 : : #endif
122 : : &s2n_ecc_curve_secp521r1,
123 : : };
124 : :
125 : : const size_t s2n_all_supported_curves_list_len = s2n_array_len(s2n_all_supported_curves_list);
126 : :
127 : : int s2n_is_evp_apis_supported()
128 : 174 : {
129 : 174 : return EVP_APIS_SUPPORTED;
130 : 174 : }
131 : :
132 : : bool s2n_ecc_evp_supports_fips_check()
133 : 0 : {
134 : : #ifdef S2N_LIBCRYPTO_SUPPORTS_EC_KEY_CHECK_FIPS
135 : : return true;
136 : : #else
137 : 0 : return false;
138 : 0 : #endif
139 : 0 : }
140 : :
141 : : #if EVP_APIS_SUPPORTED
142 : : static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
143 : 1987 : {
144 : 1987 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(named_curve->libcrypto_nid, NULL),
145 : 1987 : EVP_PKEY_CTX_free_pointer);
146 [ - + ][ # # ]: 1987 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
147 : :
148 [ # # ][ - + ]: 1987 : POSIX_GUARD_OSSL(EVP_PKEY_keygen_init(pctx), S2N_ERR_ECDHE_GEN_KEY);
149 [ - + ][ # # ]: 1987 : POSIX_GUARD_OSSL(EVP_PKEY_keygen(pctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY);
150 [ - + ][ # # ]: 1987 : S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
151 : :
152 : 1987 : return 0;
153 : 1987 : }
154 : : #endif
155 : :
156 : : static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
157 : 11590 : {
158 : 11590 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
159 [ - + ][ # # ]: 11590 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
160 : :
161 [ # # ][ - + ]: 11590 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_GEN_KEY);
162 [ - + ][ # # ]: 11590 : POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, named_curve->libcrypto_nid), S2N_ERR_ECDHE_GEN_KEY);
163 : :
164 : 11590 : DEFER_CLEANUP(EVP_PKEY *params = NULL, EVP_PKEY_free_pointer);
165 [ - + ][ # # ]: 11590 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, ¶ms), S2N_ERR_ECDHE_GEN_KEY);
166 [ - + ][ # # ]: 11590 : S2N_ERROR_IF(params == NULL, S2N_ERR_ECDHE_GEN_KEY);
167 : :
168 : 11590 : DEFER_CLEANUP(EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL), EVP_PKEY_CTX_free_pointer);
169 [ - + ][ # # ]: 11590 : S2N_ERROR_IF(kctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
170 : :
171 [ # # ][ - + ]: 11590 : POSIX_GUARD_OSSL(EVP_PKEY_keygen_init(kctx), S2N_ERR_ECDHE_GEN_KEY);
172 [ - + ][ # # ]: 11590 : POSIX_GUARD_OSSL(EVP_PKEY_keygen(kctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY);
173 [ - + ][ # # ]: 11590 : S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
174 : :
175 : 11590 : return 0;
176 : 11590 : }
177 : :
178 : : static int s2n_ecc_evp_generate_key_noop(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
179 : 0 : {
180 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
181 : 0 : }
182 : :
183 : : static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
184 : 13578 : {
185 [ # # ][ - + ]: 13578 : POSIX_ENSURE_REF(named_curve);
186 [ + + ][ + - ]: 13578 : S2N_ERROR_IF(named_curve->generate_key == NULL, S2N_ERR_ECDHE_GEN_KEY);
187 : :
188 : 13577 : return named_curve->generate_key(named_curve, evp_pkey);
189 : 13578 : }
190 : :
191 : : static S2N_RESULT s2n_ecc_check_key(EC_KEY *ec_key)
192 : 9677 : {
193 [ - + ][ # # ]: 9677 : RESULT_ENSURE_REF(ec_key);
194 : :
195 : : #ifdef S2N_LIBCRYPTO_SUPPORTS_EC_KEY_CHECK_FIPS
196 : : if (s2n_is_in_fips_mode()) {
197 : : RESULT_GUARD_OSSL(EC_KEY_check_fips(ec_key), S2N_ERR_ECDHE_INVALID_PUBLIC_KEY_FIPS);
198 : : return S2N_RESULT_OK;
199 : : }
200 : : #endif
201 : :
202 [ + - ][ + + ]: 9677 : RESULT_GUARD_OSSL(EC_KEY_check_key(ec_key), S2N_ERR_ECDHE_INVALID_PUBLIC_KEY);
203 : :
204 : 9674 : return S2N_RESULT_OK;
205 : 9677 : }
206 : :
207 : : static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret)
208 : 10950 : {
209 [ - + ][ # # ]: 10950 : POSIX_ENSURE_REF(peer_public);
210 [ - + ][ # # ]: 10950 : POSIX_ENSURE_REF(own_key);
211 : :
212 : : /**
213 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.8.2
214 : : *# For the curves secp256r1, secp384r1, and secp521r1, peers MUST
215 : : *# validate each other's public value Q by ensuring that the point is a
216 : : *# valid point on the elliptic curve.
217 : : *
218 : : *= https://www.rfc-editor.org/rfc/rfc8422#section-5.11
219 : : *# With the NIST curves, each party MUST validate the public key sent by
220 : : *# its peer in the ClientKeyExchange and ServerKeyExchange messages. A
221 : : *# receiving party MUST check that the x and y parameters from the
222 : : *# peer's public value satisfy the curve equation, y^2 = x^3 + ax + b
223 : : *# mod p.
224 : : *
225 : : * The validation requirement for the public key value only applies to NIST curves. The
226 : : * validation is skipped with non-NIST curves for increased performance.
227 : : */
228 [ + + ][ + - ]: 10950 : if (iana_id != TLS_EC_CURVE_ECDH_X25519 && iana_id != TLS_EC_CURVE_ECDH_X448) {
229 : 9677 : DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(peer_public), EC_KEY_free_pointer);
230 [ # # ][ - + ]: 9677 : POSIX_ENSURE(ec_key, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
231 [ + + ]: 9677 : POSIX_GUARD_RESULT(s2n_ecc_check_key(ec_key));
232 : 9677 : }
233 : :
234 : 10947 : size_t shared_secret_size = 0;
235 : :
236 : 10947 : DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(own_key, NULL), EVP_PKEY_CTX_free_pointer);
237 [ - + ][ # # ]: 10947 : S2N_ERROR_IF(ctx == NULL, S2N_ERR_ECDHE_SHARED_SECRET);
238 : :
239 [ # # ][ - + ]: 10947 : POSIX_GUARD_OSSL(EVP_PKEY_derive_init(ctx), S2N_ERR_ECDHE_SHARED_SECRET);
240 [ - + ][ # # ]: 10947 : POSIX_GUARD_OSSL(EVP_PKEY_derive_set_peer(ctx, peer_public), S2N_ERR_ECDHE_SHARED_SECRET);
241 [ - + ][ # # ]: 10947 : POSIX_GUARD_OSSL(EVP_PKEY_derive(ctx, NULL, &shared_secret_size), S2N_ERR_ECDHE_SHARED_SECRET);
242 [ - + ]: 10947 : POSIX_GUARD(s2n_alloc(shared_secret, shared_secret_size));
243 : :
244 [ - + ]: 10947 : if (EVP_PKEY_derive(ctx, shared_secret->data, &shared_secret_size) != 1) {
245 [ # # ]: 0 : POSIX_GUARD(s2n_free(shared_secret));
246 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_ECDHE_SHARED_SECRET);
247 : 0 : }
248 : :
249 : 10947 : return 0;
250 : 10947 : }
251 : :
252 : : int s2n_ecc_evp_generate_ephemeral_key(struct s2n_ecc_evp_params *ecc_evp_params)
253 : 12795 : {
254 [ + - ][ + + ]: 12795 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
255 [ - + ][ # # ]: 12791 : S2N_ERROR_IF(ecc_evp_params->evp_pkey != NULL, S2N_ERR_ECDHE_GEN_KEY);
256 [ + + ][ + - ]: 12791 : S2N_ERROR_IF(s2n_ecc_evp_generate_own_key(ecc_evp_params->negotiated_curve, &ecc_evp_params->evp_pkey) != 0,
257 : 12791 : S2N_ERR_ECDHE_GEN_KEY);
258 [ - + ][ # # ]: 12790 : S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
259 : 12790 : return 0;
260 : 12790 : }
261 : :
262 : : int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *private_ecc_evp_params,
263 : : struct s2n_ecc_evp_params *public_ecc_evp_params,
264 : : struct s2n_blob *shared_key)
265 : 9367 : {
266 [ - + ][ # # ]: 9367 : POSIX_ENSURE_REF(private_ecc_evp_params->negotiated_curve);
267 [ # # ][ - + ]: 9367 : POSIX_ENSURE_REF(private_ecc_evp_params->evp_pkey);
268 [ - + ][ # # ]: 9367 : POSIX_ENSURE_REF(public_ecc_evp_params->negotiated_curve);
269 [ + + ][ + - ]: 9367 : POSIX_ENSURE_REF(public_ecc_evp_params->evp_pkey);
270 [ + + ][ + - ]: 9366 : S2N_ERROR_IF(private_ecc_evp_params->negotiated_curve->iana_id != public_ecc_evp_params->negotiated_curve->iana_id,
271 : 9366 : S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
272 [ + + ]: 9342 : POSIX_GUARD(s2n_ecc_evp_compute_shared_secret(private_ecc_evp_params->evp_pkey, public_ecc_evp_params->evp_pkey,
273 : 9339 : private_ecc_evp_params->negotiated_curve->iana_id, shared_key));
274 : 9339 : return 0;
275 : 9342 : }
276 : :
277 : : int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *ecc_evp_params,
278 : : struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key)
279 : 821 : {
280 [ - + ][ # # ]: 821 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
281 [ - + ][ # # ]: 821 : POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
282 [ - + ][ # # ]: 821 : POSIX_ENSURE_REF(Yc_in);
283 : :
284 : 821 : uint8_t client_public_len = 0;
285 : 821 : struct s2n_blob client_public_blob = { 0 };
286 : :
287 : 821 : DEFER_CLEANUP(EVP_PKEY *peer_key = EVP_PKEY_new(), EVP_PKEY_free_pointer);
288 [ - + ][ # # ]: 821 : S2N_ERROR_IF(peer_key == NULL, S2N_ERR_BAD_MESSAGE);
289 [ - + ]: 821 : POSIX_GUARD(s2n_stuffer_read_uint8(Yc_in, &client_public_len));
290 : 821 : client_public_blob.size = client_public_len;
291 : 821 : client_public_blob.data = s2n_stuffer_raw_read(Yc_in, client_public_blob.size);
292 [ - + ][ # # ]: 821 : POSIX_ENSURE_REF(client_public_blob.data);
293 : :
294 : 821 : #if EVP_APIS_SUPPORTED
295 [ + + ]: 821 : if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) {
296 [ - + ]: 360 : POSIX_GUARD(EVP_PKEY_set_type(peer_key, ecc_evp_params->negotiated_curve->libcrypto_nid));
297 : 461 : } else {
298 : 461 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
299 [ - + ][ # # ]: 461 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING);
300 [ # # ][ - + ]: 461 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING);
301 [ - + ][ # # ]: 461 : POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING);
302 [ - + ][ # # ]: 461 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, &peer_key), S2N_ERR_ECDHE_SERIALIZING);
303 : 461 : }
304 [ - + ][ # # ]: 821 : POSIX_GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(peer_key, client_public_blob.data, client_public_blob.size),
305 : 821 : S2N_ERR_ECDHE_SERIALIZING);
306 : : #else
307 : : DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid),
308 : : EC_KEY_free_pointer);
309 : : S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
310 : :
311 : : DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(&client_public_blob, ec_key), EC_POINT_free_pointer);
312 : : S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE);
313 : :
314 : : int success = EC_KEY_set_public_key(ec_key, point);
315 : : POSIX_GUARD_OSSL(EVP_PKEY_set1_EC_KEY(peer_key, ec_key), S2N_ERR_ECDHE_SERIALIZING);
316 : : S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE);
317 : : #endif
318 : :
319 : 821 : return s2n_ecc_evp_compute_shared_secret(ecc_evp_params->evp_pkey, peer_key,
320 : 821 : ecc_evp_params->negotiated_curve->iana_id, shared_key);
321 : 821 : }
322 : :
323 : : int s2n_ecc_evp_compute_shared_secret_as_client(struct s2n_ecc_evp_params *ecc_evp_params,
324 : : struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key)
325 : 787 : {
326 : 787 : DEFER_CLEANUP(struct s2n_ecc_evp_params client_params = { 0 }, s2n_ecc_evp_params_free);
327 : :
328 [ # # ][ - + ]: 787 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
329 : 787 : client_params.negotiated_curve = ecc_evp_params->negotiated_curve;
330 [ - + ]: 787 : POSIX_GUARD(s2n_ecc_evp_generate_own_key(client_params.negotiated_curve, &client_params.evp_pkey));
331 [ - + ][ # # ]: 787 : S2N_ERROR_IF(client_params.evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
332 : :
333 [ - + ]: 787 : if (s2n_ecc_evp_compute_shared_secret(client_params.evp_pkey, ecc_evp_params->evp_pkey, ecc_evp_params->negotiated_curve->iana_id, shared_key)
334 : 787 : != S2N_SUCCESS) {
335 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_ECDHE_SHARED_SECRET);
336 : 0 : }
337 : :
338 [ - + ]: 787 : POSIX_GUARD(s2n_stuffer_write_uint8(Yc_out, client_params.negotiated_curve->share_size));
339 : :
340 [ - + ]: 787 : if (s2n_ecc_evp_write_params_point(&client_params, Yc_out) != 0) {
341 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_ECDHE_SERIALIZING);
342 : 0 : }
343 : 787 : return 0;
344 : 787 : }
345 : :
346 : : #if (!EVP_APIS_SUPPORTED)
347 : : static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length)
348 : : {
349 : : size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
350 : : S2N_ERROR_IF(ret == 0, S2N_ERR_ECDHE_SERIALIZING);
351 : : S2N_ERROR_IF(ret > UINT8_MAX, S2N_ERR_ECDHE_SERIALIZING);
352 : : *length = (uint8_t) ret;
353 : : return 0;
354 : : }
355 : :
356 : : static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out)
357 : : {
358 : : size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, out->data, out->size, NULL);
359 : : S2N_ERROR_IF(ret != out->size, S2N_ERR_ECDHE_SERIALIZING);
360 : : return 0;
361 : : }
362 : :
363 : : static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key)
364 : : {
365 : : const EC_GROUP *group = EC_KEY_get0_group(ec_key);
366 : : EC_POINT *point = EC_POINT_new(group);
367 : : if (point == NULL) {
368 : : PTR_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
369 : : }
370 : : if (EC_POINT_oct2point(group, point, blob->data, blob->size, NULL) != 1) {
371 : : EC_POINT_free(point);
372 : : PTR_BAIL(S2N_ERR_BAD_MESSAGE);
373 : : }
374 : : return point;
375 : : }
376 : : #endif
377 : :
378 : : int s2n_ecc_evp_read_params_point(struct s2n_stuffer *in, int point_size, struct s2n_blob *point_blob)
379 : 9833 : {
380 [ - + ][ # # ]: 9833 : POSIX_ENSURE_REF(in);
381 [ - + ][ # # ]: 9833 : POSIX_ENSURE_REF(point_blob);
382 [ # # ][ - + ]: 9833 : POSIX_ENSURE_GTE(point_size, 0);
383 : :
384 : : /* Extract point from stuffer */
385 : 9833 : point_blob->size = point_size;
386 : 9833 : point_blob->data = s2n_stuffer_raw_read(in, point_size);
387 [ - + ][ # # ]: 9833 : POSIX_ENSURE_REF(point_blob->data);
388 : :
389 : 9833 : return 0;
390 : 9833 : }
391 : :
392 : : int s2n_ecc_evp_read_params(struct s2n_stuffer *in, struct s2n_blob *data_to_verify,
393 : : struct s2n_ecdhe_raw_server_params *raw_server_ecc_params)
394 : 822 : {
395 [ # # ][ - + ]: 822 : POSIX_ENSURE_REF(in);
396 : 822 : uint8_t curve_type = 0;
397 : 822 : uint8_t point_length = 0;
398 : :
399 : : /* Remember where we started reading the data */
400 : 822 : data_to_verify->data = s2n_stuffer_raw_read(in, 0);
401 [ - + ][ # # ]: 822 : POSIX_ENSURE_REF(data_to_verify->data);
402 : :
403 : : /* Read the curve */
404 [ - + ]: 822 : POSIX_GUARD(s2n_stuffer_read_uint8(in, &curve_type));
405 [ - + ][ # # ]: 822 : S2N_ERROR_IF(curve_type != TLS_EC_CURVE_TYPE_NAMED, S2N_ERR_BAD_MESSAGE);
406 : 822 : raw_server_ecc_params->curve_blob.data = s2n_stuffer_raw_read(in, 2);
407 [ - + ][ # # ]: 822 : POSIX_ENSURE_REF(raw_server_ecc_params->curve_blob.data);
408 : 822 : raw_server_ecc_params->curve_blob.size = 2;
409 : :
410 : : /* Read the point */
411 [ - + ]: 822 : POSIX_GUARD(s2n_stuffer_read_uint8(in, &point_length));
412 : :
413 [ - + ]: 822 : POSIX_GUARD(s2n_ecc_evp_read_params_point(in, point_length, &raw_server_ecc_params->point_blob));
414 : :
415 : : /* curve type (1) + iana (2) + key share size (1) + key share */
416 : 822 : data_to_verify->size = point_length + 4;
417 : :
418 : 822 : return 0;
419 : 822 : }
420 : :
421 : : int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out)
422 : 11822 : {
423 [ - + ][ # # ]: 11822 : POSIX_ENSURE_REF(ecc_evp_params);
424 [ - + ][ # # ]: 11822 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
425 [ - + ][ # # ]: 11822 : POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
426 [ - + ][ # # ]: 11822 : POSIX_ENSURE_REF(out);
427 : :
428 : 11822 : #if EVP_APIS_SUPPORTED
429 : 11822 : uint8_t *encoded_point = NULL;
430 : :
431 : 11822 : size_t size = EVP_PKEY_get1_tls_encodedpoint(ecc_evp_params->evp_pkey, &encoded_point);
432 [ + + ]: 11822 : if (size != ecc_evp_params->negotiated_curve->share_size) {
433 : 1 : OPENSSL_free(encoded_point);
434 [ + - ]: 1 : POSIX_BAIL(S2N_ERR_ECDHE_SERIALIZING);
435 : 11821 : } else {
436 [ - + ]: 11821 : POSIX_GUARD(s2n_stuffer_write_bytes(out, encoded_point, size));
437 : 11821 : OPENSSL_free(encoded_point);
438 : 11821 : }
439 : : #else
440 : : uint8_t point_len = 0;
441 : : struct s2n_blob point_blob = { 0 };
442 : :
443 : : DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(ecc_evp_params->evp_pkey), EC_KEY_free_pointer);
444 : : S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
445 : : const EC_POINT *point = EC_KEY_get0_public_key(ec_key);
446 : : const EC_GROUP *group = EC_KEY_get0_group(ec_key);
447 : : S2N_ERROR_IF(point == NULL || group == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
448 : :
449 : : POSIX_GUARD(s2n_ecc_evp_calculate_point_length(point, group, &point_len));
450 : : S2N_ERROR_IF(point_len != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
451 : : point_blob.data = s2n_stuffer_raw_write(out, point_len);
452 : : POSIX_ENSURE_REF(point_blob.data);
453 : : point_blob.size = point_len;
454 : :
455 : : POSIX_GUARD(s2n_ecc_evp_write_point_data_snug(point, group, &point_blob));
456 : : #endif
457 : 11821 : return 0;
458 : 11822 : }
459 : :
460 : : int s2n_ecc_evp_write_params(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out,
461 : : struct s2n_blob *written)
462 : 895 : {
463 [ - + ][ # # ]: 895 : POSIX_ENSURE_REF(ecc_evp_params);
464 [ # # ][ - + ]: 895 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
465 [ # # ][ - + ]: 895 : POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
466 [ # # ][ - + ]: 895 : POSIX_ENSURE_REF(out);
467 [ - + ][ # # ]: 895 : POSIX_ENSURE_REF(written);
468 : :
469 : 895 : uint8_t key_share_size = ecc_evp_params->negotiated_curve->share_size;
470 : 895 : uint32_t key_share_offset = out->write_cursor;
471 : :
472 [ - + ]: 895 : POSIX_GUARD(s2n_stuffer_write_uint8(out, TLS_EC_CURVE_TYPE_NAMED));
473 [ - + ]: 895 : POSIX_GUARD(s2n_stuffer_write_uint16(out, ecc_evp_params->negotiated_curve->iana_id));
474 [ - + ]: 895 : POSIX_GUARD(s2n_stuffer_write_uint8(out, key_share_size));
475 : :
476 [ - + ]: 895 : POSIX_GUARD(s2n_ecc_evp_write_params_point(ecc_evp_params, out));
477 : :
478 : : /* key share + key share size (1) + iana (2) + curve type (1) */
479 : 895 : written->size = key_share_size + 4;
480 : 895 : written->data = out->blob.data + key_share_offset;
481 : :
482 : 895 : return written->size;
483 : 895 : }
484 : :
485 : : int s2n_ecc_evp_parse_params_point(struct s2n_blob *point_blob, struct s2n_ecc_evp_params *ecc_evp_params)
486 : 9827 : {
487 [ - + ][ # # ]: 9827 : POSIX_ENSURE_REF(point_blob->data);
488 [ # # ][ - + ]: 9827 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
489 [ - + ][ # # ]: 9827 : S2N_ERROR_IF(point_blob->size != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
490 : :
491 : 9827 : #if EVP_APIS_SUPPORTED
492 [ + + ]: 9827 : if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) {
493 [ + - ]: 845 : if (ecc_evp_params->evp_pkey == NULL) {
494 : 845 : ecc_evp_params->evp_pkey = EVP_PKEY_new();
495 : 845 : }
496 [ - + ][ # # ]: 845 : S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE);
497 [ - + ]: 845 : POSIX_GUARD(EVP_PKEY_set_type(ecc_evp_params->evp_pkey, ecc_evp_params->negotiated_curve->libcrypto_nid));
498 : 8982 : } else {
499 : 8982 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
500 [ - + ][ # # ]: 8982 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING);
501 [ - + ][ # # ]: 8982 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING);
502 [ - + ][ # # ]: 8982 : POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING);
503 [ # # ][ - + ]: 8982 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, &ecc_evp_params->evp_pkey), S2N_ERR_ECDHE_SERIALIZING);
504 : 8982 : }
505 [ + - ][ + + ]: 9827 : POSIX_GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(ecc_evp_params->evp_pkey, point_blob->data, point_blob->size),
506 : 9825 : S2N_ERR_ECDHE_SERIALIZING);
507 : : #else
508 : : if (ecc_evp_params->evp_pkey == NULL) {
509 : : ecc_evp_params->evp_pkey = EVP_PKEY_new();
510 : : }
511 : : S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE);
512 : : /* Create a key to store the point */
513 : : DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid),
514 : : EC_KEY_free_pointer);
515 : : S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
516 : :
517 : : /* Parse and store the server public point */
518 : : DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(point_blob, ec_key), EC_POINT_free_pointer);
519 : : S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE);
520 : :
521 : : /* Set the point as the public key */
522 : : int success = EC_KEY_set_public_key(ec_key, point);
523 : :
524 : : POSIX_GUARD_OSSL(EVP_PKEY_set1_EC_KEY(ecc_evp_params->evp_pkey, ec_key), S2N_ERR_ECDHE_SERIALIZING);
525 : :
526 : : /* EC_KEY_set_public_key returns 1 on success, 0 on failure */
527 : : S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE);
528 : :
529 : : #endif
530 : 9825 : return 0;
531 : 9827 : }
532 : :
533 : : int s2n_ecc_evp_parse_params(struct s2n_connection *conn, struct s2n_ecdhe_raw_server_params *raw_server_ecc_params,
534 : : struct s2n_ecc_evp_params *ecc_evp_params)
535 : 822 : {
536 [ + + ][ + - ]: 822 : POSIX_ENSURE(s2n_ecc_evp_find_supported_curve(conn, &raw_server_ecc_params->curve_blob, &ecc_evp_params->negotiated_curve) == 0,
537 : 820 : S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
538 : 820 : return s2n_ecc_evp_parse_params_point(&raw_server_ecc_params->point_blob, ecc_evp_params);
539 : 822 : }
540 : :
541 : : int s2n_ecc_evp_find_supported_curve(struct s2n_connection *conn, struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **found)
542 : 822 : {
543 : 822 : const struct s2n_ecc_preferences *ecc_prefs = NULL;
544 [ - + ]: 822 : POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_prefs));
545 [ - + ][ # # ]: 822 : POSIX_ENSURE_REF(ecc_prefs);
546 : :
547 : 822 : struct s2n_stuffer iana_ids_in = { 0 };
548 : :
549 [ - + ]: 822 : POSIX_GUARD(s2n_stuffer_init(&iana_ids_in, iana_ids));
550 [ - + ]: 822 : POSIX_GUARD(s2n_stuffer_write(&iana_ids_in, iana_ids));
551 [ + + ]: 852 : for (size_t i = 0; i < ecc_prefs->count; i++) {
552 : 850 : const struct s2n_ecc_named_curve *supported_curve = ecc_prefs->ecc_curves[i];
553 [ + + ]: 880 : for (uint32_t j = 0; j < iana_ids->size / 2; j++) {
554 : 850 : uint16_t iana_id = 0;
555 [ - + ]: 850 : POSIX_GUARD(s2n_stuffer_read_uint16(&iana_ids_in, &iana_id));
556 [ + + ]: 850 : if (supported_curve->iana_id == iana_id) {
557 : 820 : *found = supported_curve;
558 : 820 : return 0;
559 : 820 : }
560 : 850 : }
561 [ - + ]: 30 : POSIX_GUARD(s2n_stuffer_reread(&iana_ids_in));
562 : 30 : }
563 : :
564 [ + - ]: 2 : POSIX_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
565 : 2 : }
566 : :
567 : : int s2n_ecc_evp_params_free(struct s2n_ecc_evp_params *ecc_evp_params)
568 : 14242825 : {
569 [ + + ]: 14242825 : if (ecc_evp_params->evp_pkey != NULL) {
570 : 23488 : EVP_PKEY_free(ecc_evp_params->evp_pkey);
571 : 23488 : ecc_evp_params->evp_pkey = NULL;
572 : 23488 : }
573 : 14242825 : return 0;
574 : 14242825 : }
|