1/*
2 * Elliptic curve Diffie-Hellman
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20/*
21 * References:
22 *
23 * SEC1 https://www.secg.org/sec1-v2.pdf
24 * RFC 4492
25 */
26
27#include "common.h"
28
29#if defined(MBEDTLS_ECDH_C)
30
31#include "mbedtls/ecdh.h"
32#include "mbedtls/platform_util.h"
33#include "mbedtls/error.h"
34
35#include <string.h>
36
37/* Parameter validation macros based on platform_util.h */
38#define ECDH_VALIDATE_RET(cond) \
39 MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA)
40#define ECDH_VALIDATE(cond) \
41 MBEDTLS_INTERNAL_VALIDATE(cond)
42
43#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
44typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed;
45#endif
46
47static mbedtls_ecp_group_id mbedtls_ecdh_grp_id(
48 const mbedtls_ecdh_context *ctx)
49{
50#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
51 return ctx->grp.id;
52#else
53 return ctx->grp_id;
54#endif
55}
56
57int mbedtls_ecdh_can_do(mbedtls_ecp_group_id gid)
58{
59 /* At this time, all groups support ECDH. */
60 (void) gid;
61 return 1;
62}
63
64#if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)
65/*
66 * Generate public key (restartable version)
67 *
68 * Note: this internal function relies on its caller preserving the value of
69 * the output parameter 'd' across continuation calls. This would not be
70 * acceptable for a public function but is OK here as we control call sites.
71 */
72static int ecdh_gen_public_restartable(mbedtls_ecp_group *grp,
73 mbedtls_mpi *d, mbedtls_ecp_point *Q,
74 int (*f_rng)(void *, unsigned char *, size_t),
75 void *p_rng,
76 mbedtls_ecp_restart_ctx *rs_ctx)
77{
78 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
79
80 int restarting = 0;
81#if defined(MBEDTLS_ECP_RESTARTABLE)
82 restarting = (rs_ctx != NULL && rs_ctx->rsm != NULL);
83#endif
84 /* If multiplication is in progress, we already generated a privkey */
85 if (!restarting) {
86 MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, d, f_rng, p_rng));
87 }
88
89 MBEDTLS_MPI_CHK(mbedtls_ecp_mul_restartable(grp, Q, d, &grp->G,
90 f_rng, p_rng, rs_ctx));
91
92cleanup:
93 return ret;
94}
95
96/*
97 * Generate public key
98 */
99int mbedtls_ecdh_gen_public(mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,
100 int (*f_rng)(void *, unsigned char *, size_t),
101 void *p_rng)
102{
103 ECDH_VALIDATE_RET(grp != NULL);
104 ECDH_VALIDATE_RET(d != NULL);
105 ECDH_VALIDATE_RET(Q != NULL);
106 ECDH_VALIDATE_RET(f_rng != NULL);
107 return ecdh_gen_public_restartable(grp, d, Q, f_rng, p_rng, NULL);
108}
109#endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */
110
111#if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT)
112/*
113 * Compute shared secret (SEC1 3.3.1)
114 */
115static int ecdh_compute_shared_restartable(mbedtls_ecp_group *grp,
116 mbedtls_mpi *z,
117 const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
118 int (*f_rng)(void *, unsigned char *, size_t),
119 void *p_rng,
120 mbedtls_ecp_restart_ctx *rs_ctx)
121{
122 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
123 mbedtls_ecp_point P;
124
125 mbedtls_ecp_point_init(&P);
126
127 MBEDTLS_MPI_CHK(mbedtls_ecp_mul_restartable(grp, &P, d, Q,
128 f_rng, p_rng, rs_ctx));
129
130 if (mbedtls_ecp_is_zero(&P)) {
131 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
132 goto cleanup;
133 }
134
135 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(z, &P.X));
136
137cleanup:
138 mbedtls_ecp_point_free(&P);
139
140 return ret;
141}
142
143/*
144 * Compute shared secret (SEC1 3.3.1)
145 */
146int mbedtls_ecdh_compute_shared(mbedtls_ecp_group *grp, mbedtls_mpi *z,
147 const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
148 int (*f_rng)(void *, unsigned char *, size_t),
149 void *p_rng)
150{
151 ECDH_VALIDATE_RET(grp != NULL);
152 ECDH_VALIDATE_RET(Q != NULL);
153 ECDH_VALIDATE_RET(d != NULL);
154 ECDH_VALIDATE_RET(z != NULL);
155 return ecdh_compute_shared_restartable(grp, z, Q, d,
156 f_rng, p_rng, NULL);
157}
158#endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
159
160static void ecdh_init_internal(mbedtls_ecdh_context_mbed *ctx)
161{
162 mbedtls_ecp_group_init(&ctx->grp);
163 mbedtls_mpi_init(&ctx->d);
164 mbedtls_ecp_point_init(&ctx->Q);
165 mbedtls_ecp_point_init(&ctx->Qp);
166 mbedtls_mpi_init(&ctx->z);
167
168#if defined(MBEDTLS_ECP_RESTARTABLE)
169 mbedtls_ecp_restart_init(&ctx->rs);
170#endif
171}
172
173/*
174 * Initialize context
175 */
176void mbedtls_ecdh_init(mbedtls_ecdh_context *ctx)
177{
178 ECDH_VALIDATE(ctx != NULL);
179
180#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
181 ecdh_init_internal(ctx);
182 mbedtls_ecp_point_init(&ctx->Vi);
183 mbedtls_ecp_point_init(&ctx->Vf);
184 mbedtls_mpi_init(&ctx->_d);
185#else
186 memset(ctx, 0, sizeof(mbedtls_ecdh_context));
187
188 ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
189#endif
190 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
191#if defined(MBEDTLS_ECP_RESTARTABLE)
192 ctx->restart_enabled = 0;
193#endif
194}
195
196static int ecdh_setup_internal(mbedtls_ecdh_context_mbed *ctx,
197 mbedtls_ecp_group_id grp_id)
198{
199 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
200
201 ret = mbedtls_ecp_group_load(&ctx->grp, grp_id);
202 if (ret != 0) {
203 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
204 }
205
206 return 0;
207}
208
209/*
210 * Setup context
211 */
212int mbedtls_ecdh_setup(mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id)
213{
214 ECDH_VALIDATE_RET(ctx != NULL);
215
216#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
217 return ecdh_setup_internal(ctx, grp_id);
218#else
219 switch (grp_id) {
220#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
221 case MBEDTLS_ECP_DP_CURVE25519:
222 ctx->point_format = MBEDTLS_ECP_PF_COMPRESSED;
223 ctx->var = MBEDTLS_ECDH_VARIANT_EVEREST;
224 ctx->grp_id = grp_id;
225 return mbedtls_everest_setup(&ctx->ctx.everest_ecdh, grp_id);
226#endif
227 default:
228 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
229 ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0;
230 ctx->grp_id = grp_id;
231 ecdh_init_internal(&ctx->ctx.mbed_ecdh);
232 return ecdh_setup_internal(&ctx->ctx.mbed_ecdh, grp_id);
233 }
234#endif
235}
236
237static void ecdh_free_internal(mbedtls_ecdh_context_mbed *ctx)
238{
239 mbedtls_ecp_group_free(&ctx->grp);
240 mbedtls_mpi_free(&ctx->d);
241 mbedtls_ecp_point_free(&ctx->Q);
242 mbedtls_ecp_point_free(&ctx->Qp);
243 mbedtls_mpi_free(&ctx->z);
244
245#if defined(MBEDTLS_ECP_RESTARTABLE)
246 mbedtls_ecp_restart_free(&ctx->rs);
247#endif
248}
249
250#if defined(MBEDTLS_ECP_RESTARTABLE)
251/*
252 * Enable restartable operations for context
253 */
254void mbedtls_ecdh_enable_restart(mbedtls_ecdh_context *ctx)
255{
256 ECDH_VALIDATE(ctx != NULL);
257
258 ctx->restart_enabled = 1;
259}
260#endif
261
262/*
263 * Free context
264 */
265void mbedtls_ecdh_free(mbedtls_ecdh_context *ctx)
266{
267 if (ctx == NULL) {
268 return;
269 }
270
271#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
272 mbedtls_ecp_point_free(&ctx->Vi);
273 mbedtls_ecp_point_free(&ctx->Vf);
274 mbedtls_mpi_free(&ctx->_d);
275 ecdh_free_internal(ctx);
276#else
277 switch (ctx->var) {
278#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
279 case MBEDTLS_ECDH_VARIANT_EVEREST:
280 mbedtls_everest_free(&ctx->ctx.everest_ecdh);
281 break;
282#endif
283 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
284 ecdh_free_internal(&ctx->ctx.mbed_ecdh);
285 break;
286 default:
287 break;
288 }
289
290 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
291 ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
292 ctx->grp_id = MBEDTLS_ECP_DP_NONE;
293#endif
294}
295
296static int ecdh_make_params_internal(mbedtls_ecdh_context_mbed *ctx,
297 size_t *olen, int point_format,
298 unsigned char *buf, size_t blen,
299 int (*f_rng)(void *,
300 unsigned char *,
301 size_t),
302 void *p_rng,
303 int restart_enabled)
304{
305 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
306 size_t grp_len, pt_len;
307#if defined(MBEDTLS_ECP_RESTARTABLE)
308 mbedtls_ecp_restart_ctx *rs_ctx = NULL;
309#endif
310
311 if (ctx->grp.pbits == 0) {
312 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
313 }
314
315#if defined(MBEDTLS_ECP_RESTARTABLE)
316 if (restart_enabled) {
317 rs_ctx = &ctx->rs;
318 }
319#else
320 (void) restart_enabled;
321#endif
322
323
324#if defined(MBEDTLS_ECP_RESTARTABLE)
325 if ((ret = ecdh_gen_public_restartable(&ctx->grp, &ctx->d, &ctx->Q,
326 f_rng, p_rng, rs_ctx)) != 0) {
327 return ret;
328 }
329#else
330 if ((ret = mbedtls_ecdh_gen_public(&ctx->grp, &ctx->d, &ctx->Q,
331 f_rng, p_rng)) != 0) {
332 return ret;
333 }
334#endif /* MBEDTLS_ECP_RESTARTABLE */
335
336 if ((ret = mbedtls_ecp_tls_write_group(&ctx->grp, &grp_len, buf,
337 blen)) != 0) {
338 return ret;
339 }
340
341 buf += grp_len;
342 blen -= grp_len;
343
344 if ((ret = mbedtls_ecp_tls_write_point(&ctx->grp, &ctx->Q, point_format,
345 &pt_len, buf, blen)) != 0) {
346 return ret;
347 }
348
349 *olen = grp_len + pt_len;
350 return 0;
351}
352
353/*
354 * Setup and write the ServerKeyExchange parameters (RFC 4492)
355 * struct {
356 * ECParameters curve_params;
357 * ECPoint public;
358 * } ServerECDHParams;
359 */
360int mbedtls_ecdh_make_params(mbedtls_ecdh_context *ctx, size_t *olen,
361 unsigned char *buf, size_t blen,
362 int (*f_rng)(void *, unsigned char *, size_t),
363 void *p_rng)
364{
365 int restart_enabled = 0;
366 ECDH_VALIDATE_RET(ctx != NULL);
367 ECDH_VALIDATE_RET(olen != NULL);
368 ECDH_VALIDATE_RET(buf != NULL);
369 ECDH_VALIDATE_RET(f_rng != NULL);
370
371#if defined(MBEDTLS_ECP_RESTARTABLE)
372 restart_enabled = ctx->restart_enabled;
373#else
374 (void) restart_enabled;
375#endif
376
377#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
378 return ecdh_make_params_internal(ctx, olen, ctx->point_format, buf, blen,
379 f_rng, p_rng, restart_enabled);
380#else
381 switch (ctx->var) {
382#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
383 case MBEDTLS_ECDH_VARIANT_EVEREST:
384 return mbedtls_everest_make_params(&ctx->ctx.everest_ecdh, olen,
385 buf, blen, f_rng, p_rng);
386#endif
387 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
388 return ecdh_make_params_internal(&ctx->ctx.mbed_ecdh, olen,
389 ctx->point_format, buf, blen,
390 f_rng, p_rng,
391 restart_enabled);
392 default:
393 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
394 }
395#endif
396}
397
398static int ecdh_read_params_internal(mbedtls_ecdh_context_mbed *ctx,
399 const unsigned char **buf,
400 const unsigned char *end)
401{
402 return mbedtls_ecp_tls_read_point(&ctx->grp, &ctx->Qp, buf,
403 end - *buf);
404}
405
406/*
407 * Read the ServerKeyExchange parameters (RFC 4492)
408 * struct {
409 * ECParameters curve_params;
410 * ECPoint public;
411 * } ServerECDHParams;
412 */
413int mbedtls_ecdh_read_params(mbedtls_ecdh_context *ctx,
414 const unsigned char **buf,
415 const unsigned char *end)
416{
417 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
418 mbedtls_ecp_group_id grp_id;
419 ECDH_VALIDATE_RET(ctx != NULL);
420 ECDH_VALIDATE_RET(buf != NULL);
421 ECDH_VALIDATE_RET(*buf != NULL);
422 ECDH_VALIDATE_RET(end != NULL);
423
424 if ((ret = mbedtls_ecp_tls_read_group_id(&grp_id, buf, end - *buf))
425 != 0) {
426 return ret;
427 }
428
429 if ((ret = mbedtls_ecdh_setup(ctx, grp_id)) != 0) {
430 return ret;
431 }
432
433#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
434 return ecdh_read_params_internal(ctx, buf, end);
435#else
436 switch (ctx->var) {
437#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
438 case MBEDTLS_ECDH_VARIANT_EVEREST:
439 return mbedtls_everest_read_params(&ctx->ctx.everest_ecdh,
440 buf, end);
441#endif
442 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
443 return ecdh_read_params_internal(&ctx->ctx.mbed_ecdh,
444 buf, end);
445 default:
446 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
447 }
448#endif
449}
450
451static int ecdh_get_params_internal(mbedtls_ecdh_context_mbed *ctx,
452 const mbedtls_ecp_keypair *key,
453 mbedtls_ecdh_side side)
454{
455 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
456
457 /* If it's not our key, just import the public part as Qp */
458 if (side == MBEDTLS_ECDH_THEIRS) {
459 return mbedtls_ecp_copy(&ctx->Qp, &key->Q);
460 }
461
462 /* Our key: import public (as Q) and private parts */
463 if (side != MBEDTLS_ECDH_OURS) {
464 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
465 }
466
467 if ((ret = mbedtls_ecp_copy(&ctx->Q, &key->Q)) != 0 ||
468 (ret = mbedtls_mpi_copy(&ctx->d, &key->d)) != 0) {
469 return ret;
470 }
471
472 return 0;
473}
474
475/*
476 * Get parameters from a keypair
477 */
478int mbedtls_ecdh_get_params(mbedtls_ecdh_context *ctx,
479 const mbedtls_ecp_keypair *key,
480 mbedtls_ecdh_side side)
481{
482 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
483 ECDH_VALIDATE_RET(ctx != NULL);
484 ECDH_VALIDATE_RET(key != NULL);
485 ECDH_VALIDATE_RET(side == MBEDTLS_ECDH_OURS ||
486 side == MBEDTLS_ECDH_THEIRS);
487
488 if (mbedtls_ecdh_grp_id(ctx) == MBEDTLS_ECP_DP_NONE) {
489 /* This is the first call to get_params(). Set up the context
490 * for use with the group. */
491 if ((ret = mbedtls_ecdh_setup(ctx, key->grp.id)) != 0) {
492 return ret;
493 }
494 } else {
495 /* This is not the first call to get_params(). Check that the
496 * current key's group is the same as the context's, which was set
497 * from the first key's group. */
498 if (mbedtls_ecdh_grp_id(ctx) != key->grp.id) {
499 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
500 }
501 }
502
503#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
504 return ecdh_get_params_internal(ctx, key, side);
505#else
506 switch (ctx->var) {
507#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
508 case MBEDTLS_ECDH_VARIANT_EVEREST:
509 {
510 mbedtls_everest_ecdh_side s = side == MBEDTLS_ECDH_OURS ?
511 MBEDTLS_EVEREST_ECDH_OURS :
512 MBEDTLS_EVEREST_ECDH_THEIRS;
513 return mbedtls_everest_get_params(&ctx->ctx.everest_ecdh,
514 key, s);
515 }
516#endif
517 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
518 return ecdh_get_params_internal(&ctx->ctx.mbed_ecdh,
519 key, side);
520 default:
521 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
522 }
523#endif
524}
525
526static int ecdh_make_public_internal(mbedtls_ecdh_context_mbed *ctx,
527 size_t *olen, int point_format,
528 unsigned char *buf, size_t blen,
529 int (*f_rng)(void *,
530 unsigned char *,
531 size_t),
532 void *p_rng,
533 int restart_enabled)
534{
535 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
536#if defined(MBEDTLS_ECP_RESTARTABLE)
537 mbedtls_ecp_restart_ctx *rs_ctx = NULL;
538#endif
539
540 if (ctx->grp.pbits == 0) {
541 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
542 }
543
544#if defined(MBEDTLS_ECP_RESTARTABLE)
545 if (restart_enabled) {
546 rs_ctx = &ctx->rs;
547 }
548#else
549 (void) restart_enabled;
550#endif
551
552#if defined(MBEDTLS_ECP_RESTARTABLE)
553 if ((ret = ecdh_gen_public_restartable(&ctx->grp, &ctx->d, &ctx->Q,
554 f_rng, p_rng, rs_ctx)) != 0) {
555 return ret;
556 }
557#else
558 if ((ret = mbedtls_ecdh_gen_public(&ctx->grp, &ctx->d, &ctx->Q,
559 f_rng, p_rng)) != 0) {
560 return ret;
561 }
562#endif /* MBEDTLS_ECP_RESTARTABLE */
563
564 return mbedtls_ecp_tls_write_point(&ctx->grp, &ctx->Q, point_format, olen,
565 buf, blen);
566}
567
568/*
569 * Setup and export the client public value
570 */
571int mbedtls_ecdh_make_public(mbedtls_ecdh_context *ctx, size_t *olen,
572 unsigned char *buf, size_t blen,
573 int (*f_rng)(void *, unsigned char *, size_t),
574 void *p_rng)
575{
576 int restart_enabled = 0;
577 ECDH_VALIDATE_RET(ctx != NULL);
578 ECDH_VALIDATE_RET(olen != NULL);
579 ECDH_VALIDATE_RET(buf != NULL);
580 ECDH_VALIDATE_RET(f_rng != NULL);
581
582#if defined(MBEDTLS_ECP_RESTARTABLE)
583 restart_enabled = ctx->restart_enabled;
584#endif
585
586#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
587 return ecdh_make_public_internal(ctx, olen, ctx->point_format, buf, blen,
588 f_rng, p_rng, restart_enabled);
589#else
590 switch (ctx->var) {
591#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
592 case MBEDTLS_ECDH_VARIANT_EVEREST:
593 return mbedtls_everest_make_public(&ctx->ctx.everest_ecdh, olen,
594 buf, blen, f_rng, p_rng);
595#endif
596 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
597 return ecdh_make_public_internal(&ctx->ctx.mbed_ecdh, olen,
598 ctx->point_format, buf, blen,
599 f_rng, p_rng,
600 restart_enabled);
601 default:
602 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
603 }
604#endif
605}
606
607static int ecdh_read_public_internal(mbedtls_ecdh_context_mbed *ctx,
608 const unsigned char *buf, size_t blen)
609{
610 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
611 const unsigned char *p = buf;
612
613 if ((ret = mbedtls_ecp_tls_read_point(&ctx->grp, &ctx->Qp, &p,
614 blen)) != 0) {
615 return ret;
616 }
617
618 if ((size_t) (p - buf) != blen) {
619 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
620 }
621
622 return 0;
623}
624
625/*
626 * Parse and import the client's public value
627 */
628int mbedtls_ecdh_read_public(mbedtls_ecdh_context *ctx,
629 const unsigned char *buf, size_t blen)
630{
631 ECDH_VALIDATE_RET(ctx != NULL);
632 ECDH_VALIDATE_RET(buf != NULL);
633
634#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
635 return ecdh_read_public_internal(ctx, buf, blen);
636#else
637 switch (ctx->var) {
638#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
639 case MBEDTLS_ECDH_VARIANT_EVEREST:
640 return mbedtls_everest_read_public(&ctx->ctx.everest_ecdh,
641 buf, blen);
642#endif
643 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
644 return ecdh_read_public_internal(&ctx->ctx.mbed_ecdh,
645 buf, blen);
646 default:
647 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
648 }
649#endif
650}
651
652static int ecdh_calc_secret_internal(mbedtls_ecdh_context_mbed *ctx,
653 size_t *olen, unsigned char *buf,
654 size_t blen,
655 int (*f_rng)(void *,
656 unsigned char *,
657 size_t),
658 void *p_rng,
659 int restart_enabled)
660{
661 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
662#if defined(MBEDTLS_ECP_RESTARTABLE)
663 mbedtls_ecp_restart_ctx *rs_ctx = NULL;
664#endif
665
666 if (ctx == NULL || ctx->grp.pbits == 0) {
667 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
668 }
669
670#if defined(MBEDTLS_ECP_RESTARTABLE)
671 if (restart_enabled) {
672 rs_ctx = &ctx->rs;
673 }
674#else
675 (void) restart_enabled;
676#endif
677
678#if defined(MBEDTLS_ECP_RESTARTABLE)
679 if ((ret = ecdh_compute_shared_restartable(&ctx->grp, &ctx->z, &ctx->Qp,
680 &ctx->d, f_rng, p_rng,
681 rs_ctx)) != 0) {
682 return ret;
683 }
684#else
685 if ((ret = mbedtls_ecdh_compute_shared(&ctx->grp, &ctx->z, &ctx->Qp,
686 &ctx->d, f_rng, p_rng)) != 0) {
687 return ret;
688 }
689#endif /* MBEDTLS_ECP_RESTARTABLE */
690
691 if (mbedtls_mpi_size(&ctx->z) > blen) {
692 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
693 }
694
695 *olen = ctx->grp.pbits / 8 + ((ctx->grp.pbits % 8) != 0);
696
697 if (mbedtls_ecp_get_type(&ctx->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
698 return mbedtls_mpi_write_binary_le(&ctx->z, buf, *olen);
699 }
700
701 return mbedtls_mpi_write_binary(&ctx->z, buf, *olen);
702}
703
704/*
705 * Derive and export the shared secret
706 */
707int mbedtls_ecdh_calc_secret(mbedtls_ecdh_context *ctx, size_t *olen,
708 unsigned char *buf, size_t blen,
709 int (*f_rng)(void *, unsigned char *, size_t),
710 void *p_rng)
711{
712 int restart_enabled = 0;
713 ECDH_VALIDATE_RET(ctx != NULL);
714 ECDH_VALIDATE_RET(olen != NULL);
715 ECDH_VALIDATE_RET(buf != NULL);
716
717#if defined(MBEDTLS_ECP_RESTARTABLE)
718 restart_enabled = ctx->restart_enabled;
719#endif
720
721#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
722 return ecdh_calc_secret_internal(ctx, olen, buf, blen, f_rng, p_rng,
723 restart_enabled);
724#else
725 switch (ctx->var) {
726#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
727 case MBEDTLS_ECDH_VARIANT_EVEREST:
728 return mbedtls_everest_calc_secret(&ctx->ctx.everest_ecdh, olen,
729 buf, blen, f_rng, p_rng);
730#endif
731 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
732 return ecdh_calc_secret_internal(&ctx->ctx.mbed_ecdh, olen, buf,
733 blen, f_rng, p_rng,
734 restart_enabled);
735 default:
736 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
737 }
738#endif
739}
740
741#endif /* MBEDTLS_ECDH_C */
742