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