blob: 1236cd398bbdb34d55d0bef508530b99473b6225 [file] [log] [blame]
David Benjamin4298d772015-12-19 00:18:25 -05001/* Copyright (c) 2015, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#include <openssl/ssl.h>
16
17#include <assert.h>
18#include <string.h>
19
20#include <openssl/bn.h>
21#include <openssl/bytestring.h>
22#include <openssl/curve25519.h>
23#include <openssl/ec.h>
24#include <openssl/err.h>
25#include <openssl/mem.h>
Matt Braithwaitee25775b2016-05-16 16:31:05 -070026#include <openssl/newhope.h>
David Benjamin98193672016-03-25 18:07:11 -040027#include <openssl/nid.h>
David Benjamin4298d772015-12-19 00:18:25 -050028
29#include "internal.h"
30
31
32/* |EC_POINT| implementation. */
33
34static void ssl_ec_point_cleanup(SSL_ECDH_CTX *ctx) {
35 BIGNUM *private_key = (BIGNUM *)ctx->data;
36 BN_clear_free(private_key);
37}
38
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -070039static int ssl_ec_point_offer(SSL_ECDH_CTX *ctx, CBB *out) {
David Benjamin4298d772015-12-19 00:18:25 -050040 assert(ctx->data == NULL);
41 BIGNUM *private_key = BN_new();
42 if (private_key == NULL) {
43 return 0;
44 }
45 ctx->data = private_key;
46
47 /* Set up a shared |BN_CTX| for all operations. */
48 BN_CTX *bn_ctx = BN_CTX_new();
49 if (bn_ctx == NULL) {
50 return 0;
51 }
52 BN_CTX_start(bn_ctx);
53
54 int ret = 0;
55 EC_POINT *public_key = NULL;
56 EC_GROUP *group = EC_GROUP_new_by_curve_name(ctx->method->nid);
57 if (group == NULL) {
58 goto err;
59 }
60
61 /* Generate a private key. */
62 const BIGNUM *order = EC_GROUP_get0_order(group);
63 do {
64 if (!BN_rand_range(private_key, order)) {
65 goto err;
66 }
67 } while (BN_is_zero(private_key));
68
David Benjamin6014ea62015-12-30 21:39:34 -050069 /* Compute the corresponding public key and serialize it. */
David Benjamin4298d772015-12-19 00:18:25 -050070 public_key = EC_POINT_new(group);
71 if (public_key == NULL ||
David Benjamin6014ea62015-12-30 21:39:34 -050072 !EC_POINT_mul(group, public_key, private_key, NULL, NULL, bn_ctx) ||
73 !EC_POINT_point2cbb(out, group, public_key, POINT_CONVERSION_UNCOMPRESSED,
74 bn_ctx)) {
David Benjamin4298d772015-12-19 00:18:25 -050075 goto err;
76 }
77
78 ret = 1;
79
80err:
81 EC_GROUP_free(group);
82 EC_POINT_free(public_key);
83 BN_CTX_end(bn_ctx);
84 BN_CTX_free(bn_ctx);
85 return ret;
86}
87
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -070088static int ssl_ec_point_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
89 size_t *out_secret_len, uint8_t *out_alert,
90 const uint8_t *peer_key, size_t peer_key_len) {
David Benjamin4298d772015-12-19 00:18:25 -050091 BIGNUM *private_key = (BIGNUM *)ctx->data;
92 assert(private_key != NULL);
93 *out_alert = SSL_AD_INTERNAL_ERROR;
94
95 /* Set up a shared |BN_CTX| for all operations. */
96 BN_CTX *bn_ctx = BN_CTX_new();
97 if (bn_ctx == NULL) {
98 return 0;
99 }
100 BN_CTX_start(bn_ctx);
101
102 int ret = 0;
103 EC_GROUP *group = EC_GROUP_new_by_curve_name(ctx->method->nid);
104 EC_POINT *peer_point = NULL, *result = NULL;
105 uint8_t *secret = NULL;
106 if (group == NULL) {
107 goto err;
108 }
109
110 /* Compute the x-coordinate of |peer_key| * |private_key|. */
111 peer_point = EC_POINT_new(group);
112 result = EC_POINT_new(group);
113 if (peer_point == NULL || result == NULL) {
114 goto err;
115 }
116 BIGNUM *x = BN_CTX_get(bn_ctx);
117 if (x == NULL) {
118 goto err;
119 }
120 if (!EC_POINT_oct2point(group, peer_point, peer_key, peer_key_len, bn_ctx)) {
121 *out_alert = SSL_AD_DECODE_ERROR;
122 goto err;
123 }
124 if (!EC_POINT_mul(group, result, NULL, peer_point, private_key, bn_ctx) ||
125 !EC_POINT_get_affine_coordinates_GFp(group, result, x, NULL, bn_ctx)) {
126 goto err;
127 }
128
129 /* Encode the x-coordinate left-padded with zeros. */
130 size_t secret_len = (EC_GROUP_get_degree(group) + 7) / 8;
131 secret = OPENSSL_malloc(secret_len);
132 if (secret == NULL || !BN_bn2bin_padded(secret, secret_len, x)) {
133 goto err;
134 }
135
136 *out_secret = secret;
137 *out_secret_len = secret_len;
138 secret = NULL;
139 ret = 1;
140
141err:
142 EC_GROUP_free(group);
143 EC_POINT_free(peer_point);
144 EC_POINT_free(result);
145 BN_CTX_end(bn_ctx);
146 BN_CTX_free(bn_ctx);
147 OPENSSL_free(secret);
148 return ret;
149}
150
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700151static int ssl_ec_point_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
152 uint8_t **out_secret, size_t *out_secret_len,
153 uint8_t *out_alert, const uint8_t *peer_key,
154 size_t peer_key_len) {
155 *out_alert = SSL_AD_INTERNAL_ERROR;
156 if (!ssl_ec_point_offer(ctx, out_public_key) ||
157 !ssl_ec_point_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
158 peer_key_len)) {
159 return 0;
160 }
161 return 1;
162}
David Benjamin4298d772015-12-19 00:18:25 -0500163
164/* X25119 implementation. */
165
166static void ssl_x25519_cleanup(SSL_ECDH_CTX *ctx) {
167 if (ctx->data == NULL) {
168 return;
169 }
170 OPENSSL_cleanse(ctx->data, 32);
171 OPENSSL_free(ctx->data);
172}
173
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700174static int ssl_x25519_offer(SSL_ECDH_CTX *ctx, CBB *out) {
David Benjamin4298d772015-12-19 00:18:25 -0500175 assert(ctx->data == NULL);
176
177 ctx->data = OPENSSL_malloc(32);
178 if (ctx->data == NULL) {
179 OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
180 return 0;
181 }
182 uint8_t public_key[32];
183 X25519_keypair(public_key, (uint8_t *)ctx->data);
184 return CBB_add_bytes(out, public_key, sizeof(public_key));
185}
186
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700187static int ssl_x25519_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
188 size_t *out_secret_len, uint8_t *out_alert,
189 const uint8_t *peer_key, size_t peer_key_len) {
David Benjamin4298d772015-12-19 00:18:25 -0500190 assert(ctx->data != NULL);
191 *out_alert = SSL_AD_INTERNAL_ERROR;
192
193 uint8_t *secret = OPENSSL_malloc(32);
194 if (secret == NULL) {
195 return 0;
196 }
197
198 if (peer_key_len != 32 ||
199 !X25519(secret, (uint8_t *)ctx->data, peer_key)) {
200 OPENSSL_free(secret);
201 *out_alert = SSL_AD_DECODE_ERROR;
202 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
203 return 0;
204 }
205
206 *out_secret = secret;
207 *out_secret_len = 32;
208 return 1;
209}
210
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700211static int ssl_x25519_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
212 uint8_t **out_secret, size_t *out_secret_len,
213 uint8_t *out_alert, const uint8_t *peer_key,
214 size_t peer_key_len) {
215 *out_alert = SSL_AD_INTERNAL_ERROR;
216 if (!ssl_x25519_offer(ctx, out_public_key) ||
217 !ssl_x25519_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
218 peer_key_len)) {
219 return 0;
220 }
221 return 1;
222}
David Benjamin4298d772015-12-19 00:18:25 -0500223
Matt Braithwaitee25775b2016-05-16 16:31:05 -0700224
225/* Combined X25119 + New Hope (post-quantum) implementation. */
226
227typedef struct {
228 uint8_t x25519_key[32];
229 NEWHOPE_POLY *newhope_sk;
230} cecpq1_data;
231
232#define CECPQ1_OFFERMSG_LENGTH (32 + NEWHOPE_OFFERMSG_LENGTH)
233#define CECPQ1_ACCEPTMSG_LENGTH (32 + NEWHOPE_ACCEPTMSG_LENGTH)
234#define CECPQ1_SECRET_LENGTH (32 + SHA256_DIGEST_LENGTH)
235
236static void ssl_cecpq1_cleanup(SSL_ECDH_CTX *ctx) {
237 if (ctx->data == NULL) {
238 return;
239 }
240 cecpq1_data *data = ctx->data;
241 NEWHOPE_POLY_free(data->newhope_sk);
242 OPENSSL_cleanse(data, sizeof(cecpq1_data));
243 OPENSSL_free(data);
244}
245
246static int ssl_cecpq1_offer(SSL_ECDH_CTX *ctx, CBB *out) {
247 assert(ctx->data == NULL);
248 cecpq1_data *data = OPENSSL_malloc(sizeof(cecpq1_data));
249 if (data == NULL) {
250 OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
251 return 0;
252 }
253 ctx->data = data;
254 data->newhope_sk = NEWHOPE_POLY_new();
255 if (data->newhope_sk == NULL) {
256 OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
257 return 0;
258 }
259
260 uint8_t x25519_public_key[32];
261 X25519_keypair(x25519_public_key, data->x25519_key);
262
263 uint8_t newhope_offermsg[NEWHOPE_OFFERMSG_LENGTH];
264 NEWHOPE_offer(newhope_offermsg, data->newhope_sk);
265
266 if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) ||
267 !CBB_add_bytes(out, newhope_offermsg, sizeof(newhope_offermsg))) {
268 return 0;
269 }
270 return 1;
271}
272
273static int ssl_cecpq1_accept(SSL_ECDH_CTX *ctx, CBB *cbb, uint8_t **out_secret,
274 size_t *out_secret_len, uint8_t *out_alert,
275 const uint8_t *peer_key, size_t peer_key_len) {
276 if (peer_key_len != CECPQ1_OFFERMSG_LENGTH) {
277 *out_alert = SSL_AD_DECODE_ERROR;
278 return 0;
279 }
280
281 *out_alert = SSL_AD_INTERNAL_ERROR;
282
283 assert(ctx->data == NULL);
284 cecpq1_data *data = OPENSSL_malloc(sizeof(cecpq1_data));
285 if (data == NULL) {
286 OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
287 return 0;
288 }
289 data->newhope_sk = NULL;
290 ctx->data = data;
291
292 uint8_t *secret = OPENSSL_malloc(CECPQ1_SECRET_LENGTH);
293 if (secret == NULL) {
294 OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
295 return 0;
296 }
297
298 /* Generate message to server, and secret key, at once. */
299
300 uint8_t x25519_public_key[32];
301 X25519_keypair(x25519_public_key, data->x25519_key);
302 if (!X25519(secret, data->x25519_key, peer_key)) {
303 *out_alert = SSL_AD_DECODE_ERROR;
304 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
305 goto err;
306 }
307
308 uint8_t newhope_acceptmsg[NEWHOPE_ACCEPTMSG_LENGTH];
309 if (!NEWHOPE_accept(secret + 32, newhope_acceptmsg, peer_key + 32,
310 NEWHOPE_OFFERMSG_LENGTH)) {
311 *out_alert = SSL_AD_DECODE_ERROR;
312 goto err;
313 }
314
315 if (!CBB_add_bytes(cbb, x25519_public_key, sizeof(x25519_public_key)) ||
316 !CBB_add_bytes(cbb, newhope_acceptmsg, sizeof(newhope_acceptmsg))) {
317 goto err;
318 }
319
320 *out_secret = secret;
321 *out_secret_len = CECPQ1_SECRET_LENGTH;
322 return 1;
323
324 err:
325 OPENSSL_cleanse(secret, CECPQ1_SECRET_LENGTH);
326 OPENSSL_free(secret);
327 return 0;
328}
329
330static int ssl_cecpq1_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
331 size_t *out_secret_len, uint8_t *out_alert,
332 const uint8_t *peer_key, size_t peer_key_len) {
333 if (peer_key_len != CECPQ1_ACCEPTMSG_LENGTH) {
334 *out_alert = SSL_AD_DECODE_ERROR;
335 return 0;
336 }
337
338 *out_alert = SSL_AD_INTERNAL_ERROR;
339
340 assert(ctx->data != NULL);
341 cecpq1_data *data = ctx->data;
342
343 uint8_t *secret = OPENSSL_malloc(CECPQ1_SECRET_LENGTH);
344 if (secret == NULL) {
345 OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
346 return 0;
347 }
348
349 if (!X25519(secret, data->x25519_key, peer_key)) {
350 *out_alert = SSL_AD_DECODE_ERROR;
351 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
352 goto err;
353 }
354
355 if (!NEWHOPE_finish(secret + 32, data->newhope_sk, peer_key + 32,
356 NEWHOPE_ACCEPTMSG_LENGTH)) {
357 *out_alert = SSL_AD_DECODE_ERROR;
358 goto err;
359 }
360
361 *out_secret = secret;
362 *out_secret_len = CECPQ1_SECRET_LENGTH;
363 return 1;
364
365 err:
366 OPENSSL_cleanse(secret, CECPQ1_SECRET_LENGTH);
367 OPENSSL_free(secret);
368 return 0;
369}
370
371
David Benjamin974c7ba2015-12-19 16:58:04 -0500372/* Legacy DHE-based implementation. */
373
374static void ssl_dhe_cleanup(SSL_ECDH_CTX *ctx) {
375 DH_free((DH *)ctx->data);
376}
377
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700378static int ssl_dhe_offer(SSL_ECDH_CTX *ctx, CBB *out) {
David Benjamin974c7ba2015-12-19 16:58:04 -0500379 DH *dh = (DH *)ctx->data;
380 /* The group must have been initialized already, but not the key. */
381 assert(dh != NULL);
382 assert(dh->priv_key == NULL);
383
384 /* Due to a bug in yaSSL, the public key must be zero padded to the size of
385 * the prime. */
386 return DH_generate_key(dh) &&
387 BN_bn2cbb_padded(out, BN_num_bytes(dh->p), dh->pub_key);
388}
389
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700390static int ssl_dhe_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
391 size_t *out_secret_len, uint8_t *out_alert,
392 const uint8_t *peer_key, size_t peer_key_len) {
David Benjamin974c7ba2015-12-19 16:58:04 -0500393 DH *dh = (DH *)ctx->data;
394 assert(dh != NULL);
395 assert(dh->priv_key != NULL);
396 *out_alert = SSL_AD_INTERNAL_ERROR;
397
398 int secret_len = 0;
399 uint8_t *secret = NULL;
400 BIGNUM *peer_point = BN_bin2bn(peer_key, peer_key_len, NULL);
401 if (peer_point == NULL) {
402 goto err;
403 }
404
405 secret = OPENSSL_malloc(DH_size(dh));
406 if (secret == NULL) {
407 goto err;
408 }
409 secret_len = DH_compute_key(secret, peer_point, dh);
410 if (secret_len <= 0) {
411 goto err;
412 }
413
414 *out_secret = secret;
415 *out_secret_len = (size_t)secret_len;
416 BN_free(peer_point);
417 return 1;
418
419err:
420 if (secret_len > 0) {
421 OPENSSL_cleanse(secret, (size_t)secret_len);
422 }
423 OPENSSL_free(secret);
424 BN_free(peer_point);
425 return 0;
426}
427
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700428static int ssl_dhe_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
429 uint8_t **out_secret, size_t *out_secret_len,
430 uint8_t *out_alert, const uint8_t *peer_key,
431 size_t peer_key_len) {
432 *out_alert = SSL_AD_INTERNAL_ERROR;
433 if (!ssl_dhe_offer(ctx, out_public_key) ||
434 !ssl_dhe_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
435 peer_key_len)) {
436 return 0;
437 }
438 return 1;
439}
440
David Benjamin974c7ba2015-12-19 16:58:04 -0500441static const SSL_ECDH_METHOD kDHEMethod = {
442 NID_undef, 0, "",
443 ssl_dhe_cleanup,
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700444 ssl_dhe_offer,
445 ssl_dhe_accept,
446 ssl_dhe_finish,
Matt Braithwaitee25775b2016-05-16 16:31:05 -0700447 CBS_get_u16_length_prefixed,
448 CBB_add_u16_length_prefixed,
David Benjamin974c7ba2015-12-19 16:58:04 -0500449};
450
David Benjamin4298d772015-12-19 00:18:25 -0500451static const SSL_ECDH_METHOD kMethods[] = {
452 {
453 NID_X9_62_prime256v1,
Steven Valdezce902a92016-05-17 11:47:53 -0400454 SSL_GROUP_SECP256R1,
David Benjamin4298d772015-12-19 00:18:25 -0500455 "P-256",
456 ssl_ec_point_cleanup,
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700457 ssl_ec_point_offer,
458 ssl_ec_point_accept,
459 ssl_ec_point_finish,
Matt Braithwaitee25775b2016-05-16 16:31:05 -0700460 CBS_get_u8_length_prefixed,
461 CBB_add_u8_length_prefixed,
David Benjamin4298d772015-12-19 00:18:25 -0500462 },
463 {
464 NID_secp384r1,
Steven Valdezce902a92016-05-17 11:47:53 -0400465 SSL_GROUP_SECP384R1,
David Benjamin4298d772015-12-19 00:18:25 -0500466 "P-384",
467 ssl_ec_point_cleanup,
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700468 ssl_ec_point_offer,
469 ssl_ec_point_accept,
470 ssl_ec_point_finish,
Matt Braithwaitee25775b2016-05-16 16:31:05 -0700471 CBS_get_u8_length_prefixed,
472 CBB_add_u8_length_prefixed,
David Benjamin4298d772015-12-19 00:18:25 -0500473 },
474 {
475 NID_secp521r1,
Steven Valdezce902a92016-05-17 11:47:53 -0400476 SSL_GROUP_SECP521R1,
David Benjamin4298d772015-12-19 00:18:25 -0500477 "P-521",
478 ssl_ec_point_cleanup,
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700479 ssl_ec_point_offer,
480 ssl_ec_point_accept,
481 ssl_ec_point_finish,
Matt Braithwaitee25775b2016-05-16 16:31:05 -0700482 CBS_get_u8_length_prefixed,
483 CBB_add_u8_length_prefixed,
David Benjamin4298d772015-12-19 00:18:25 -0500484 },
485 {
David Benjaminad004af2016-03-05 14:35:35 -0500486 NID_X25519,
Steven Valdezce902a92016-05-17 11:47:53 -0400487 SSL_GROUP_X25519,
David Benjamin4298d772015-12-19 00:18:25 -0500488 "X25519",
489 ssl_x25519_cleanup,
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700490 ssl_x25519_offer,
491 ssl_x25519_accept,
492 ssl_x25519_finish,
Matt Braithwaitee25775b2016-05-16 16:31:05 -0700493 CBS_get_u8_length_prefixed,
494 CBB_add_u8_length_prefixed,
495 },
496 {
497 NID_cecpq1,
Steven Valdezce902a92016-05-17 11:47:53 -0400498 SSL_GROUP_CECPQ1,
Matt Braithwaitee25775b2016-05-16 16:31:05 -0700499 "CECPQ1",
500 ssl_cecpq1_cleanup,
501 ssl_cecpq1_offer,
502 ssl_cecpq1_accept,
503 ssl_cecpq1_finish,
504 CBS_get_u16_length_prefixed,
505 CBB_add_u16_length_prefixed,
David Benjamin4298d772015-12-19 00:18:25 -0500506 },
507};
508
Steven Valdezce902a92016-05-17 11:47:53 -0400509static const SSL_ECDH_METHOD *method_from_group_id(uint16_t group_id) {
David Benjamin4298d772015-12-19 00:18:25 -0500510 size_t i;
511 for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); i++) {
Steven Valdezce902a92016-05-17 11:47:53 -0400512 if (kMethods[i].group_id == group_id) {
David Benjamin4298d772015-12-19 00:18:25 -0500513 return &kMethods[i];
514 }
515 }
516 return NULL;
517}
518
519static const SSL_ECDH_METHOD *method_from_nid(int nid) {
520 size_t i;
521 for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); i++) {
522 if (kMethods[i].nid == nid) {
523 return &kMethods[i];
524 }
525 }
526 return NULL;
527}
528
Steven Valdezce902a92016-05-17 11:47:53 -0400529const char* SSL_get_curve_name(uint16_t group_id) {
530 const SSL_ECDH_METHOD *method = method_from_group_id(group_id);
David Benjamin4298d772015-12-19 00:18:25 -0500531 if (method == NULL) {
532 return NULL;
533 }
534 return method->name;
535}
536
Steven Valdezce902a92016-05-17 11:47:53 -0400537int ssl_nid_to_group_id(uint16_t *out_group_id, int nid) {
David Benjamin4298d772015-12-19 00:18:25 -0500538 const SSL_ECDH_METHOD *method = method_from_nid(nid);
539 if (method == NULL) {
540 return 0;
541 }
Steven Valdezce902a92016-05-17 11:47:53 -0400542 *out_group_id = method->group_id;
David Benjamin4298d772015-12-19 00:18:25 -0500543 return 1;
544}
545
Steven Valdezce902a92016-05-17 11:47:53 -0400546int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id) {
David Benjamin4298d772015-12-19 00:18:25 -0500547 SSL_ECDH_CTX_cleanup(ctx);
548
Steven Valdezce902a92016-05-17 11:47:53 -0400549 const SSL_ECDH_METHOD *method = method_from_group_id(group_id);
David Benjamin4298d772015-12-19 00:18:25 -0500550 if (method == NULL) {
551 OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
552 return 0;
553 }
554 ctx->method = method;
555 return 1;
556}
557
David Benjamin974c7ba2015-12-19 16:58:04 -0500558void SSL_ECDH_CTX_init_for_dhe(SSL_ECDH_CTX *ctx, DH *params) {
559 SSL_ECDH_CTX_cleanup(ctx);
560
561 ctx->method = &kDHEMethod;
562 ctx->data = params;
563}
564
Matt Braithwaitee25775b2016-05-16 16:31:05 -0700565int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out) {
566 if (ctx->method == NULL) {
567 return 0;
568 }
569 return ctx->method->get_key(cbs, out);
570}
571
572int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents) {
573 if (ctx->method == NULL) {
574 return 0;
575 }
576 return ctx->method->add_key(cbb, out_contents);
577}
578
David Benjamin4298d772015-12-19 00:18:25 -0500579void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) {
580 if (ctx->method == NULL) {
581 return;
582 }
583 ctx->method->cleanup(ctx);
584 ctx->method = NULL;
585 ctx->data = NULL;
586}
587
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700588int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key) {
589 return ctx->method->offer(ctx, out_public_key);
David Benjamin4298d772015-12-19 00:18:25 -0500590}
591
Matt Braithwaitef4ce8e52016-05-16 14:27:14 -0700592int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
593 uint8_t **out_secret, size_t *out_secret_len,
594 uint8_t *out_alert, const uint8_t *peer_key,
595 size_t peer_key_len) {
596 return ctx->method->accept(ctx, out_public_key, out_secret, out_secret_len,
597 out_alert, peer_key, peer_key_len);
598}
599
600int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
601 size_t *out_secret_len, uint8_t *out_alert,
602 const uint8_t *peer_key, size_t peer_key_len) {
603 return ctx->method->finish(ctx, out_secret, out_secret_len, out_alert,
604 peer_key, peer_key_len);
David Benjamin4298d772015-12-19 00:18:25 -0500605}