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)
26 typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed;
27 #endif
28 
mbedtls_ecdh_grp_id(const mbedtls_ecdh_context * ctx)29 static 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 
mbedtls_ecdh_can_do(mbedtls_ecp_group_id gid)39 int 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  */
ecdh_gen_public_restartable(mbedtls_ecp_group * grp,mbedtls_mpi * d,mbedtls_ecp_point * Q,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng,mbedtls_ecp_restart_ctx * rs_ctx)54 static 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 
74 cleanup:
75     return ret;
76 }
77 
78 /*
79  * Generate public key
80  */
mbedtls_ecdh_gen_public(mbedtls_ecp_group * grp,mbedtls_mpi * d,mbedtls_ecp_point * Q,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)81 int 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  */
ecdh_compute_shared_restartable(mbedtls_ecp_group * grp,mbedtls_mpi * z,const mbedtls_ecp_point * Q,const mbedtls_mpi * d,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng,mbedtls_ecp_restart_ctx * rs_ctx)93 static 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 
115 cleanup:
116     mbedtls_ecp_point_free(&P);
117 
118     return ret;
119 }
120 
121 /*
122  * Compute shared secret (SEC1 3.3.1)
123  */
mbedtls_ecdh_compute_shared(mbedtls_ecp_group * grp,mbedtls_mpi * z,const mbedtls_ecp_point * Q,const mbedtls_mpi * d,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)124 int 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 
ecdh_init_internal(mbedtls_ecdh_context_mbed * ctx)134 static 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 
147 /*
148  * Initialize context
149  */
mbedtls_ecdh_init(mbedtls_ecdh_context * ctx)150 void mbedtls_ecdh_init(mbedtls_ecdh_context *ctx)
151 {
152 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
153     ecdh_init_internal(ctx);
154     mbedtls_ecp_point_init(&ctx->Vi);
155     mbedtls_ecp_point_init(&ctx->Vf);
156     mbedtls_mpi_init(&ctx->_d);
157 #else
158     memset(ctx, 0, sizeof(mbedtls_ecdh_context));
159 
160     ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
161 #endif
162     ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
163 #if defined(MBEDTLS_ECP_RESTARTABLE)
164     ctx->restart_enabled = 0;
165 #endif
166 }
167 
ecdh_setup_internal(mbedtls_ecdh_context_mbed * ctx,mbedtls_ecp_group_id grp_id)168 static int ecdh_setup_internal(mbedtls_ecdh_context_mbed *ctx,
169                                mbedtls_ecp_group_id grp_id)
170 {
171     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
172 
173     ret = mbedtls_ecp_group_load(&ctx->grp, grp_id);
174     if (ret != 0) {
175         return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
176     }
177 
178     return 0;
179 }
180 
181 /*
182  * Setup context
183  */
mbedtls_ecdh_setup(mbedtls_ecdh_context * ctx,mbedtls_ecp_group_id grp_id)184 int mbedtls_ecdh_setup(mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id)
185 {
186 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
187     return ecdh_setup_internal(ctx, grp_id);
188 #else
189     switch (grp_id) {
190 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
191         case MBEDTLS_ECP_DP_CURVE25519:
192             ctx->point_format = MBEDTLS_ECP_PF_COMPRESSED;
193             ctx->var = MBEDTLS_ECDH_VARIANT_EVEREST;
194             ctx->grp_id = grp_id;
195             return mbedtls_everest_setup(&ctx->ctx.everest_ecdh, grp_id);
196 #endif
197         default:
198             ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
199             ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0;
200             ctx->grp_id = grp_id;
201             ecdh_init_internal(&ctx->ctx.mbed_ecdh);
202             return ecdh_setup_internal(&ctx->ctx.mbed_ecdh, grp_id);
203     }
204 #endif
205 }
206 
ecdh_free_internal(mbedtls_ecdh_context_mbed * ctx)207 static void ecdh_free_internal(mbedtls_ecdh_context_mbed *ctx)
208 {
209     mbedtls_ecp_group_free(&ctx->grp);
210     mbedtls_mpi_free(&ctx->d);
211     mbedtls_ecp_point_free(&ctx->Q);
212     mbedtls_ecp_point_free(&ctx->Qp);
213     mbedtls_mpi_free(&ctx->z);
214 
215 #if defined(MBEDTLS_ECP_RESTARTABLE)
216     mbedtls_ecp_restart_free(&ctx->rs);
217 #endif
218 }
219 
220 #if defined(MBEDTLS_ECP_RESTARTABLE)
221 /*
222  * Enable restartable operations for context
223  */
mbedtls_ecdh_enable_restart(mbedtls_ecdh_context * ctx)224 void mbedtls_ecdh_enable_restart(mbedtls_ecdh_context *ctx)
225 {
226     ctx->restart_enabled = 1;
227 }
228 #endif
229 
230 /*
231  * Free context
232  */
mbedtls_ecdh_free(mbedtls_ecdh_context * ctx)233 void mbedtls_ecdh_free(mbedtls_ecdh_context *ctx)
234 {
235     if (ctx == NULL) {
236         return;
237     }
238 
239 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
240     mbedtls_ecp_point_free(&ctx->Vi);
241     mbedtls_ecp_point_free(&ctx->Vf);
242     mbedtls_mpi_free(&ctx->_d);
243     ecdh_free_internal(ctx);
244 #else
245     switch (ctx->var) {
246 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
247         case MBEDTLS_ECDH_VARIANT_EVEREST:
248             mbedtls_everest_free(&ctx->ctx.everest_ecdh);
249             break;
250 #endif
251         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
252             ecdh_free_internal(&ctx->ctx.mbed_ecdh);
253             break;
254         default:
255             break;
256     }
257 
258     ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
259     ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
260     ctx->grp_id = MBEDTLS_ECP_DP_NONE;
261 #endif
262 }
263 
ecdh_make_params_internal(mbedtls_ecdh_context_mbed * ctx,size_t * olen,int point_format,unsigned char * buf,size_t blen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng,int restart_enabled)264 static int ecdh_make_params_internal(mbedtls_ecdh_context_mbed *ctx,
265                                      size_t *olen, int point_format,
266                                      unsigned char *buf, size_t blen,
267                                      int (*f_rng)(void *,
268                                                   unsigned char *,
269                                                   size_t),
270                                      void *p_rng,
271                                      int restart_enabled)
272 {
273     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
274     size_t grp_len, pt_len;
275 #if defined(MBEDTLS_ECP_RESTARTABLE)
276     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
277 #endif
278 
279     if (ctx->grp.pbits == 0) {
280         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
281     }
282 
283 #if defined(MBEDTLS_ECP_RESTARTABLE)
284     if (restart_enabled) {
285         rs_ctx = &ctx->rs;
286     }
287 #else
288     (void) restart_enabled;
289 #endif
290 
291 
292 #if defined(MBEDTLS_ECP_RESTARTABLE)
293     if ((ret = ecdh_gen_public_restartable(&ctx->grp, &ctx->d, &ctx->Q,
294                                            f_rng, p_rng, rs_ctx)) != 0) {
295         return ret;
296     }
297 #else
298     if ((ret = mbedtls_ecdh_gen_public(&ctx->grp, &ctx->d, &ctx->Q,
299                                        f_rng, p_rng)) != 0) {
300         return ret;
301     }
302 #endif /* MBEDTLS_ECP_RESTARTABLE */
303 
304     if ((ret = mbedtls_ecp_tls_write_group(&ctx->grp, &grp_len, buf,
305                                            blen)) != 0) {
306         return ret;
307     }
308 
309     buf += grp_len;
310     blen -= grp_len;
311 
312     if ((ret = mbedtls_ecp_tls_write_point(&ctx->grp, &ctx->Q, point_format,
313                                            &pt_len, buf, blen)) != 0) {
314         return ret;
315     }
316 
317     *olen = grp_len + pt_len;
318     return 0;
319 }
320 
321 /*
322  * Setup and write the ServerKeyExchange parameters (RFC 4492)
323  *      struct {
324  *          ECParameters    curve_params;
325  *          ECPoint         public;
326  *      } ServerECDHParams;
327  */
mbedtls_ecdh_make_params(mbedtls_ecdh_context * ctx,size_t * olen,unsigned char * buf,size_t blen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)328 int mbedtls_ecdh_make_params(mbedtls_ecdh_context *ctx, size_t *olen,
329                              unsigned char *buf, size_t blen,
330                              int (*f_rng)(void *, unsigned char *, size_t),
331                              void *p_rng)
332 {
333     int restart_enabled = 0;
334 #if defined(MBEDTLS_ECP_RESTARTABLE)
335     restart_enabled = ctx->restart_enabled;
336 #else
337     (void) restart_enabled;
338 #endif
339 
340 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
341     return ecdh_make_params_internal(ctx, olen, ctx->point_format, buf, blen,
342                                      f_rng, p_rng, restart_enabled);
343 #else
344     switch (ctx->var) {
345 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
346         case MBEDTLS_ECDH_VARIANT_EVEREST:
347             return mbedtls_everest_make_params(&ctx->ctx.everest_ecdh, olen,
348                                                buf, blen, f_rng, p_rng);
349 #endif
350         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
351             return ecdh_make_params_internal(&ctx->ctx.mbed_ecdh, olen,
352                                              ctx->point_format, buf, blen,
353                                              f_rng, p_rng,
354                                              restart_enabled);
355         default:
356             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
357     }
358 #endif
359 }
360 
ecdh_read_params_internal(mbedtls_ecdh_context_mbed * ctx,const unsigned char ** buf,const unsigned char * end)361 static int ecdh_read_params_internal(mbedtls_ecdh_context_mbed *ctx,
362                                      const unsigned char **buf,
363                                      const unsigned char *end)
364 {
365     return mbedtls_ecp_tls_read_point(&ctx->grp, &ctx->Qp, buf,
366                                       end - *buf);
367 }
368 
369 /*
370  * Read the ServerKeyExchange parameters (RFC 4492)
371  *      struct {
372  *          ECParameters    curve_params;
373  *          ECPoint         public;
374  *      } ServerECDHParams;
375  */
mbedtls_ecdh_read_params(mbedtls_ecdh_context * ctx,const unsigned char ** buf,const unsigned char * end)376 int mbedtls_ecdh_read_params(mbedtls_ecdh_context *ctx,
377                              const unsigned char **buf,
378                              const unsigned char *end)
379 {
380     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
381     mbedtls_ecp_group_id grp_id;
382     if ((ret = mbedtls_ecp_tls_read_group_id(&grp_id, buf, end - *buf))
383         != 0) {
384         return ret;
385     }
386 
387     if ((ret = mbedtls_ecdh_setup(ctx, grp_id)) != 0) {
388         return ret;
389     }
390 
391 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
392     return ecdh_read_params_internal(ctx, buf, end);
393 #else
394     switch (ctx->var) {
395 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
396         case MBEDTLS_ECDH_VARIANT_EVEREST:
397             return mbedtls_everest_read_params(&ctx->ctx.everest_ecdh,
398                                                buf, end);
399 #endif
400         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
401             return ecdh_read_params_internal(&ctx->ctx.mbed_ecdh,
402                                              buf, end);
403         default:
404             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
405     }
406 #endif
407 }
408 
ecdh_get_params_internal(mbedtls_ecdh_context_mbed * ctx,const mbedtls_ecp_keypair * key,mbedtls_ecdh_side side)409 static int ecdh_get_params_internal(mbedtls_ecdh_context_mbed *ctx,
410                                     const mbedtls_ecp_keypair *key,
411                                     mbedtls_ecdh_side side)
412 {
413     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
414 
415     /* If it's not our key, just import the public part as Qp */
416     if (side == MBEDTLS_ECDH_THEIRS) {
417         return mbedtls_ecp_copy(&ctx->Qp, &key->Q);
418     }
419 
420     /* Our key: import public (as Q) and private parts */
421     if (side != MBEDTLS_ECDH_OURS) {
422         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
423     }
424 
425     if ((ret = mbedtls_ecp_copy(&ctx->Q, &key->Q)) != 0 ||
426         (ret = mbedtls_mpi_copy(&ctx->d, &key->d)) != 0) {
427         return ret;
428     }
429 
430     return 0;
431 }
432 
433 /*
434  * Get parameters from a keypair
435  */
mbedtls_ecdh_get_params(mbedtls_ecdh_context * ctx,const mbedtls_ecp_keypair * key,mbedtls_ecdh_side side)436 int mbedtls_ecdh_get_params(mbedtls_ecdh_context *ctx,
437                             const mbedtls_ecp_keypair *key,
438                             mbedtls_ecdh_side side)
439 {
440     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
441     if (side != MBEDTLS_ECDH_OURS && side != MBEDTLS_ECDH_THEIRS) {
442         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
443     }
444 
445     if (mbedtls_ecdh_grp_id(ctx) == MBEDTLS_ECP_DP_NONE) {
446         /* This is the first call to get_params(). Set up the context
447          * for use with the group. */
448         if ((ret = mbedtls_ecdh_setup(ctx, key->grp.id)) != 0) {
449             return ret;
450         }
451     } else {
452         /* This is not the first call to get_params(). Check that the
453          * current key's group is the same as the context's, which was set
454          * from the first key's group. */
455         if (mbedtls_ecdh_grp_id(ctx) != key->grp.id) {
456             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
457         }
458     }
459 
460 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
461     return ecdh_get_params_internal(ctx, key, side);
462 #else
463     switch (ctx->var) {
464 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
465         case MBEDTLS_ECDH_VARIANT_EVEREST:
466         {
467             mbedtls_everest_ecdh_side s = side == MBEDTLS_ECDH_OURS ?
468                                           MBEDTLS_EVEREST_ECDH_OURS :
469                                           MBEDTLS_EVEREST_ECDH_THEIRS;
470             return mbedtls_everest_get_params(&ctx->ctx.everest_ecdh,
471                                               key, s);
472         }
473 #endif
474         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
475             return ecdh_get_params_internal(&ctx->ctx.mbed_ecdh,
476                                             key, side);
477         default:
478             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
479     }
480 #endif
481 }
482 
ecdh_make_public_internal(mbedtls_ecdh_context_mbed * ctx,size_t * olen,int point_format,unsigned char * buf,size_t blen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng,int restart_enabled)483 static int ecdh_make_public_internal(mbedtls_ecdh_context_mbed *ctx,
484                                      size_t *olen, int point_format,
485                                      unsigned char *buf, size_t blen,
486                                      int (*f_rng)(void *,
487                                                   unsigned char *,
488                                                   size_t),
489                                      void *p_rng,
490                                      int restart_enabled)
491 {
492     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
493 #if defined(MBEDTLS_ECP_RESTARTABLE)
494     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
495 #endif
496 
497     if (ctx->grp.pbits == 0) {
498         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
499     }
500 
501 #if defined(MBEDTLS_ECP_RESTARTABLE)
502     if (restart_enabled) {
503         rs_ctx = &ctx->rs;
504     }
505 #else
506     (void) restart_enabled;
507 #endif
508 
509 #if defined(MBEDTLS_ECP_RESTARTABLE)
510     if ((ret = ecdh_gen_public_restartable(&ctx->grp, &ctx->d, &ctx->Q,
511                                            f_rng, p_rng, rs_ctx)) != 0) {
512         return ret;
513     }
514 #else
515     if ((ret = mbedtls_ecdh_gen_public(&ctx->grp, &ctx->d, &ctx->Q,
516                                        f_rng, p_rng)) != 0) {
517         return ret;
518     }
519 #endif /* MBEDTLS_ECP_RESTARTABLE */
520 
521     return mbedtls_ecp_tls_write_point(&ctx->grp, &ctx->Q, point_format, olen,
522                                        buf, blen);
523 }
524 
525 /*
526  * Setup and export the client public value
527  */
mbedtls_ecdh_make_public(mbedtls_ecdh_context * ctx,size_t * olen,unsigned char * buf,size_t blen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)528 int mbedtls_ecdh_make_public(mbedtls_ecdh_context *ctx, size_t *olen,
529                              unsigned char *buf, size_t blen,
530                              int (*f_rng)(void *, unsigned char *, size_t),
531                              void *p_rng)
532 {
533     int restart_enabled = 0;
534 #if defined(MBEDTLS_ECP_RESTARTABLE)
535     restart_enabled = ctx->restart_enabled;
536 #endif
537 
538 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
539     return ecdh_make_public_internal(ctx, olen, ctx->point_format, buf, blen,
540                                      f_rng, p_rng, restart_enabled);
541 #else
542     switch (ctx->var) {
543 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
544         case MBEDTLS_ECDH_VARIANT_EVEREST:
545             return mbedtls_everest_make_public(&ctx->ctx.everest_ecdh, olen,
546                                                buf, blen, f_rng, p_rng);
547 #endif
548         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
549             return ecdh_make_public_internal(&ctx->ctx.mbed_ecdh, olen,
550                                              ctx->point_format, buf, blen,
551                                              f_rng, p_rng,
552                                              restart_enabled);
553         default:
554             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
555     }
556 #endif
557 }
558 
ecdh_read_public_internal(mbedtls_ecdh_context_mbed * ctx,const unsigned char * buf,size_t blen)559 static int ecdh_read_public_internal(mbedtls_ecdh_context_mbed *ctx,
560                                      const unsigned char *buf, size_t blen)
561 {
562     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
563     const unsigned char *p = buf;
564 
565     if ((ret = mbedtls_ecp_tls_read_point(&ctx->grp, &ctx->Qp, &p,
566                                           blen)) != 0) {
567         return ret;
568     }
569 
570     if ((size_t) (p - buf) != blen) {
571         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
572     }
573 
574     return 0;
575 }
576 
577 /*
578  * Parse and import the client's public value
579  */
mbedtls_ecdh_read_public(mbedtls_ecdh_context * ctx,const unsigned char * buf,size_t blen)580 int mbedtls_ecdh_read_public(mbedtls_ecdh_context *ctx,
581                              const unsigned char *buf, size_t blen)
582 {
583 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
584     return ecdh_read_public_internal(ctx, buf, blen);
585 #else
586     switch (ctx->var) {
587 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
588         case MBEDTLS_ECDH_VARIANT_EVEREST:
589             return mbedtls_everest_read_public(&ctx->ctx.everest_ecdh,
590                                                buf, blen);
591 #endif
592         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
593             return ecdh_read_public_internal(&ctx->ctx.mbed_ecdh,
594                                              buf, blen);
595         default:
596             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
597     }
598 #endif
599 }
600 
ecdh_calc_secret_internal(mbedtls_ecdh_context_mbed * ctx,size_t * olen,unsigned char * buf,size_t blen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng,int restart_enabled)601 static int ecdh_calc_secret_internal(mbedtls_ecdh_context_mbed *ctx,
602                                      size_t *olen, unsigned char *buf,
603                                      size_t blen,
604                                      int (*f_rng)(void *,
605                                                   unsigned char *,
606                                                   size_t),
607                                      void *p_rng,
608                                      int restart_enabled)
609 {
610     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
611 #if defined(MBEDTLS_ECP_RESTARTABLE)
612     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
613 #endif
614 
615     if (ctx == NULL || ctx->grp.pbits == 0) {
616         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
617     }
618 
619 #if defined(MBEDTLS_ECP_RESTARTABLE)
620     if (restart_enabled) {
621         rs_ctx = &ctx->rs;
622     }
623 #else
624     (void) restart_enabled;
625 #endif
626 
627 #if defined(MBEDTLS_ECP_RESTARTABLE)
628     if ((ret = ecdh_compute_shared_restartable(&ctx->grp, &ctx->z, &ctx->Qp,
629                                                &ctx->d, f_rng, p_rng,
630                                                rs_ctx)) != 0) {
631         return ret;
632     }
633 #else
634     if ((ret = mbedtls_ecdh_compute_shared(&ctx->grp, &ctx->z, &ctx->Qp,
635                                            &ctx->d, f_rng, p_rng)) != 0) {
636         return ret;
637     }
638 #endif /* MBEDTLS_ECP_RESTARTABLE */
639 
640     if (mbedtls_mpi_size(&ctx->z) > blen) {
641         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
642     }
643 
644     *olen = ctx->grp.pbits / 8 + ((ctx->grp.pbits % 8) != 0);
645 
646     if (mbedtls_ecp_get_type(&ctx->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
647         return mbedtls_mpi_write_binary_le(&ctx->z, buf, *olen);
648     }
649 
650     return mbedtls_mpi_write_binary(&ctx->z, buf, *olen);
651 }
652 
653 /*
654  * Derive and export the shared secret
655  */
mbedtls_ecdh_calc_secret(mbedtls_ecdh_context * ctx,size_t * olen,unsigned char * buf,size_t blen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)656 int mbedtls_ecdh_calc_secret(mbedtls_ecdh_context *ctx, size_t *olen,
657                              unsigned char *buf, size_t blen,
658                              int (*f_rng)(void *, unsigned char *, size_t),
659                              void *p_rng)
660 {
661     int restart_enabled = 0;
662 #if defined(MBEDTLS_ECP_RESTARTABLE)
663     restart_enabled = ctx->restart_enabled;
664 #endif
665 
666 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
667     return ecdh_calc_secret_internal(ctx, olen, buf, blen, f_rng, p_rng,
668                                      restart_enabled);
669 #else
670     switch (ctx->var) {
671 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
672         case MBEDTLS_ECDH_VARIANT_EVEREST:
673             return mbedtls_everest_calc_secret(&ctx->ctx.everest_ecdh, olen,
674                                                buf, blen, f_rng, p_rng);
675 #endif
676         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
677             return ecdh_calc_secret_internal(&ctx->ctx.mbed_ecdh, olen, buf,
678                                              blen, f_rng, p_rng,
679                                              restart_enabled);
680         default:
681             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
682     }
683 #endif
684 }
685 #endif /* MBEDTLS_ECDH_C */
686