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 : 5269 : {
129 : 5269 : return EVP_APIS_SUPPORTED;
130 : 5269 : }
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 : : int s2n_find_ecc_curve_from_iana_id(uint16_t iana_id, const struct s2n_ecc_named_curve **out, bool *found)
142 : 4 : {
143 [ # # ][ - + ]: 4 : POSIX_ENSURE_REF(out);
144 [ # # ][ - + ]: 4 : POSIX_ENSURE_REF(found);
145 : 4 : *found = false;
146 : :
147 [ + - ]: 8 : for (size_t i = 0; i < s2n_all_supported_curves_list_len; i++) {
148 : 8 : const struct s2n_ecc_named_curve *curve = s2n_all_supported_curves_list[i];
149 [ - + ][ # # ]: 8 : POSIX_ENSURE_REF(curve);
150 [ + + ]: 8 : if (curve->iana_id == iana_id) {
151 : 4 : *out = curve;
152 : 4 : *found = true;
153 : 4 : return S2N_SUCCESS;
154 : 4 : }
155 : 8 : }
156 : 0 : return S2N_SUCCESS;
157 : 4 : }
158 : :
159 : : #if EVP_APIS_SUPPORTED
160 : : static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
161 : 1997 : {
162 : 1997 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(named_curve->libcrypto_nid, NULL),
163 : 1997 : EVP_PKEY_CTX_free_pointer);
164 [ - + ][ # # ]: 1997 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
165 : :
166 [ - + ][ # # ]: 1997 : POSIX_GUARD_OSSL(EVP_PKEY_keygen_init(pctx), S2N_ERR_ECDHE_GEN_KEY);
167 [ - + ][ # # ]: 1997 : POSIX_GUARD_OSSL(EVP_PKEY_keygen(pctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY);
168 [ - + ][ # # ]: 1997 : S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
169 : :
170 : 1997 : return 0;
171 : 1997 : }
172 : : #endif
173 : :
174 : : static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
175 : 11859 : {
176 : 11859 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
177 [ - + ][ # # ]: 11859 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
178 : :
179 [ - + ][ # # ]: 11859 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_GEN_KEY);
180 [ - + ][ # # ]: 11859 : POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, named_curve->libcrypto_nid), S2N_ERR_ECDHE_GEN_KEY);
181 : :
182 : 11859 : DEFER_CLEANUP(EVP_PKEY *params = NULL, EVP_PKEY_free_pointer);
183 [ # # ][ - + ]: 11859 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, ¶ms), S2N_ERR_ECDHE_GEN_KEY);
184 [ - + ][ # # ]: 11859 : S2N_ERROR_IF(params == NULL, S2N_ERR_ECDHE_GEN_KEY);
185 : :
186 : 11859 : DEFER_CLEANUP(EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL), EVP_PKEY_CTX_free_pointer);
187 [ - + ][ # # ]: 11859 : S2N_ERROR_IF(kctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
188 : :
189 [ - + ][ # # ]: 11859 : POSIX_GUARD_OSSL(EVP_PKEY_keygen_init(kctx), S2N_ERR_ECDHE_GEN_KEY);
190 [ - + ][ # # ]: 11859 : POSIX_GUARD_OSSL(EVP_PKEY_keygen(kctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY);
191 [ - + ][ # # ]: 11859 : S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
192 : :
193 : 11859 : return 0;
194 : 11859 : }
195 : :
196 : : static int s2n_ecc_evp_generate_key_noop(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
197 : 0 : {
198 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
199 : 0 : }
200 : :
201 : : static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
202 : 13857 : {
203 [ # # ][ - + ]: 13857 : POSIX_ENSURE_REF(named_curve);
204 [ + + ][ + - ]: 13857 : S2N_ERROR_IF(named_curve->generate_key == NULL, S2N_ERR_ECDHE_GEN_KEY);
205 : :
206 : 13856 : return named_curve->generate_key(named_curve, evp_pkey);
207 : 13857 : }
208 : :
209 : : static S2N_RESULT s2n_ecc_check_key(EC_KEY *ec_key)
210 : 9949 : {
211 [ - + ][ # # ]: 9949 : RESULT_ENSURE_REF(ec_key);
212 : :
213 : : #ifdef S2N_LIBCRYPTO_SUPPORTS_EC_KEY_CHECK_FIPS
214 : : if (s2n_is_in_fips_mode()) {
215 : : RESULT_GUARD_OSSL(EC_KEY_check_fips(ec_key), S2N_ERR_ECDHE_INVALID_PUBLIC_KEY_FIPS);
216 : : return S2N_RESULT_OK;
217 : : }
218 : : #endif
219 : :
220 [ + + ][ + - ]: 9949 : RESULT_GUARD_OSSL(EC_KEY_check_key(ec_key), S2N_ERR_ECDHE_INVALID_PUBLIC_KEY);
221 : :
222 : 9946 : return S2N_RESULT_OK;
223 : 9949 : }
224 : :
225 : : 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)
226 : 11228 : {
227 [ # # ][ - + ]: 11228 : POSIX_ENSURE_REF(peer_public);
228 [ # # ][ - + ]: 11228 : POSIX_ENSURE_REF(own_key);
229 : :
230 : : /**
231 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.8.2
232 : : *# For the curves secp256r1, secp384r1, and secp521r1, peers MUST
233 : : *# validate each other's public value Q by ensuring that the point is a
234 : : *# valid point on the elliptic curve.
235 : : *
236 : : *= https://www.rfc-editor.org/rfc/rfc8422#section-5.11
237 : : *# With the NIST curves, each party MUST validate the public key sent by
238 : : *# its peer in the ClientKeyExchange and ServerKeyExchange messages. A
239 : : *# receiving party MUST check that the x and y parameters from the
240 : : *# peer's public value satisfy the curve equation, y^2 = x^3 + ax + b
241 : : *# mod p.
242 : : *
243 : : * The validation requirement for the public key value only applies to NIST curves. The
244 : : * validation is skipped with non-NIST curves for increased performance.
245 : : */
246 [ + + ][ + - ]: 11228 : if (iana_id != TLS_EC_CURVE_ECDH_X25519 && iana_id != TLS_EC_CURVE_ECDH_X448) {
247 : 9949 : DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(peer_public), EC_KEY_free_pointer);
248 [ - + ][ # # ]: 9949 : POSIX_ENSURE(ec_key, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
249 [ + + ]: 9949 : POSIX_GUARD_RESULT(s2n_ecc_check_key(ec_key));
250 : 9949 : }
251 : :
252 : 11225 : size_t shared_secret_size = 0;
253 : :
254 : 11225 : DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(own_key, NULL), EVP_PKEY_CTX_free_pointer);
255 [ - + ][ # # ]: 11225 : S2N_ERROR_IF(ctx == NULL, S2N_ERR_ECDHE_SHARED_SECRET);
256 : :
257 [ - + ][ # # ]: 11225 : POSIX_GUARD_OSSL(EVP_PKEY_derive_init(ctx), S2N_ERR_ECDHE_SHARED_SECRET);
258 [ # # ][ - + ]: 11225 : POSIX_GUARD_OSSL(EVP_PKEY_derive_set_peer(ctx, peer_public), S2N_ERR_ECDHE_SHARED_SECRET);
259 [ # # ][ - + ]: 11225 : POSIX_GUARD_OSSL(EVP_PKEY_derive(ctx, NULL, &shared_secret_size), S2N_ERR_ECDHE_SHARED_SECRET);
260 [ - + ]: 11225 : POSIX_GUARD(s2n_alloc(shared_secret, shared_secret_size));
261 : :
262 [ - + ]: 11225 : if (EVP_PKEY_derive(ctx, shared_secret->data, &shared_secret_size) != 1) {
263 [ # # ]: 0 : POSIX_GUARD(s2n_free(shared_secret));
264 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_ECDHE_SHARED_SECRET);
265 : 0 : }
266 : :
267 : 11225 : return 0;
268 : 11225 : }
269 : :
270 : : int s2n_ecc_evp_generate_ephemeral_key(struct s2n_ecc_evp_params *ecc_evp_params)
271 : 13077 : {
272 [ + + ][ + - ]: 13077 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
273 [ - + ][ # # ]: 13073 : S2N_ERROR_IF(ecc_evp_params->evp_pkey != NULL, S2N_ERR_ECDHE_GEN_KEY);
274 [ + + ][ + - ]: 13073 : S2N_ERROR_IF(s2n_ecc_evp_generate_own_key(ecc_evp_params->negotiated_curve, &ecc_evp_params->evp_pkey) != 0,
275 : 13073 : S2N_ERR_ECDHE_GEN_KEY);
276 [ - + ][ # # ]: 13072 : S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
277 : 13072 : return 0;
278 : 13072 : }
279 : :
280 : : int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *private_ecc_evp_params,
281 : : struct s2n_ecc_evp_params *public_ecc_evp_params,
282 : : struct s2n_blob *shared_key)
283 : 9651 : {
284 [ - + ][ # # ]: 9651 : POSIX_ENSURE_REF(private_ecc_evp_params->negotiated_curve);
285 [ - + ][ # # ]: 9651 : POSIX_ENSURE_REF(private_ecc_evp_params->evp_pkey);
286 [ # # ][ - + ]: 9651 : POSIX_ENSURE_REF(public_ecc_evp_params->negotiated_curve);
287 [ + - ][ + + ]: 9651 : POSIX_ENSURE_REF(public_ecc_evp_params->evp_pkey);
288 [ + + ][ + - ]: 9650 : S2N_ERROR_IF(private_ecc_evp_params->negotiated_curve->iana_id != public_ecc_evp_params->negotiated_curve->iana_id,
289 : 9650 : S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
290 [ + + ]: 9626 : POSIX_GUARD(s2n_ecc_evp_compute_shared_secret(private_ecc_evp_params->evp_pkey, public_ecc_evp_params->evp_pkey,
291 : 9623 : private_ecc_evp_params->negotiated_curve->iana_id, shared_key));
292 : 9623 : return 0;
293 : 9626 : }
294 : :
295 : : int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *ecc_evp_params,
296 : : struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key)
297 : 818 : {
298 [ - + ][ # # ]: 818 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
299 [ - + ][ # # ]: 818 : POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
300 [ # # ][ - + ]: 818 : POSIX_ENSURE_REF(Yc_in);
301 : :
302 : 818 : uint8_t client_public_len = 0;
303 : 818 : struct s2n_blob client_public_blob = { 0 };
304 : :
305 : 818 : DEFER_CLEANUP(EVP_PKEY *peer_key = EVP_PKEY_new(), EVP_PKEY_free_pointer);
306 [ - + ][ # # ]: 818 : S2N_ERROR_IF(peer_key == NULL, S2N_ERR_BAD_MESSAGE);
307 [ - + ]: 818 : POSIX_GUARD(s2n_stuffer_read_uint8(Yc_in, &client_public_len));
308 : 818 : client_public_blob.size = client_public_len;
309 : 818 : client_public_blob.data = s2n_stuffer_raw_read(Yc_in, client_public_blob.size);
310 [ # # ][ - + ]: 818 : POSIX_ENSURE_REF(client_public_blob.data);
311 : :
312 : 818 : #if EVP_APIS_SUPPORTED
313 [ + + ]: 818 : if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) {
314 [ - + ]: 360 : POSIX_GUARD(EVP_PKEY_set_type(peer_key, ecc_evp_params->negotiated_curve->libcrypto_nid));
315 : 458 : } else {
316 : 458 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
317 [ - + ][ # # ]: 458 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING);
318 [ - + ][ # # ]: 458 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING);
319 [ # # ][ - + ]: 458 : POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING);
320 [ - + ][ # # ]: 458 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, &peer_key), S2N_ERR_ECDHE_SERIALIZING);
321 : 458 : }
322 [ - + ][ # # ]: 818 : POSIX_GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(peer_key, client_public_blob.data, client_public_blob.size),
323 : 818 : S2N_ERR_ECDHE_SERIALIZING);
324 : : #else
325 : : DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid),
326 : : EC_KEY_free_pointer);
327 : : S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
328 : :
329 : : DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(&client_public_blob, ec_key), EC_POINT_free_pointer);
330 : : S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE);
331 : :
332 : : int success = EC_KEY_set_public_key(ec_key, point);
333 : : POSIX_GUARD_OSSL(EVP_PKEY_set1_EC_KEY(peer_key, ec_key), S2N_ERR_ECDHE_SERIALIZING);
334 : : S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE);
335 : : #endif
336 : :
337 : 818 : return s2n_ecc_evp_compute_shared_secret(ecc_evp_params->evp_pkey, peer_key,
338 : 818 : ecc_evp_params->negotiated_curve->iana_id, shared_key);
339 : 818 : }
340 : :
341 : : int s2n_ecc_evp_compute_shared_secret_as_client(struct s2n_ecc_evp_params *ecc_evp_params,
342 : : struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key)
343 : 784 : {
344 : 784 : DEFER_CLEANUP(struct s2n_ecc_evp_params client_params = { 0 }, s2n_ecc_evp_params_free);
345 : :
346 [ - + ][ # # ]: 784 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
347 : 784 : client_params.negotiated_curve = ecc_evp_params->negotiated_curve;
348 [ - + ]: 784 : POSIX_GUARD(s2n_ecc_evp_generate_own_key(client_params.negotiated_curve, &client_params.evp_pkey));
349 [ - + ][ # # ]: 784 : S2N_ERROR_IF(client_params.evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
350 : :
351 [ - + ]: 784 : 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)
352 : 784 : != S2N_SUCCESS) {
353 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_ECDHE_SHARED_SECRET);
354 : 0 : }
355 : :
356 [ - + ]: 784 : POSIX_GUARD(s2n_stuffer_write_uint8(Yc_out, client_params.negotiated_curve->share_size));
357 : :
358 [ - + ]: 784 : if (s2n_ecc_evp_write_params_point(&client_params, Yc_out) != 0) {
359 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_ECDHE_SERIALIZING);
360 : 0 : }
361 : 784 : return 0;
362 : 784 : }
363 : :
364 : : #if (!EVP_APIS_SUPPORTED)
365 : : static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length)
366 : : {
367 : : size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
368 : : S2N_ERROR_IF(ret == 0, S2N_ERR_ECDHE_SERIALIZING);
369 : : S2N_ERROR_IF(ret > UINT8_MAX, S2N_ERR_ECDHE_SERIALIZING);
370 : : *length = (uint8_t) ret;
371 : : return 0;
372 : : }
373 : :
374 : : static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out)
375 : : {
376 : : size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, out->data, out->size, NULL);
377 : : S2N_ERROR_IF(ret != out->size, S2N_ERR_ECDHE_SERIALIZING);
378 : : return 0;
379 : : }
380 : :
381 : : static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key)
382 : : {
383 : : const EC_GROUP *group = EC_KEY_get0_group(ec_key);
384 : : EC_POINT *point = EC_POINT_new(group);
385 : : if (point == NULL) {
386 : : PTR_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
387 : : }
388 : : if (EC_POINT_oct2point(group, point, blob->data, blob->size, NULL) != 1) {
389 : : EC_POINT_free(point);
390 : : PTR_BAIL(S2N_ERR_BAD_MESSAGE);
391 : : }
392 : : return point;
393 : : }
394 : : #endif
395 : :
396 : : int s2n_ecc_evp_read_params_point(struct s2n_stuffer *in, int point_size, struct s2n_blob *point_blob)
397 : 10122 : {
398 [ - + ][ # # ]: 10122 : POSIX_ENSURE_REF(in);
399 [ - + ][ # # ]: 10122 : POSIX_ENSURE_REF(point_blob);
400 [ - + ][ # # ]: 10122 : POSIX_ENSURE_GTE(point_size, 0);
401 : :
402 : : /* Extract point from stuffer */
403 : 10122 : point_blob->size = point_size;
404 : 10122 : point_blob->data = s2n_stuffer_raw_read(in, point_size);
405 [ - + ][ # # ]: 10122 : POSIX_ENSURE_REF(point_blob->data);
406 : :
407 : 10122 : return 0;
408 : 10122 : }
409 : :
410 : : int s2n_ecc_evp_read_params(struct s2n_stuffer *in, struct s2n_blob *data_to_verify,
411 : : struct s2n_ecdhe_raw_server_params *raw_server_ecc_params)
412 : 819 : {
413 [ - + ][ # # ]: 819 : POSIX_ENSURE_REF(in);
414 : 819 : uint8_t curve_type = 0;
415 : 819 : uint8_t point_length = 0;
416 : :
417 : : /* Remember where we started reading the data */
418 : 819 : data_to_verify->data = s2n_stuffer_raw_read(in, 0);
419 [ - + ][ # # ]: 819 : POSIX_ENSURE_REF(data_to_verify->data);
420 : :
421 : : /* Read the curve */
422 [ - + ]: 819 : POSIX_GUARD(s2n_stuffer_read_uint8(in, &curve_type));
423 [ - + ][ # # ]: 819 : S2N_ERROR_IF(curve_type != TLS_EC_CURVE_TYPE_NAMED, S2N_ERR_BAD_MESSAGE);
424 : 819 : raw_server_ecc_params->curve_blob.data = s2n_stuffer_raw_read(in, 2);
425 [ - + ][ # # ]: 819 : POSIX_ENSURE_REF(raw_server_ecc_params->curve_blob.data);
426 : 819 : raw_server_ecc_params->curve_blob.size = 2;
427 : :
428 : : /* Read the point */
429 [ - + ]: 819 : POSIX_GUARD(s2n_stuffer_read_uint8(in, &point_length));
430 : :
431 [ - + ]: 819 : POSIX_GUARD(s2n_ecc_evp_read_params_point(in, point_length, &raw_server_ecc_params->point_blob));
432 : :
433 : : /* curve type (1) + iana (2) + key share size (1) + key share */
434 : 819 : data_to_verify->size = point_length + 4;
435 : :
436 : 819 : return 0;
437 : 819 : }
438 : :
439 : : int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out)
440 : 12101 : {
441 [ - + ][ # # ]: 12101 : POSIX_ENSURE_REF(ecc_evp_params);
442 [ - + ][ # # ]: 12101 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
443 [ - + ][ # # ]: 12101 : POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
444 [ # # ][ - + ]: 12101 : POSIX_ENSURE_REF(out);
445 : :
446 : 12101 : #if EVP_APIS_SUPPORTED
447 : 12101 : uint8_t *encoded_point = NULL;
448 : :
449 : 12101 : size_t size = EVP_PKEY_get1_tls_encodedpoint(ecc_evp_params->evp_pkey, &encoded_point);
450 [ + + ]: 12101 : if (size != ecc_evp_params->negotiated_curve->share_size) {
451 : 1 : OPENSSL_free(encoded_point);
452 [ + - ]: 1 : POSIX_BAIL(S2N_ERR_ECDHE_SERIALIZING);
453 : 12100 : } else {
454 [ - + ]: 12100 : POSIX_GUARD(s2n_stuffer_write_bytes(out, encoded_point, size));
455 : 12100 : OPENSSL_free(encoded_point);
456 : 12100 : }
457 : : #else
458 : : uint8_t point_len = 0;
459 : : struct s2n_blob point_blob = { 0 };
460 : :
461 : : DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(ecc_evp_params->evp_pkey), EC_KEY_free_pointer);
462 : : S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
463 : : const EC_POINT *point = EC_KEY_get0_public_key(ec_key);
464 : : const EC_GROUP *group = EC_KEY_get0_group(ec_key);
465 : : S2N_ERROR_IF(point == NULL || group == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
466 : :
467 : : POSIX_GUARD(s2n_ecc_evp_calculate_point_length(point, group, &point_len));
468 : : S2N_ERROR_IF(point_len != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
469 : : point_blob.data = s2n_stuffer_raw_write(out, point_len);
470 : : POSIX_ENSURE_REF(point_blob.data);
471 : : point_blob.size = point_len;
472 : :
473 : : POSIX_GUARD(s2n_ecc_evp_write_point_data_snug(point, group, &point_blob));
474 : : #endif
475 : 12100 : return 0;
476 : 12101 : }
477 : :
478 : : int s2n_ecc_evp_write_params(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out,
479 : : struct s2n_blob *written)
480 : 890 : {
481 [ # # ][ - + ]: 890 : POSIX_ENSURE_REF(ecc_evp_params);
482 [ - + ][ # # ]: 890 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
483 [ - + ][ # # ]: 890 : POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
484 [ # # ][ - + ]: 890 : POSIX_ENSURE_REF(out);
485 [ - + ][ # # ]: 890 : POSIX_ENSURE_REF(written);
486 : :
487 : 890 : uint8_t key_share_size = ecc_evp_params->negotiated_curve->share_size;
488 : 890 : uint32_t key_share_offset = out->write_cursor;
489 : :
490 [ - + ]: 890 : POSIX_GUARD(s2n_stuffer_write_uint8(out, TLS_EC_CURVE_TYPE_NAMED));
491 [ - + ]: 890 : POSIX_GUARD(s2n_stuffer_write_uint16(out, ecc_evp_params->negotiated_curve->iana_id));
492 [ - + ]: 890 : POSIX_GUARD(s2n_stuffer_write_uint8(out, key_share_size));
493 : :
494 [ - + ]: 890 : POSIX_GUARD(s2n_ecc_evp_write_params_point(ecc_evp_params, out));
495 : :
496 : : /* key share + key share size (1) + iana (2) + curve type (1) */
497 : 890 : written->size = key_share_size + 4;
498 : 890 : written->data = out->blob.data + key_share_offset;
499 : :
500 : 890 : return written->size;
501 : 890 : }
502 : :
503 : : int s2n_ecc_evp_parse_params_point(struct s2n_blob *point_blob, struct s2n_ecc_evp_params *ecc_evp_params)
504 : 10116 : {
505 [ - + ][ # # ]: 10116 : POSIX_ENSURE_REF(point_blob->data);
506 [ # # ][ - + ]: 10116 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
507 [ - + ][ # # ]: 10116 : S2N_ERROR_IF(point_blob->size != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
508 : :
509 : 10116 : #if EVP_APIS_SUPPORTED
510 [ + + ]: 10116 : if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) {
511 [ + - ]: 855 : if (ecc_evp_params->evp_pkey == NULL) {
512 : 855 : ecc_evp_params->evp_pkey = EVP_PKEY_new();
513 : 855 : }
514 [ - + ][ # # ]: 855 : S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE);
515 [ - + ]: 855 : POSIX_GUARD(EVP_PKEY_set_type(ecc_evp_params->evp_pkey, ecc_evp_params->negotiated_curve->libcrypto_nid));
516 : 9261 : } else {
517 : 9261 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
518 [ - + ][ # # ]: 9261 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING);
519 [ # # ][ - + ]: 9261 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING);
520 [ - + ][ # # ]: 9261 : POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING);
521 [ - + ][ # # ]: 9261 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, &ecc_evp_params->evp_pkey), S2N_ERR_ECDHE_SERIALIZING);
522 : 9261 : }
523 [ + + ][ + - ]: 10116 : POSIX_GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(ecc_evp_params->evp_pkey, point_blob->data, point_blob->size),
524 : 10114 : S2N_ERR_ECDHE_SERIALIZING);
525 : : #else
526 : : if (ecc_evp_params->evp_pkey == NULL) {
527 : : ecc_evp_params->evp_pkey = EVP_PKEY_new();
528 : : }
529 : : S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE);
530 : : /* Create a key to store the point */
531 : : DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid),
532 : : EC_KEY_free_pointer);
533 : : S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
534 : :
535 : : /* Parse and store the server public point */
536 : : DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(point_blob, ec_key), EC_POINT_free_pointer);
537 : : S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE);
538 : :
539 : : /* Set the point as the public key */
540 : : int success = EC_KEY_set_public_key(ec_key, point);
541 : :
542 : : POSIX_GUARD_OSSL(EVP_PKEY_set1_EC_KEY(ecc_evp_params->evp_pkey, ec_key), S2N_ERR_ECDHE_SERIALIZING);
543 : :
544 : : /* EC_KEY_set_public_key returns 1 on success, 0 on failure */
545 : : S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE);
546 : :
547 : : #endif
548 : 10114 : return 0;
549 : 10116 : }
550 : :
551 : : int s2n_ecc_evp_parse_params(struct s2n_connection *conn, struct s2n_ecdhe_raw_server_params *raw_server_ecc_params,
552 : : struct s2n_ecc_evp_params *ecc_evp_params)
553 : 819 : {
554 [ + - ][ + + ]: 819 : POSIX_ENSURE(s2n_ecc_evp_find_supported_curve(conn, &raw_server_ecc_params->curve_blob, &ecc_evp_params->negotiated_curve) == 0,
555 : 817 : S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
556 : 817 : return s2n_ecc_evp_parse_params_point(&raw_server_ecc_params->point_blob, ecc_evp_params);
557 : 819 : }
558 : :
559 : : int s2n_ecc_evp_find_supported_curve(struct s2n_connection *conn, struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **found)
560 : 819 : {
561 : 819 : const struct s2n_ecc_preferences *ecc_prefs = NULL;
562 [ - + ]: 819 : POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_prefs));
563 [ - + ][ # # ]: 819 : POSIX_ENSURE_REF(ecc_prefs);
564 : :
565 : 819 : struct s2n_stuffer iana_ids_in = { 0 };
566 : :
567 [ - + ]: 819 : POSIX_GUARD(s2n_stuffer_init(&iana_ids_in, iana_ids));
568 [ - + ]: 819 : POSIX_GUARD(s2n_stuffer_write(&iana_ids_in, iana_ids));
569 [ + + ]: 849 : for (size_t i = 0; i < ecc_prefs->count; i++) {
570 : 847 : const struct s2n_ecc_named_curve *supported_curve = ecc_prefs->ecc_curves[i];
571 [ + + ]: 877 : for (uint32_t j = 0; j < iana_ids->size / 2; j++) {
572 : 847 : uint16_t iana_id = 0;
573 [ - + ]: 847 : POSIX_GUARD(s2n_stuffer_read_uint16(&iana_ids_in, &iana_id));
574 [ + + ]: 847 : if (supported_curve->iana_id == iana_id) {
575 : 817 : *found = supported_curve;
576 : 817 : return 0;
577 : 817 : }
578 : 847 : }
579 [ - + ]: 30 : POSIX_GUARD(s2n_stuffer_reread(&iana_ids_in));
580 : 30 : }
581 : :
582 [ + - ]: 2 : POSIX_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
583 : 2 : }
584 : :
585 : : int s2n_ecc_evp_params_free(struct s2n_ecc_evp_params *ecc_evp_params)
586 : 14246808 : {
587 [ + + ]: 14246808 : if (ecc_evp_params->evp_pkey != NULL) {
588 : 24056 : EVP_PKEY_free(ecc_evp_params->evp_pkey);
589 : 24056 : ecc_evp_params->evp_pkey = NULL;
590 : 24056 : }
591 : 14246808 : return 0;
592 : 14246808 : }
|