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