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