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 http://www.secg.org/index.php?action=secg,docs_secg
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)
44 typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed;
45 #endif
46 
mbedtls_ecdh_grp_id(const mbedtls_ecdh_context * ctx)47 static 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 
mbedtls_ecdh_can_do(mbedtls_ecp_group_id gid)57 int 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  */
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)72 static 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     /* If multiplication is in progress, we already generated a privkey */
81 #if defined(MBEDTLS_ECP_RESTARTABLE)
82     if( rs_ctx == NULL || rs_ctx->rsm == NULL )
83 #endif
84         MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) );
85 
86     MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G,
87                                                   f_rng, p_rng, rs_ctx ) );
88 
89 cleanup:
90     return( ret );
91 }
92 
93 /*
94  * Generate public key
95  */
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)96 int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,
97                      int (*f_rng)(void *, unsigned char *, size_t),
98                      void *p_rng )
99 {
100     ECDH_VALIDATE_RET( grp != NULL );
101     ECDH_VALIDATE_RET( d != NULL );
102     ECDH_VALIDATE_RET( Q != NULL );
103     ECDH_VALIDATE_RET( f_rng != NULL );
104     return( ecdh_gen_public_restartable( grp, d, Q, f_rng, p_rng, NULL ) );
105 }
106 #endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */
107 
108 #if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT)
109 /*
110  * Compute shared secret (SEC1 3.3.1)
111  */
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)112 static int ecdh_compute_shared_restartable( mbedtls_ecp_group *grp,
113                          mbedtls_mpi *z,
114                          const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
115                          int (*f_rng)(void *, unsigned char *, size_t),
116                          void *p_rng,
117                          mbedtls_ecp_restart_ctx *rs_ctx )
118 {
119     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
120     mbedtls_ecp_point P;
121 
122     mbedtls_ecp_point_init( &P );
123 
124     MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &P, d, Q,
125                                                   f_rng, p_rng, rs_ctx ) );
126 
127     if( mbedtls_ecp_is_zero( &P ) )
128     {
129         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
130         goto cleanup;
131     }
132 
133     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) );
134 
135 cleanup:
136     mbedtls_ecp_point_free( &P );
137 
138     return( ret );
139 }
140 
141 /*
142  * Compute shared secret (SEC1 3.3.1)
143  */
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)144 int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,
145                          const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
146                          int (*f_rng)(void *, unsigned char *, size_t),
147                          void *p_rng )
148 {
149     ECDH_VALIDATE_RET( grp != NULL );
150     ECDH_VALIDATE_RET( Q != NULL );
151     ECDH_VALIDATE_RET( d != NULL );
152     ECDH_VALIDATE_RET( z != NULL );
153     return( ecdh_compute_shared_restartable( grp, z, Q, d,
154                                              f_rng, p_rng, NULL ) );
155 }
156 #endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
157 
ecdh_init_internal(mbedtls_ecdh_context_mbed * ctx)158 static void ecdh_init_internal( mbedtls_ecdh_context_mbed *ctx )
159 {
160     mbedtls_ecp_group_init( &ctx->grp );
161     mbedtls_mpi_init( &ctx->d  );
162     mbedtls_ecp_point_init( &ctx->Q   );
163     mbedtls_ecp_point_init( &ctx->Qp  );
164     mbedtls_mpi_init( &ctx->z  );
165 
166 #if defined(MBEDTLS_ECP_RESTARTABLE)
167     mbedtls_ecp_restart_init( &ctx->rs );
168 #endif
169 }
170 
171 /*
172  * Initialize context
173  */
mbedtls_ecdh_init(mbedtls_ecdh_context * ctx)174 void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx )
175 {
176     ECDH_VALIDATE( ctx != NULL );
177 
178 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
179     ecdh_init_internal( ctx );
180     mbedtls_ecp_point_init( &ctx->Vi  );
181     mbedtls_ecp_point_init( &ctx->Vf  );
182     mbedtls_mpi_init( &ctx->_d );
183 #else
184     memset( ctx, 0, sizeof( mbedtls_ecdh_context ) );
185 
186     ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
187 #endif
188     ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
189 #if defined(MBEDTLS_ECP_RESTARTABLE)
190     ctx->restart_enabled = 0;
191 #endif
192 }
193 
ecdh_setup_internal(mbedtls_ecdh_context_mbed * ctx,mbedtls_ecp_group_id grp_id)194 static int ecdh_setup_internal( mbedtls_ecdh_context_mbed *ctx,
195                                 mbedtls_ecp_group_id grp_id )
196 {
197     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
198 
199     ret = mbedtls_ecp_group_load( &ctx->grp, grp_id );
200     if( ret != 0 )
201     {
202         return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
203     }
204 
205     return( 0 );
206 }
207 
208 /*
209  * Setup context
210  */
mbedtls_ecdh_setup(mbedtls_ecdh_context * ctx,mbedtls_ecp_group_id grp_id)211 int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id )
212 {
213     ECDH_VALIDATE_RET( ctx != NULL );
214 
215 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
216     return( ecdh_setup_internal( ctx, grp_id ) );
217 #else
218     switch( grp_id )
219     {
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 
ecdh_free_internal(mbedtls_ecdh_context_mbed * ctx)237 static 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  */
mbedtls_ecdh_enable_restart(mbedtls_ecdh_context * ctx)254 void 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  */
mbedtls_ecdh_free(mbedtls_ecdh_context * ctx)265 void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx )
266 {
267     if( ctx == NULL )
268         return;
269 
270 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
271     mbedtls_ecp_point_free( &ctx->Vi );
272     mbedtls_ecp_point_free( &ctx->Vf );
273     mbedtls_mpi_free( &ctx->_d );
274     ecdh_free_internal( ctx );
275 #else
276     switch( ctx->var )
277     {
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 
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)296 static 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 #if defined(MBEDTLS_ECP_RESTARTABLE)
315     if( restart_enabled )
316         rs_ctx = &ctx->rs;
317 #else
318     (void) restart_enabled;
319 #endif
320 
321 
322 #if defined(MBEDTLS_ECP_RESTARTABLE)
323     if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
324                                              f_rng, p_rng, rs_ctx ) ) != 0 )
325         return( ret );
326 #else
327     if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
328                                          f_rng, p_rng ) ) != 0 )
329         return( ret );
330 #endif /* MBEDTLS_ECP_RESTARTABLE */
331 
332     if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf,
333                                              blen ) ) != 0 )
334         return( ret );
335 
336     buf += grp_len;
337     blen -= grp_len;
338 
339     if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format,
340                                              &pt_len, buf, blen ) ) != 0 )
341         return( ret );
342 
343     *olen = grp_len + pt_len;
344     return( 0 );
345 }
346 
347 /*
348  * Setup and write the ServerKeyExchange parameters (RFC 4492)
349  *      struct {
350  *          ECParameters    curve_params;
351  *          ECPoint         public;
352  *      } ServerECDHParams;
353  */
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)354 int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
355                               unsigned char *buf, size_t blen,
356                               int (*f_rng)(void *, unsigned char *, size_t),
357                               void *p_rng )
358 {
359     int restart_enabled = 0;
360     ECDH_VALIDATE_RET( ctx != NULL );
361     ECDH_VALIDATE_RET( olen != NULL );
362     ECDH_VALIDATE_RET( buf != NULL );
363     ECDH_VALIDATE_RET( f_rng != NULL );
364 
365 #if defined(MBEDTLS_ECP_RESTARTABLE)
366     restart_enabled = ctx->restart_enabled;
367 #else
368     (void) restart_enabled;
369 #endif
370 
371 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
372     return( ecdh_make_params_internal( ctx, olen, ctx->point_format, buf, blen,
373                                        f_rng, p_rng, restart_enabled ) );
374 #else
375     switch( ctx->var )
376     {
377 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
378         case MBEDTLS_ECDH_VARIANT_EVEREST:
379             return( mbedtls_everest_make_params( &ctx->ctx.everest_ecdh, olen,
380                                                  buf, blen, f_rng, p_rng ) );
381 #endif
382         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
383             return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen,
384                                                ctx->point_format, buf, blen,
385                                                f_rng, p_rng,
386                                                restart_enabled ) );
387         default:
388             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
389     }
390 #endif
391 }
392 
ecdh_read_params_internal(mbedtls_ecdh_context_mbed * ctx,const unsigned char ** buf,const unsigned char * end)393 static int ecdh_read_params_internal( mbedtls_ecdh_context_mbed *ctx,
394                                       const unsigned char **buf,
395                                       const unsigned char *end )
396 {
397     return( mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf,
398                                         end - *buf ) );
399 }
400 
401 /*
402  * Read the ServerKeyExhange parameters (RFC 4492)
403  *      struct {
404  *          ECParameters    curve_params;
405  *          ECPoint         public;
406  *      } ServerECDHParams;
407  */
mbedtls_ecdh_read_params(mbedtls_ecdh_context * ctx,const unsigned char ** buf,const unsigned char * end)408 int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx,
409                               const unsigned char **buf,
410                               const unsigned char *end )
411 {
412     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
413     mbedtls_ecp_group_id grp_id;
414     ECDH_VALIDATE_RET( ctx != NULL );
415     ECDH_VALIDATE_RET( buf != NULL );
416     ECDH_VALIDATE_RET( *buf != NULL );
417     ECDH_VALIDATE_RET( end != NULL );
418 
419     if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, end - *buf ) )
420             != 0 )
421         return( ret );
422 
423     if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 )
424         return( ret );
425 
426 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
427     return( ecdh_read_params_internal( ctx, buf, end ) );
428 #else
429     switch( ctx->var )
430     {
431 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
432         case MBEDTLS_ECDH_VARIANT_EVEREST:
433             return( mbedtls_everest_read_params( &ctx->ctx.everest_ecdh,
434                                                  buf, end) );
435 #endif
436         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
437             return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh,
438                                                buf, end ) );
439         default:
440             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
441     }
442 #endif
443 }
444 
ecdh_get_params_internal(mbedtls_ecdh_context_mbed * ctx,const mbedtls_ecp_keypair * key,mbedtls_ecdh_side side)445 static int ecdh_get_params_internal( mbedtls_ecdh_context_mbed *ctx,
446                                      const mbedtls_ecp_keypair *key,
447                                      mbedtls_ecdh_side side )
448 {
449     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
450 
451     /* If it's not our key, just import the public part as Qp */
452     if( side == MBEDTLS_ECDH_THEIRS )
453         return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) );
454 
455     /* Our key: import public (as Q) and private parts */
456     if( side != MBEDTLS_ECDH_OURS )
457         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
458 
459     if( ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 ||
460         ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 )
461         return( ret );
462 
463     return( 0 );
464 }
465 
466 /*
467  * Get parameters from a keypair
468  */
mbedtls_ecdh_get_params(mbedtls_ecdh_context * ctx,const mbedtls_ecp_keypair * key,mbedtls_ecdh_side side)469 int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx,
470                              const mbedtls_ecp_keypair *key,
471                              mbedtls_ecdh_side side )
472 {
473     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
474     ECDH_VALIDATE_RET( ctx != NULL );
475     ECDH_VALIDATE_RET( key != NULL );
476     ECDH_VALIDATE_RET( side == MBEDTLS_ECDH_OURS ||
477                        side == MBEDTLS_ECDH_THEIRS );
478 
479     if( mbedtls_ecdh_grp_id( ctx ) == MBEDTLS_ECP_DP_NONE )
480     {
481         /* This is the first call to get_params(). Set up the context
482          * for use with the group. */
483         if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 )
484             return( ret );
485     }
486     else
487     {
488         /* This is not the first call to get_params(). Check that the
489          * current key's group is the same as the context's, which was set
490          * from the first key's group. */
491         if( mbedtls_ecdh_grp_id( ctx ) != key->grp.id )
492             return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
493     }
494 
495 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
496     return( ecdh_get_params_internal( ctx, key, side ) );
497 #else
498     switch( ctx->var )
499     {
500 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
501         case MBEDTLS_ECDH_VARIANT_EVEREST:
502         {
503             mbedtls_everest_ecdh_side s = side == MBEDTLS_ECDH_OURS ?
504                                                    MBEDTLS_EVEREST_ECDH_OURS :
505                                                    MBEDTLS_EVEREST_ECDH_THEIRS;
506             return( mbedtls_everest_get_params( &ctx->ctx.everest_ecdh,
507                                                 key, s) );
508         }
509 #endif
510         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
511             return( ecdh_get_params_internal( &ctx->ctx.mbed_ecdh,
512                                               key, side ) );
513         default:
514             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
515     }
516 #endif
517 }
518 
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)519 static int ecdh_make_public_internal( mbedtls_ecdh_context_mbed *ctx,
520                                       size_t *olen, int point_format,
521                                       unsigned char *buf, size_t blen,
522                                       int (*f_rng)(void *,
523                                                    unsigned char *,
524                                                    size_t),
525                                       void *p_rng,
526                                       int restart_enabled )
527 {
528     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
529 #if defined(MBEDTLS_ECP_RESTARTABLE)
530     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
531 #endif
532 
533     if( ctx->grp.pbits == 0 )
534         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
535 
536 #if defined(MBEDTLS_ECP_RESTARTABLE)
537     if( restart_enabled )
538         rs_ctx = &ctx->rs;
539 #else
540     (void) restart_enabled;
541 #endif
542 
543 #if defined(MBEDTLS_ECP_RESTARTABLE)
544     if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
545                                              f_rng, p_rng, rs_ctx ) ) != 0 )
546         return( ret );
547 #else
548     if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
549                                          f_rng, p_rng ) ) != 0 )
550         return( ret );
551 #endif /* MBEDTLS_ECP_RESTARTABLE */
552 
553     return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, olen,
554                                         buf, blen );
555 }
556 
557 /*
558  * Setup and export the client public value
559  */
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)560 int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen,
561                               unsigned char *buf, size_t blen,
562                               int (*f_rng)(void *, unsigned char *, size_t),
563                               void *p_rng )
564 {
565     int restart_enabled = 0;
566     ECDH_VALIDATE_RET( ctx != NULL );
567     ECDH_VALIDATE_RET( olen != NULL );
568     ECDH_VALIDATE_RET( buf != NULL );
569     ECDH_VALIDATE_RET( f_rng != NULL );
570 
571 #if defined(MBEDTLS_ECP_RESTARTABLE)
572     restart_enabled = ctx->restart_enabled;
573 #endif
574 
575 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
576     return( ecdh_make_public_internal( ctx, olen, ctx->point_format, buf, blen,
577                                        f_rng, p_rng, restart_enabled ) );
578 #else
579     switch( ctx->var )
580     {
581 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
582         case MBEDTLS_ECDH_VARIANT_EVEREST:
583             return( mbedtls_everest_make_public( &ctx->ctx.everest_ecdh, olen,
584                                                  buf, blen, f_rng, p_rng ) );
585 #endif
586         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
587             return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen,
588                                                ctx->point_format, buf, blen,
589                                                f_rng, p_rng,
590                                                restart_enabled ) );
591         default:
592             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
593     }
594 #endif
595 }
596 
ecdh_read_public_internal(mbedtls_ecdh_context_mbed * ctx,const unsigned char * buf,size_t blen)597 static int ecdh_read_public_internal( mbedtls_ecdh_context_mbed *ctx,
598                                       const unsigned char *buf, size_t blen )
599 {
600     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
601     const unsigned char *p = buf;
602 
603     if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p,
604                                             blen ) ) != 0 )
605         return( ret );
606 
607     if( (size_t)( p - buf ) != blen )
608         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
609 
610     return( 0 );
611 }
612 
613 /*
614  * Parse and import the client's public value
615  */
mbedtls_ecdh_read_public(mbedtls_ecdh_context * ctx,const unsigned char * buf,size_t blen)616 int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx,
617                               const unsigned char *buf, size_t blen )
618 {
619     ECDH_VALIDATE_RET( ctx != NULL );
620     ECDH_VALIDATE_RET( buf != NULL );
621 
622 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
623     return( ecdh_read_public_internal( ctx, buf, blen ) );
624 #else
625     switch( ctx->var )
626     {
627 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
628         case MBEDTLS_ECDH_VARIANT_EVEREST:
629             return( mbedtls_everest_read_public( &ctx->ctx.everest_ecdh,
630                                                  buf, blen ) );
631 #endif
632         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
633             return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh,
634                                                        buf, blen ) );
635         default:
636             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
637     }
638 #endif
639 }
640 
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)641 static int ecdh_calc_secret_internal( mbedtls_ecdh_context_mbed *ctx,
642                                       size_t *olen, unsigned char *buf,
643                                       size_t blen,
644                                       int (*f_rng)(void *,
645                                                    unsigned char *,
646                                                    size_t),
647                                       void *p_rng,
648                                       int restart_enabled )
649 {
650     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
651 #if defined(MBEDTLS_ECP_RESTARTABLE)
652     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
653 #endif
654 
655     if( ctx == NULL || ctx->grp.pbits == 0 )
656         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
657 
658 #if defined(MBEDTLS_ECP_RESTARTABLE)
659     if( restart_enabled )
660         rs_ctx = &ctx->rs;
661 #else
662     (void) restart_enabled;
663 #endif
664 
665 #if defined(MBEDTLS_ECP_RESTARTABLE)
666     if( ( ret = ecdh_compute_shared_restartable( &ctx->grp, &ctx->z, &ctx->Qp,
667                                                  &ctx->d, f_rng, p_rng,
668                                                  rs_ctx ) ) != 0 )
669     {
670         return( ret );
671     }
672 #else
673     if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp,
674                                              &ctx->d, f_rng, p_rng ) ) != 0 )
675     {
676         return( ret );
677     }
678 #endif /* MBEDTLS_ECP_RESTARTABLE */
679 
680     if( mbedtls_mpi_size( &ctx->z ) > blen )
681         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
682 
683     *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 );
684 
685     if( mbedtls_ecp_get_type( &ctx->grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
686         return mbedtls_mpi_write_binary_le( &ctx->z, buf, *olen );
687 
688     return mbedtls_mpi_write_binary( &ctx->z, buf, *olen );
689 }
690 
691 /*
692  * Derive and export the shared secret
693  */
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)694 int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen,
695                               unsigned char *buf, size_t blen,
696                               int (*f_rng)(void *, unsigned char *, size_t),
697                               void *p_rng )
698 {
699     int restart_enabled = 0;
700     ECDH_VALIDATE_RET( ctx != NULL );
701     ECDH_VALIDATE_RET( olen != NULL );
702     ECDH_VALIDATE_RET( buf != NULL );
703 
704 #if defined(MBEDTLS_ECP_RESTARTABLE)
705     restart_enabled = ctx->restart_enabled;
706 #endif
707 
708 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
709     return( ecdh_calc_secret_internal( ctx, olen, buf, blen, f_rng, p_rng,
710                                        restart_enabled ) );
711 #else
712     switch( ctx->var )
713     {
714 #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
715         case MBEDTLS_ECDH_VARIANT_EVEREST:
716             return( mbedtls_everest_calc_secret( &ctx->ctx.everest_ecdh, olen,
717                                                  buf, blen, f_rng, p_rng ) );
718 #endif
719         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
720             return( ecdh_calc_secret_internal( &ctx->ctx.mbed_ecdh, olen, buf,
721                                                blen, f_rng, p_rng,
722                                                restart_enabled ) );
723         default:
724             return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
725     }
726 #endif
727 }
728 
729 #endif /* MBEDTLS_ECDH_C */
730