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