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