xref: /optee_os/lib/libmbedtls/mbedtls/library/ecdh.c (revision 11fa71b9ddb429088f325cfda430183003ccd1db)
1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0
2817466cbSJens Wiklander /*
3817466cbSJens Wiklander  *  Elliptic curve Diffie-Hellman
4817466cbSJens Wiklander  *
5817466cbSJens Wiklander  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  *
19817466cbSJens Wiklander  *  This file is part of mbed TLS (https://tls.mbed.org)
20817466cbSJens Wiklander  */
21817466cbSJens Wiklander 
22817466cbSJens Wiklander /*
23817466cbSJens Wiklander  * References:
24817466cbSJens Wiklander  *
25817466cbSJens Wiklander  * SEC1 http://www.secg.org/index.php?action=secg,docs_secg
26817466cbSJens Wiklander  * RFC 4492
27817466cbSJens Wiklander  */
28817466cbSJens Wiklander 
29817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
30817466cbSJens Wiklander #include "mbedtls/config.h"
31817466cbSJens Wiklander #else
32817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE
33817466cbSJens Wiklander #endif
34817466cbSJens Wiklander 
35817466cbSJens Wiklander #if defined(MBEDTLS_ECDH_C)
36817466cbSJens Wiklander 
37817466cbSJens Wiklander #include "mbedtls/ecdh.h"
383d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
39*11fa71b9SJerome Forissier #include "mbedtls/error.h"
40817466cbSJens Wiklander 
41817466cbSJens Wiklander #include <string.h>
42817466cbSJens Wiklander 
433d3b0591SJens Wiklander /* Parameter validation macros based on platform_util.h */
443d3b0591SJens Wiklander #define ECDH_VALIDATE_RET( cond )    \
453d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA )
463d3b0591SJens Wiklander #define ECDH_VALIDATE( cond )        \
473d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE( cond )
483d3b0591SJens Wiklander 
493d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
503d3b0591SJens Wiklander typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed;
513d3b0591SJens Wiklander #endif
523d3b0591SJens Wiklander 
535b25c76aSJerome Forissier static mbedtls_ecp_group_id mbedtls_ecdh_grp_id(
545b25c76aSJerome Forissier     const mbedtls_ecdh_context *ctx )
555b25c76aSJerome Forissier {
565b25c76aSJerome Forissier #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
575b25c76aSJerome Forissier     return( ctx->grp.id );
585b25c76aSJerome Forissier #else
595b25c76aSJerome Forissier     return( ctx->grp_id );
605b25c76aSJerome Forissier #endif
615b25c76aSJerome Forissier }
625b25c76aSJerome Forissier 
63*11fa71b9SJerome Forissier int mbedtls_ecdh_can_do( mbedtls_ecp_group_id gid )
64*11fa71b9SJerome Forissier {
65*11fa71b9SJerome Forissier     /* At this time, all groups support ECDH. */
66*11fa71b9SJerome Forissier     (void) gid;
67*11fa71b9SJerome Forissier     return( 1 );
68*11fa71b9SJerome Forissier }
69*11fa71b9SJerome Forissier 
703d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)
71817466cbSJens Wiklander /*
723d3b0591SJens Wiklander  * Generate public key (restartable version)
733d3b0591SJens Wiklander  *
743d3b0591SJens Wiklander  * Note: this internal function relies on its caller preserving the value of
753d3b0591SJens Wiklander  * the output parameter 'd' across continuation calls. This would not be
763d3b0591SJens Wiklander  * acceptable for a public function but is OK here as we control call sites.
773d3b0591SJens Wiklander  */
783d3b0591SJens Wiklander static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp,
793d3b0591SJens Wiklander                     mbedtls_mpi *d, mbedtls_ecp_point *Q,
803d3b0591SJens Wiklander                     int (*f_rng)(void *, unsigned char *, size_t),
813d3b0591SJens Wiklander                     void *p_rng,
823d3b0591SJens Wiklander                     mbedtls_ecp_restart_ctx *rs_ctx )
833d3b0591SJens Wiklander {
84*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
853d3b0591SJens Wiklander 
863d3b0591SJens Wiklander     /* If multiplication is in progress, we already generated a privkey */
873d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
883d3b0591SJens Wiklander     if( rs_ctx == NULL || rs_ctx->rsm == NULL )
893d3b0591SJens Wiklander #endif
903d3b0591SJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) );
913d3b0591SJens Wiklander 
923d3b0591SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G,
933d3b0591SJens Wiklander                                                   f_rng, p_rng, rs_ctx ) );
943d3b0591SJens Wiklander 
953d3b0591SJens Wiklander cleanup:
963d3b0591SJens Wiklander     return( ret );
973d3b0591SJens Wiklander }
983d3b0591SJens Wiklander 
993d3b0591SJens Wiklander /*
1003d3b0591SJens Wiklander  * Generate public key
101817466cbSJens Wiklander  */
102817466cbSJens Wiklander int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,
103817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
104817466cbSJens Wiklander                      void *p_rng )
105817466cbSJens Wiklander {
1063d3b0591SJens Wiklander     ECDH_VALIDATE_RET( grp != NULL );
1073d3b0591SJens Wiklander     ECDH_VALIDATE_RET( d != NULL );
1083d3b0591SJens Wiklander     ECDH_VALIDATE_RET( Q != NULL );
1093d3b0591SJens Wiklander     ECDH_VALIDATE_RET( f_rng != NULL );
1103d3b0591SJens Wiklander     return( ecdh_gen_public_restartable( grp, d, Q, f_rng, p_rng, NULL ) );
111817466cbSJens Wiklander }
1123d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */
113817466cbSJens Wiklander 
1143d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT)
115817466cbSJens Wiklander /*
116817466cbSJens Wiklander  * Compute shared secret (SEC1 3.3.1)
117817466cbSJens Wiklander  */
1183d3b0591SJens Wiklander static int ecdh_compute_shared_restartable( mbedtls_ecp_group *grp,
1193d3b0591SJens Wiklander                          mbedtls_mpi *z,
120817466cbSJens Wiklander                          const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
121817466cbSJens Wiklander                          int (*f_rng)(void *, unsigned char *, size_t),
1223d3b0591SJens Wiklander                          void *p_rng,
1233d3b0591SJens Wiklander                          mbedtls_ecp_restart_ctx *rs_ctx )
124817466cbSJens Wiklander {
125*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
126817466cbSJens Wiklander     mbedtls_ecp_point P;
127817466cbSJens Wiklander 
128817466cbSJens Wiklander     mbedtls_ecp_point_init( &P );
129817466cbSJens Wiklander 
1303d3b0591SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &P, d, Q,
1313d3b0591SJens Wiklander                                                   f_rng, p_rng, rs_ctx ) );
132817466cbSJens Wiklander 
133817466cbSJens Wiklander     if( mbedtls_ecp_is_zero( &P ) )
134817466cbSJens Wiklander     {
135817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
136817466cbSJens Wiklander         goto cleanup;
137817466cbSJens Wiklander     }
138817466cbSJens Wiklander 
139817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) );
140817466cbSJens Wiklander 
141817466cbSJens Wiklander cleanup:
142817466cbSJens Wiklander     mbedtls_ecp_point_free( &P );
143817466cbSJens Wiklander 
144817466cbSJens Wiklander     return( ret );
145817466cbSJens Wiklander }
146817466cbSJens Wiklander 
147817466cbSJens Wiklander /*
1483d3b0591SJens Wiklander  * Compute shared secret (SEC1 3.3.1)
1493d3b0591SJens Wiklander  */
1503d3b0591SJens Wiklander int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,
1513d3b0591SJens Wiklander                          const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
1523d3b0591SJens Wiklander                          int (*f_rng)(void *, unsigned char *, size_t),
1533d3b0591SJens Wiklander                          void *p_rng )
1543d3b0591SJens Wiklander {
1553d3b0591SJens Wiklander     ECDH_VALIDATE_RET( grp != NULL );
1563d3b0591SJens Wiklander     ECDH_VALIDATE_RET( Q != NULL );
1573d3b0591SJens Wiklander     ECDH_VALIDATE_RET( d != NULL );
1583d3b0591SJens Wiklander     ECDH_VALIDATE_RET( z != NULL );
1593d3b0591SJens Wiklander     return( ecdh_compute_shared_restartable( grp, z, Q, d,
1603d3b0591SJens Wiklander                                              f_rng, p_rng, NULL ) );
1613d3b0591SJens Wiklander }
1623d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
1633d3b0591SJens Wiklander 
1643d3b0591SJens Wiklander static void ecdh_init_internal( mbedtls_ecdh_context_mbed *ctx )
1653d3b0591SJens Wiklander {
1663d3b0591SJens Wiklander     mbedtls_ecp_group_init( &ctx->grp );
1673d3b0591SJens Wiklander     mbedtls_mpi_init( &ctx->d  );
1683d3b0591SJens Wiklander     mbedtls_ecp_point_init( &ctx->Q   );
1693d3b0591SJens Wiklander     mbedtls_ecp_point_init( &ctx->Qp  );
1703d3b0591SJens Wiklander     mbedtls_mpi_init( &ctx->z  );
1713d3b0591SJens Wiklander 
1723d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
1733d3b0591SJens Wiklander     mbedtls_ecp_restart_init( &ctx->rs );
1743d3b0591SJens Wiklander #endif
1753d3b0591SJens Wiklander }
1763d3b0591SJens Wiklander 
1773d3b0591SJens Wiklander /*
178817466cbSJens Wiklander  * Initialize context
179817466cbSJens Wiklander  */
180817466cbSJens Wiklander void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx )
181817466cbSJens Wiklander {
1823d3b0591SJens Wiklander     ECDH_VALIDATE( ctx != NULL );
1833d3b0591SJens Wiklander 
1843d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
1853d3b0591SJens Wiklander     ecdh_init_internal( ctx );
1863d3b0591SJens Wiklander     mbedtls_ecp_point_init( &ctx->Vi  );
1873d3b0591SJens Wiklander     mbedtls_ecp_point_init( &ctx->Vf  );
1883d3b0591SJens Wiklander     mbedtls_mpi_init( &ctx->_d );
1893d3b0591SJens Wiklander #else
190817466cbSJens Wiklander     memset( ctx, 0, sizeof( mbedtls_ecdh_context ) );
1913d3b0591SJens Wiklander 
1923d3b0591SJens Wiklander     ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
1933d3b0591SJens Wiklander #endif
1943d3b0591SJens Wiklander     ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
1953d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
1963d3b0591SJens Wiklander     ctx->restart_enabled = 0;
1973d3b0591SJens Wiklander #endif
198817466cbSJens Wiklander }
199817466cbSJens Wiklander 
2003d3b0591SJens Wiklander static int ecdh_setup_internal( mbedtls_ecdh_context_mbed *ctx,
2013d3b0591SJens Wiklander                                 mbedtls_ecp_group_id grp_id )
2023d3b0591SJens Wiklander {
203*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2043d3b0591SJens Wiklander 
2053d3b0591SJens Wiklander     ret = mbedtls_ecp_group_load( &ctx->grp, grp_id );
2063d3b0591SJens Wiklander     if( ret != 0 )
2073d3b0591SJens Wiklander     {
2083d3b0591SJens Wiklander         return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
2093d3b0591SJens Wiklander     }
2103d3b0591SJens Wiklander 
2113d3b0591SJens Wiklander     return( 0 );
2123d3b0591SJens Wiklander }
2133d3b0591SJens Wiklander 
2143d3b0591SJens Wiklander /*
2153d3b0591SJens Wiklander  * Setup context
2163d3b0591SJens Wiklander  */
2173d3b0591SJens Wiklander int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id )
2183d3b0591SJens Wiklander {
2193d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
2203d3b0591SJens Wiklander 
2213d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
2223d3b0591SJens Wiklander     return( ecdh_setup_internal( ctx, grp_id ) );
2233d3b0591SJens Wiklander #else
2243d3b0591SJens Wiklander     switch( grp_id )
2253d3b0591SJens Wiklander     {
226*11fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
227*11fa71b9SJerome Forissier         case MBEDTLS_ECP_DP_CURVE25519:
228*11fa71b9SJerome Forissier             ctx->point_format = MBEDTLS_ECP_PF_COMPRESSED;
229*11fa71b9SJerome Forissier             ctx->var = MBEDTLS_ECDH_VARIANT_EVEREST;
230*11fa71b9SJerome Forissier             ctx->grp_id = grp_id;
231*11fa71b9SJerome Forissier             return( mbedtls_everest_setup( &ctx->ctx.everest_ecdh, grp_id ) );
232*11fa71b9SJerome Forissier #endif
2333d3b0591SJens Wiklander         default:
2343d3b0591SJens Wiklander             ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
2353d3b0591SJens Wiklander             ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0;
2363d3b0591SJens Wiklander             ctx->grp_id = grp_id;
2373d3b0591SJens Wiklander             ecdh_init_internal( &ctx->ctx.mbed_ecdh );
2383d3b0591SJens Wiklander             return( ecdh_setup_internal( &ctx->ctx.mbed_ecdh, grp_id ) );
2393d3b0591SJens Wiklander     }
2403d3b0591SJens Wiklander #endif
2413d3b0591SJens Wiklander }
2423d3b0591SJens Wiklander 
2433d3b0591SJens Wiklander static void ecdh_free_internal( mbedtls_ecdh_context_mbed *ctx )
2443d3b0591SJens Wiklander {
2453d3b0591SJens Wiklander     mbedtls_ecp_group_free( &ctx->grp );
2463d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->d  );
2473d3b0591SJens Wiklander     mbedtls_ecp_point_free( &ctx->Q   );
2483d3b0591SJens Wiklander     mbedtls_ecp_point_free( &ctx->Qp  );
2493d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->z  );
2503d3b0591SJens Wiklander 
2513d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
2523d3b0591SJens Wiklander     mbedtls_ecp_restart_free( &ctx->rs );
2533d3b0591SJens Wiklander #endif
2543d3b0591SJens Wiklander }
2553d3b0591SJens Wiklander 
2563d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
2573d3b0591SJens Wiklander /*
2583d3b0591SJens Wiklander  * Enable restartable operations for context
2593d3b0591SJens Wiklander  */
2603d3b0591SJens Wiklander void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx )
2613d3b0591SJens Wiklander {
2623d3b0591SJens Wiklander     ECDH_VALIDATE( ctx != NULL );
2633d3b0591SJens Wiklander 
2643d3b0591SJens Wiklander     ctx->restart_enabled = 1;
2653d3b0591SJens Wiklander }
2663d3b0591SJens Wiklander #endif
2673d3b0591SJens Wiklander 
268817466cbSJens Wiklander /*
269817466cbSJens Wiklander  * Free context
270817466cbSJens Wiklander  */
271817466cbSJens Wiklander void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx )
272817466cbSJens Wiklander {
273817466cbSJens Wiklander     if( ctx == NULL )
274817466cbSJens Wiklander         return;
275817466cbSJens Wiklander 
2763d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
277817466cbSJens Wiklander     mbedtls_ecp_point_free( &ctx->Vi );
278817466cbSJens Wiklander     mbedtls_ecp_point_free( &ctx->Vf );
279817466cbSJens Wiklander     mbedtls_mpi_free( &ctx->_d );
2803d3b0591SJens Wiklander     ecdh_free_internal( ctx );
2813d3b0591SJens Wiklander #else
2823d3b0591SJens Wiklander     switch( ctx->var )
2833d3b0591SJens Wiklander     {
284*11fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
285*11fa71b9SJerome Forissier         case MBEDTLS_ECDH_VARIANT_EVEREST:
286*11fa71b9SJerome Forissier             mbedtls_everest_free( &ctx->ctx.everest_ecdh );
287*11fa71b9SJerome Forissier             break;
288*11fa71b9SJerome Forissier #endif
2893d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
2903d3b0591SJens Wiklander             ecdh_free_internal( &ctx->ctx.mbed_ecdh );
2913d3b0591SJens Wiklander             break;
2923d3b0591SJens Wiklander         default:
2933d3b0591SJens Wiklander             break;
2943d3b0591SJens Wiklander     }
2953d3b0591SJens Wiklander 
2963d3b0591SJens Wiklander     ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
2973d3b0591SJens Wiklander     ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
2983d3b0591SJens Wiklander     ctx->grp_id = MBEDTLS_ECP_DP_NONE;
2993d3b0591SJens Wiklander #endif
3003d3b0591SJens Wiklander }
3013d3b0591SJens Wiklander 
3023d3b0591SJens Wiklander static int ecdh_make_params_internal( mbedtls_ecdh_context_mbed *ctx,
3033d3b0591SJens Wiklander                                       size_t *olen, int point_format,
3043d3b0591SJens Wiklander                                       unsigned char *buf, size_t blen,
3053d3b0591SJens Wiklander                                       int (*f_rng)(void *,
3063d3b0591SJens Wiklander                                                    unsigned char *,
3073d3b0591SJens Wiklander                                                    size_t),
3083d3b0591SJens Wiklander                                       void *p_rng,
3093d3b0591SJens Wiklander                                       int restart_enabled )
3103d3b0591SJens Wiklander {
311*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
3123d3b0591SJens Wiklander     size_t grp_len, pt_len;
3133d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
3143d3b0591SJens Wiklander     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
3153d3b0591SJens Wiklander #endif
3163d3b0591SJens Wiklander 
3173d3b0591SJens Wiklander     if( ctx->grp.pbits == 0 )
3183d3b0591SJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
3193d3b0591SJens Wiklander 
3203d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
3213d3b0591SJens Wiklander     if( restart_enabled )
3223d3b0591SJens Wiklander         rs_ctx = &ctx->rs;
3233d3b0591SJens Wiklander #else
3243d3b0591SJens Wiklander     (void) restart_enabled;
3253d3b0591SJens Wiklander #endif
3263d3b0591SJens Wiklander 
3273d3b0591SJens Wiklander 
3283d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
3293d3b0591SJens Wiklander     if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
3303d3b0591SJens Wiklander                                              f_rng, p_rng, rs_ctx ) ) != 0 )
3313d3b0591SJens Wiklander         return( ret );
3323d3b0591SJens Wiklander #else
3333d3b0591SJens Wiklander     if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
3343d3b0591SJens Wiklander                                          f_rng, p_rng ) ) != 0 )
3353d3b0591SJens Wiklander         return( ret );
3363d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */
3373d3b0591SJens Wiklander 
3383d3b0591SJens Wiklander     if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf,
3393d3b0591SJens Wiklander                                              blen ) ) != 0 )
3403d3b0591SJens Wiklander         return( ret );
3413d3b0591SJens Wiklander 
3423d3b0591SJens Wiklander     buf += grp_len;
3433d3b0591SJens Wiklander     blen -= grp_len;
3443d3b0591SJens Wiklander 
3453d3b0591SJens Wiklander     if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format,
3463d3b0591SJens Wiklander                                              &pt_len, buf, blen ) ) != 0 )
3473d3b0591SJens Wiklander         return( ret );
3483d3b0591SJens Wiklander 
3493d3b0591SJens Wiklander     *olen = grp_len + pt_len;
3503d3b0591SJens Wiklander     return( 0 );
351817466cbSJens Wiklander }
352817466cbSJens Wiklander 
353817466cbSJens Wiklander /*
354*11fa71b9SJerome Forissier  * Setup and write the ServerKeyExchange parameters (RFC 4492)
355817466cbSJens Wiklander  *      struct {
356817466cbSJens Wiklander  *          ECParameters    curve_params;
357817466cbSJens Wiklander  *          ECPoint         public;
358817466cbSJens Wiklander  *      } ServerECDHParams;
359817466cbSJens Wiklander  */
360817466cbSJens Wiklander int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
361817466cbSJens Wiklander                               unsigned char *buf, size_t blen,
362817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
363817466cbSJens Wiklander                               void *p_rng )
364817466cbSJens Wiklander {
3653d3b0591SJens Wiklander     int restart_enabled = 0;
3663d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
3673d3b0591SJens Wiklander     ECDH_VALIDATE_RET( olen != NULL );
3683d3b0591SJens Wiklander     ECDH_VALIDATE_RET( buf != NULL );
3693d3b0591SJens Wiklander     ECDH_VALIDATE_RET( f_rng != NULL );
370817466cbSJens Wiklander 
3713d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
3723d3b0591SJens Wiklander     restart_enabled = ctx->restart_enabled;
3733d3b0591SJens Wiklander #else
3743d3b0591SJens Wiklander     (void) restart_enabled;
3753d3b0591SJens Wiklander #endif
376817466cbSJens Wiklander 
3773d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
3783d3b0591SJens Wiklander     return( ecdh_make_params_internal( ctx, olen, ctx->point_format, buf, blen,
3793d3b0591SJens Wiklander                                        f_rng, p_rng, restart_enabled ) );
3803d3b0591SJens Wiklander #else
3813d3b0591SJens Wiklander     switch( ctx->var )
3823d3b0591SJens Wiklander     {
383*11fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
384*11fa71b9SJerome Forissier         case MBEDTLS_ECDH_VARIANT_EVEREST:
385*11fa71b9SJerome Forissier             return( mbedtls_everest_make_params( &ctx->ctx.everest_ecdh, olen,
386*11fa71b9SJerome Forissier                                                  buf, blen, f_rng, p_rng ) );
387*11fa71b9SJerome Forissier #endif
3883d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
3893d3b0591SJens Wiklander             return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen,
3903d3b0591SJens Wiklander                                                ctx->point_format, buf, blen,
3913d3b0591SJens Wiklander                                                f_rng, p_rng,
3923d3b0591SJens Wiklander                                                restart_enabled ) );
3933d3b0591SJens Wiklander         default:
3943d3b0591SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
3953d3b0591SJens Wiklander     }
3963d3b0591SJens Wiklander #endif
3973d3b0591SJens Wiklander }
398817466cbSJens Wiklander 
3993d3b0591SJens Wiklander static int ecdh_read_params_internal( mbedtls_ecdh_context_mbed *ctx,
4003d3b0591SJens Wiklander                                       const unsigned char **buf,
4013d3b0591SJens Wiklander                                       const unsigned char *end )
4023d3b0591SJens Wiklander {
4033d3b0591SJens Wiklander     return( mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf,
4043d3b0591SJens Wiklander                                         end - *buf ) );
405817466cbSJens Wiklander }
406817466cbSJens Wiklander 
407817466cbSJens Wiklander /*
408817466cbSJens Wiklander  * Read the ServerKeyExhange parameters (RFC 4492)
409817466cbSJens Wiklander  *      struct {
410817466cbSJens Wiklander  *          ECParameters    curve_params;
411817466cbSJens Wiklander  *          ECPoint         public;
412817466cbSJens Wiklander  *      } ServerECDHParams;
413817466cbSJens Wiklander  */
414817466cbSJens Wiklander int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx,
4153d3b0591SJens Wiklander                               const unsigned char **buf,
4163d3b0591SJens Wiklander                               const unsigned char *end )
417817466cbSJens Wiklander {
418*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
4193d3b0591SJens Wiklander     mbedtls_ecp_group_id grp_id;
4203d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
4213d3b0591SJens Wiklander     ECDH_VALIDATE_RET( buf != NULL );
4223d3b0591SJens Wiklander     ECDH_VALIDATE_RET( *buf != NULL );
4233d3b0591SJens Wiklander     ECDH_VALIDATE_RET( end != NULL );
424817466cbSJens Wiklander 
4253d3b0591SJens Wiklander     if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, end - *buf ) )
426817466cbSJens Wiklander             != 0 )
427817466cbSJens Wiklander         return( ret );
428817466cbSJens Wiklander 
4293d3b0591SJens Wiklander     if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 )
4303d3b0591SJens Wiklander         return( ret );
4313d3b0591SJens Wiklander 
4323d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
4333d3b0591SJens Wiklander     return( ecdh_read_params_internal( ctx, buf, end ) );
4343d3b0591SJens Wiklander #else
4353d3b0591SJens Wiklander     switch( ctx->var )
4363d3b0591SJens Wiklander     {
437*11fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
438*11fa71b9SJerome Forissier         case MBEDTLS_ECDH_VARIANT_EVEREST:
439*11fa71b9SJerome Forissier             return( mbedtls_everest_read_params( &ctx->ctx.everest_ecdh,
440*11fa71b9SJerome Forissier                                                  buf, end) );
441*11fa71b9SJerome Forissier #endif
4423d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
4433d3b0591SJens Wiklander             return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh,
4443d3b0591SJens Wiklander                                                buf, end ) );
4453d3b0591SJens Wiklander         default:
4463d3b0591SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
4473d3b0591SJens Wiklander     }
4483d3b0591SJens Wiklander #endif
449817466cbSJens Wiklander }
450817466cbSJens Wiklander 
4513d3b0591SJens Wiklander static int ecdh_get_params_internal( mbedtls_ecdh_context_mbed *ctx,
4523d3b0591SJens Wiklander                                      const mbedtls_ecp_keypair *key,
453817466cbSJens Wiklander                                      mbedtls_ecdh_side side )
454817466cbSJens Wiklander {
455*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
456817466cbSJens Wiklander 
457817466cbSJens Wiklander     /* If it's not our key, just import the public part as Qp */
458817466cbSJens Wiklander     if( side == MBEDTLS_ECDH_THEIRS )
459817466cbSJens Wiklander         return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) );
460817466cbSJens Wiklander 
461817466cbSJens Wiklander     /* Our key: import public (as Q) and private parts */
462817466cbSJens Wiklander     if( side != MBEDTLS_ECDH_OURS )
463817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
464817466cbSJens Wiklander 
465817466cbSJens Wiklander     if( ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 ||
466817466cbSJens Wiklander         ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 )
467817466cbSJens Wiklander         return( ret );
468817466cbSJens Wiklander 
469817466cbSJens Wiklander     return( 0 );
470817466cbSJens Wiklander }
471817466cbSJens Wiklander 
472817466cbSJens Wiklander /*
4733d3b0591SJens Wiklander  * Get parameters from a keypair
4743d3b0591SJens Wiklander  */
4753d3b0591SJens Wiklander int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx,
4763d3b0591SJens Wiklander                              const mbedtls_ecp_keypair *key,
4773d3b0591SJens Wiklander                              mbedtls_ecdh_side side )
4783d3b0591SJens Wiklander {
479*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
4803d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
4813d3b0591SJens Wiklander     ECDH_VALIDATE_RET( key != NULL );
4823d3b0591SJens Wiklander     ECDH_VALIDATE_RET( side == MBEDTLS_ECDH_OURS ||
4833d3b0591SJens Wiklander                        side == MBEDTLS_ECDH_THEIRS );
4843d3b0591SJens Wiklander 
4855b25c76aSJerome Forissier     if( mbedtls_ecdh_grp_id( ctx ) == MBEDTLS_ECP_DP_NONE )
4865b25c76aSJerome Forissier     {
4875b25c76aSJerome Forissier         /* This is the first call to get_params(). Set up the context
4885b25c76aSJerome Forissier          * for use with the group. */
4893d3b0591SJens Wiklander         if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 )
4903d3b0591SJens Wiklander             return( ret );
4915b25c76aSJerome Forissier     }
4925b25c76aSJerome Forissier     else
4935b25c76aSJerome Forissier     {
4945b25c76aSJerome Forissier         /* This is not the first call to get_params(). Check that the
4955b25c76aSJerome Forissier          * current key's group is the same as the context's, which was set
4965b25c76aSJerome Forissier          * from the first key's group. */
4975b25c76aSJerome Forissier         if( mbedtls_ecdh_grp_id( ctx ) != key->grp.id )
4985b25c76aSJerome Forissier             return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
4995b25c76aSJerome Forissier     }
5003d3b0591SJens Wiklander 
5013d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
5023d3b0591SJens Wiklander     return( ecdh_get_params_internal( ctx, key, side ) );
5033d3b0591SJens Wiklander #else
5043d3b0591SJens Wiklander     switch( ctx->var )
5053d3b0591SJens Wiklander     {
506*11fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
507*11fa71b9SJerome Forissier         case MBEDTLS_ECDH_VARIANT_EVEREST:
508*11fa71b9SJerome Forissier         {
509*11fa71b9SJerome Forissier             mbedtls_everest_ecdh_side s = side == MBEDTLS_ECDH_OURS ?
510*11fa71b9SJerome Forissier                                                    MBEDTLS_EVEREST_ECDH_OURS :
511*11fa71b9SJerome Forissier                                                    MBEDTLS_EVEREST_ECDH_THEIRS;
512*11fa71b9SJerome Forissier             return( mbedtls_everest_get_params( &ctx->ctx.everest_ecdh,
513*11fa71b9SJerome Forissier                                                 key, s) );
514*11fa71b9SJerome Forissier         }
515*11fa71b9SJerome Forissier #endif
5163d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
5173d3b0591SJens Wiklander             return( ecdh_get_params_internal( &ctx->ctx.mbed_ecdh,
5183d3b0591SJens Wiklander                                               key, side ) );
5193d3b0591SJens Wiklander         default:
5203d3b0591SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
5213d3b0591SJens Wiklander     }
5223d3b0591SJens Wiklander #endif
5233d3b0591SJens Wiklander }
5243d3b0591SJens Wiklander 
5253d3b0591SJens Wiklander static int ecdh_make_public_internal( mbedtls_ecdh_context_mbed *ctx,
5263d3b0591SJens Wiklander                                       size_t *olen, int point_format,
5273d3b0591SJens Wiklander                                       unsigned char *buf, size_t blen,
5283d3b0591SJens Wiklander                                       int (*f_rng)(void *,
5293d3b0591SJens Wiklander                                                    unsigned char *,
5303d3b0591SJens Wiklander                                                    size_t),
5313d3b0591SJens Wiklander                                       void *p_rng,
5323d3b0591SJens Wiklander                                       int restart_enabled )
5333d3b0591SJens Wiklander {
534*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
5353d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
5363d3b0591SJens Wiklander     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
5373d3b0591SJens Wiklander #endif
5383d3b0591SJens Wiklander 
5393d3b0591SJens Wiklander     if( ctx->grp.pbits == 0 )
5403d3b0591SJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
5413d3b0591SJens Wiklander 
5423d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
5433d3b0591SJens Wiklander     if( restart_enabled )
5443d3b0591SJens Wiklander         rs_ctx = &ctx->rs;
5453d3b0591SJens Wiklander #else
5463d3b0591SJens Wiklander     (void) restart_enabled;
5473d3b0591SJens Wiklander #endif
5483d3b0591SJens Wiklander 
5493d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
5503d3b0591SJens Wiklander     if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
5513d3b0591SJens Wiklander                                              f_rng, p_rng, rs_ctx ) ) != 0 )
5523d3b0591SJens Wiklander         return( ret );
5533d3b0591SJens Wiklander #else
5543d3b0591SJens Wiklander     if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
5553d3b0591SJens Wiklander                                          f_rng, p_rng ) ) != 0 )
5563d3b0591SJens Wiklander         return( ret );
5573d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */
5583d3b0591SJens Wiklander 
5593d3b0591SJens Wiklander     return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, olen,
5603d3b0591SJens Wiklander                                         buf, blen );
5613d3b0591SJens Wiklander }
5623d3b0591SJens Wiklander 
5633d3b0591SJens Wiklander /*
564817466cbSJens Wiklander  * Setup and export the client public value
565817466cbSJens Wiklander  */
566817466cbSJens Wiklander int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen,
567817466cbSJens Wiklander                               unsigned char *buf, size_t blen,
568817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
569817466cbSJens Wiklander                               void *p_rng )
570817466cbSJens Wiklander {
5713d3b0591SJens Wiklander     int restart_enabled = 0;
5723d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
5733d3b0591SJens Wiklander     ECDH_VALIDATE_RET( olen != NULL );
5743d3b0591SJens Wiklander     ECDH_VALIDATE_RET( buf != NULL );
5753d3b0591SJens Wiklander     ECDH_VALIDATE_RET( f_rng != NULL );
5763d3b0591SJens Wiklander 
5773d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
5783d3b0591SJens Wiklander     restart_enabled = ctx->restart_enabled;
5793d3b0591SJens Wiklander #endif
5803d3b0591SJens Wiklander 
5813d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
5823d3b0591SJens Wiklander     return( ecdh_make_public_internal( ctx, olen, ctx->point_format, buf, blen,
5833d3b0591SJens Wiklander                                        f_rng, p_rng, restart_enabled ) );
5843d3b0591SJens Wiklander #else
5853d3b0591SJens Wiklander     switch( ctx->var )
5863d3b0591SJens Wiklander     {
587*11fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
588*11fa71b9SJerome Forissier         case MBEDTLS_ECDH_VARIANT_EVEREST:
589*11fa71b9SJerome Forissier             return( mbedtls_everest_make_public( &ctx->ctx.everest_ecdh, olen,
590*11fa71b9SJerome Forissier                                                  buf, blen, f_rng, p_rng ) );
591*11fa71b9SJerome Forissier #endif
5923d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
5933d3b0591SJens Wiklander             return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen,
5943d3b0591SJens Wiklander                                                ctx->point_format, buf, blen,
5953d3b0591SJens Wiklander                                                f_rng, p_rng,
5963d3b0591SJens Wiklander                                                restart_enabled ) );
5973d3b0591SJens Wiklander         default:
5983d3b0591SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
5993d3b0591SJens Wiklander     }
6003d3b0591SJens Wiklander #endif
6013d3b0591SJens Wiklander }
6023d3b0591SJens Wiklander 
6033d3b0591SJens Wiklander static int ecdh_read_public_internal( mbedtls_ecdh_context_mbed *ctx,
6043d3b0591SJens Wiklander                                       const unsigned char *buf, size_t blen )
6053d3b0591SJens Wiklander {
606*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
6073d3b0591SJens Wiklander     const unsigned char *p = buf;
608817466cbSJens Wiklander 
6093d3b0591SJens Wiklander     if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p,
6103d3b0591SJens Wiklander                                             blen ) ) != 0 )
611817466cbSJens Wiklander         return( ret );
612817466cbSJens Wiklander 
6133d3b0591SJens Wiklander     if( (size_t)( p - buf ) != blen )
6143d3b0591SJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
6153d3b0591SJens Wiklander 
6163d3b0591SJens Wiklander     return( 0 );
617817466cbSJens Wiklander }
618817466cbSJens Wiklander 
619817466cbSJens Wiklander /*
620817466cbSJens Wiklander  * Parse and import the client's public value
621817466cbSJens Wiklander  */
622817466cbSJens Wiklander int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx,
623817466cbSJens Wiklander                               const unsigned char *buf, size_t blen )
624817466cbSJens Wiklander {
6253d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
6263d3b0591SJens Wiklander     ECDH_VALIDATE_RET( buf != NULL );
6273d3b0591SJens Wiklander 
6283d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
6293d3b0591SJens Wiklander     return( ecdh_read_public_internal( ctx, buf, blen ) );
6303d3b0591SJens Wiklander #else
6313d3b0591SJens Wiklander     switch( ctx->var )
6323d3b0591SJens Wiklander     {
633*11fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
634*11fa71b9SJerome Forissier         case MBEDTLS_ECDH_VARIANT_EVEREST:
635*11fa71b9SJerome Forissier             return( mbedtls_everest_read_public( &ctx->ctx.everest_ecdh,
636*11fa71b9SJerome Forissier                                                  buf, blen ) );
637*11fa71b9SJerome Forissier #endif
6383d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
6393d3b0591SJens Wiklander             return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh,
6403d3b0591SJens Wiklander                                                        buf, blen ) );
6413d3b0591SJens Wiklander         default:
6423d3b0591SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
6433d3b0591SJens Wiklander     }
6443d3b0591SJens Wiklander #endif
6453d3b0591SJens Wiklander }
6463d3b0591SJens Wiklander 
6473d3b0591SJens Wiklander static int ecdh_calc_secret_internal( mbedtls_ecdh_context_mbed *ctx,
6483d3b0591SJens Wiklander                                       size_t *olen, unsigned char *buf,
6493d3b0591SJens Wiklander                                       size_t blen,
6503d3b0591SJens Wiklander                                       int (*f_rng)(void *,
6513d3b0591SJens Wiklander                                                    unsigned char *,
6523d3b0591SJens Wiklander                                                    size_t),
6533d3b0591SJens Wiklander                                       void *p_rng,
6543d3b0591SJens Wiklander                                       int restart_enabled )
6553d3b0591SJens Wiklander {
656*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
6573d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
6583d3b0591SJens Wiklander     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
6593d3b0591SJens Wiklander #endif
660817466cbSJens Wiklander 
6613d3b0591SJens Wiklander     if( ctx == NULL || ctx->grp.pbits == 0 )
662817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
663817466cbSJens Wiklander 
6643d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
6653d3b0591SJens Wiklander     if( restart_enabled )
6663d3b0591SJens Wiklander         rs_ctx = &ctx->rs;
6673d3b0591SJens Wiklander #else
6683d3b0591SJens Wiklander     (void) restart_enabled;
6693d3b0591SJens Wiklander #endif
6703d3b0591SJens Wiklander 
6713d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
6723d3b0591SJens Wiklander     if( ( ret = ecdh_compute_shared_restartable( &ctx->grp, &ctx->z, &ctx->Qp,
6733d3b0591SJens Wiklander                                                  &ctx->d, f_rng, p_rng,
6743d3b0591SJens Wiklander                                                  rs_ctx ) ) != 0 )
6753d3b0591SJens Wiklander     {
676817466cbSJens Wiklander         return( ret );
6773d3b0591SJens Wiklander     }
6783d3b0591SJens Wiklander #else
6793d3b0591SJens Wiklander     if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp,
6803d3b0591SJens Wiklander                                              &ctx->d, f_rng, p_rng ) ) != 0 )
6813d3b0591SJens Wiklander     {
6823d3b0591SJens Wiklander         return( ret );
6833d3b0591SJens Wiklander     }
6843d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */
685817466cbSJens Wiklander 
6863d3b0591SJens Wiklander     if( mbedtls_mpi_size( &ctx->z ) > blen )
687817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
688817466cbSJens Wiklander 
6893d3b0591SJens Wiklander     *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 );
690*11fa71b9SJerome Forissier 
691*11fa71b9SJerome Forissier     if( mbedtls_ecp_get_type( &ctx->grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
692*11fa71b9SJerome Forissier         return mbedtls_mpi_write_binary_le( &ctx->z, buf, *olen );
693*11fa71b9SJerome Forissier 
6943d3b0591SJens Wiklander     return mbedtls_mpi_write_binary( &ctx->z, buf, *olen );
695817466cbSJens Wiklander }
696817466cbSJens Wiklander 
697817466cbSJens Wiklander /*
698817466cbSJens Wiklander  * Derive and export the shared secret
699817466cbSJens Wiklander  */
700817466cbSJens Wiklander int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen,
701817466cbSJens Wiklander                               unsigned char *buf, size_t blen,
702817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
703817466cbSJens Wiklander                               void *p_rng )
704817466cbSJens Wiklander {
7053d3b0591SJens Wiklander     int restart_enabled = 0;
7063d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
7073d3b0591SJens Wiklander     ECDH_VALIDATE_RET( olen != NULL );
7083d3b0591SJens Wiklander     ECDH_VALIDATE_RET( buf != NULL );
709817466cbSJens Wiklander 
7103d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
7113d3b0591SJens Wiklander     restart_enabled = ctx->restart_enabled;
7123d3b0591SJens Wiklander #endif
713817466cbSJens Wiklander 
7143d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
7153d3b0591SJens Wiklander     return( ecdh_calc_secret_internal( ctx, olen, buf, blen, f_rng, p_rng,
7163d3b0591SJens Wiklander                                        restart_enabled ) );
7173d3b0591SJens Wiklander #else
7183d3b0591SJens Wiklander     switch( ctx->var )
719817466cbSJens Wiklander     {
720*11fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
721*11fa71b9SJerome Forissier         case MBEDTLS_ECDH_VARIANT_EVEREST:
722*11fa71b9SJerome Forissier             return( mbedtls_everest_calc_secret( &ctx->ctx.everest_ecdh, olen,
723*11fa71b9SJerome Forissier                                                  buf, blen, f_rng, p_rng ) );
724*11fa71b9SJerome Forissier #endif
7253d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
7263d3b0591SJens Wiklander             return( ecdh_calc_secret_internal( &ctx->ctx.mbed_ecdh, olen, buf,
7273d3b0591SJens Wiklander                                                blen, f_rng, p_rng,
7283d3b0591SJens Wiklander                                                restart_enabled ) );
7293d3b0591SJens Wiklander         default:
730817466cbSJens Wiklander             return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
7313d3b0591SJens Wiklander     }
7323d3b0591SJens Wiklander #endif
733817466cbSJens Wiklander }
734817466cbSJens Wiklander 
735817466cbSJens Wiklander #endif /* MBEDTLS_ECDH_C */
736