xref: /optee_os/lib/libmbedtls/mbedtls/library/ecdh.c (revision 3d3b05918ec9052ba13de82fbcaba204766eb636)
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"
38*3d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
39817466cbSJens Wiklander 
40817466cbSJens Wiklander #include <string.h>
41817466cbSJens Wiklander 
42*3d3b0591SJens Wiklander /* Parameter validation macros based on platform_util.h */
43*3d3b0591SJens Wiklander #define ECDH_VALIDATE_RET( cond )    \
44*3d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA )
45*3d3b0591SJens Wiklander #define ECDH_VALIDATE( cond )        \
46*3d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE( cond )
47*3d3b0591SJens Wiklander 
48*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
49*3d3b0591SJens Wiklander typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed;
50*3d3b0591SJens Wiklander #endif
51*3d3b0591SJens Wiklander 
52*3d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)
53817466cbSJens Wiklander /*
54*3d3b0591SJens Wiklander  * Generate public key (restartable version)
55*3d3b0591SJens Wiklander  *
56*3d3b0591SJens Wiklander  * Note: this internal function relies on its caller preserving the value of
57*3d3b0591SJens Wiklander  * the output parameter 'd' across continuation calls. This would not be
58*3d3b0591SJens Wiklander  * acceptable for a public function but is OK here as we control call sites.
59*3d3b0591SJens Wiklander  */
60*3d3b0591SJens Wiklander static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp,
61*3d3b0591SJens Wiklander                     mbedtls_mpi *d, mbedtls_ecp_point *Q,
62*3d3b0591SJens Wiklander                     int (*f_rng)(void *, unsigned char *, size_t),
63*3d3b0591SJens Wiklander                     void *p_rng,
64*3d3b0591SJens Wiklander                     mbedtls_ecp_restart_ctx *rs_ctx )
65*3d3b0591SJens Wiklander {
66*3d3b0591SJens Wiklander     int ret;
67*3d3b0591SJens Wiklander 
68*3d3b0591SJens Wiklander     /* If multiplication is in progress, we already generated a privkey */
69*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
70*3d3b0591SJens Wiklander     if( rs_ctx == NULL || rs_ctx->rsm == NULL )
71*3d3b0591SJens Wiklander #endif
72*3d3b0591SJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) );
73*3d3b0591SJens Wiklander 
74*3d3b0591SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G,
75*3d3b0591SJens Wiklander                                                   f_rng, p_rng, rs_ctx ) );
76*3d3b0591SJens Wiklander 
77*3d3b0591SJens Wiklander cleanup:
78*3d3b0591SJens Wiklander     return( ret );
79*3d3b0591SJens Wiklander }
80*3d3b0591SJens Wiklander 
81*3d3b0591SJens Wiklander /*
82*3d3b0591SJens Wiklander  * Generate public key
83817466cbSJens Wiklander  */
84817466cbSJens Wiklander int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,
85817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
86817466cbSJens Wiklander                      void *p_rng )
87817466cbSJens Wiklander {
88*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( grp != NULL );
89*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( d != NULL );
90*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( Q != NULL );
91*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( f_rng != NULL );
92*3d3b0591SJens Wiklander     return( ecdh_gen_public_restartable( grp, d, Q, f_rng, p_rng, NULL ) );
93817466cbSJens Wiklander }
94*3d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */
95817466cbSJens Wiklander 
96*3d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT)
97817466cbSJens Wiklander /*
98817466cbSJens Wiklander  * Compute shared secret (SEC1 3.3.1)
99817466cbSJens Wiklander  */
100*3d3b0591SJens Wiklander static int ecdh_compute_shared_restartable( mbedtls_ecp_group *grp,
101*3d3b0591SJens Wiklander                          mbedtls_mpi *z,
102817466cbSJens Wiklander                          const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
103817466cbSJens Wiklander                          int (*f_rng)(void *, unsigned char *, size_t),
104*3d3b0591SJens Wiklander                          void *p_rng,
105*3d3b0591SJens Wiklander                          mbedtls_ecp_restart_ctx *rs_ctx )
106817466cbSJens Wiklander {
107817466cbSJens Wiklander     int ret;
108817466cbSJens Wiklander     mbedtls_ecp_point P;
109817466cbSJens Wiklander 
110817466cbSJens Wiklander     mbedtls_ecp_point_init( &P );
111817466cbSJens Wiklander 
112*3d3b0591SJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &P, d, Q,
113*3d3b0591SJens Wiklander                                                   f_rng, p_rng, rs_ctx ) );
114817466cbSJens Wiklander 
115817466cbSJens Wiklander     if( mbedtls_ecp_is_zero( &P ) )
116817466cbSJens Wiklander     {
117817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
118817466cbSJens Wiklander         goto cleanup;
119817466cbSJens Wiklander     }
120817466cbSJens Wiklander 
121817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) );
122817466cbSJens Wiklander 
123817466cbSJens Wiklander cleanup:
124817466cbSJens Wiklander     mbedtls_ecp_point_free( &P );
125817466cbSJens Wiklander 
126817466cbSJens Wiklander     return( ret );
127817466cbSJens Wiklander }
128817466cbSJens Wiklander 
129817466cbSJens Wiklander /*
130*3d3b0591SJens Wiklander  * Compute shared secret (SEC1 3.3.1)
131*3d3b0591SJens Wiklander  */
132*3d3b0591SJens Wiklander int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,
133*3d3b0591SJens Wiklander                          const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
134*3d3b0591SJens Wiklander                          int (*f_rng)(void *, unsigned char *, size_t),
135*3d3b0591SJens Wiklander                          void *p_rng )
136*3d3b0591SJens Wiklander {
137*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( grp != NULL );
138*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( Q != NULL );
139*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( d != NULL );
140*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( z != NULL );
141*3d3b0591SJens Wiklander     return( ecdh_compute_shared_restartable( grp, z, Q, d,
142*3d3b0591SJens Wiklander                                              f_rng, p_rng, NULL ) );
143*3d3b0591SJens Wiklander }
144*3d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
145*3d3b0591SJens Wiklander 
146*3d3b0591SJens Wiklander static void ecdh_init_internal( mbedtls_ecdh_context_mbed *ctx )
147*3d3b0591SJens Wiklander {
148*3d3b0591SJens Wiklander     mbedtls_ecp_group_init( &ctx->grp );
149*3d3b0591SJens Wiklander     mbedtls_mpi_init( &ctx->d  );
150*3d3b0591SJens Wiklander     mbedtls_ecp_point_init( &ctx->Q   );
151*3d3b0591SJens Wiklander     mbedtls_ecp_point_init( &ctx->Qp  );
152*3d3b0591SJens Wiklander     mbedtls_mpi_init( &ctx->z  );
153*3d3b0591SJens Wiklander 
154*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
155*3d3b0591SJens Wiklander     mbedtls_ecp_restart_init( &ctx->rs );
156*3d3b0591SJens Wiklander #endif
157*3d3b0591SJens Wiklander }
158*3d3b0591SJens Wiklander 
159*3d3b0591SJens Wiklander /*
160817466cbSJens Wiklander  * Initialize context
161817466cbSJens Wiklander  */
162817466cbSJens Wiklander void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx )
163817466cbSJens Wiklander {
164*3d3b0591SJens Wiklander     ECDH_VALIDATE( ctx != NULL );
165*3d3b0591SJens Wiklander 
166*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
167*3d3b0591SJens Wiklander     ecdh_init_internal( ctx );
168*3d3b0591SJens Wiklander     mbedtls_ecp_point_init( &ctx->Vi  );
169*3d3b0591SJens Wiklander     mbedtls_ecp_point_init( &ctx->Vf  );
170*3d3b0591SJens Wiklander     mbedtls_mpi_init( &ctx->_d );
171*3d3b0591SJens Wiklander #else
172817466cbSJens Wiklander     memset( ctx, 0, sizeof( mbedtls_ecdh_context ) );
173*3d3b0591SJens Wiklander 
174*3d3b0591SJens Wiklander     ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
175*3d3b0591SJens Wiklander #endif
176*3d3b0591SJens Wiklander     ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
177*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
178*3d3b0591SJens Wiklander     ctx->restart_enabled = 0;
179*3d3b0591SJens Wiklander #endif
180817466cbSJens Wiklander }
181817466cbSJens Wiklander 
182*3d3b0591SJens Wiklander static int ecdh_setup_internal( mbedtls_ecdh_context_mbed *ctx,
183*3d3b0591SJens Wiklander                                 mbedtls_ecp_group_id grp_id )
184*3d3b0591SJens Wiklander {
185*3d3b0591SJens Wiklander     int ret;
186*3d3b0591SJens Wiklander 
187*3d3b0591SJens Wiklander     ret = mbedtls_ecp_group_load( &ctx->grp, grp_id );
188*3d3b0591SJens Wiklander     if( ret != 0 )
189*3d3b0591SJens Wiklander     {
190*3d3b0591SJens Wiklander         return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
191*3d3b0591SJens Wiklander     }
192*3d3b0591SJens Wiklander 
193*3d3b0591SJens Wiklander     return( 0 );
194*3d3b0591SJens Wiklander }
195*3d3b0591SJens Wiklander 
196*3d3b0591SJens Wiklander /*
197*3d3b0591SJens Wiklander  * Setup context
198*3d3b0591SJens Wiklander  */
199*3d3b0591SJens Wiklander int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id )
200*3d3b0591SJens Wiklander {
201*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
202*3d3b0591SJens Wiklander 
203*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
204*3d3b0591SJens Wiklander     return( ecdh_setup_internal( ctx, grp_id ) );
205*3d3b0591SJens Wiklander #else
206*3d3b0591SJens Wiklander     switch( grp_id )
207*3d3b0591SJens Wiklander     {
208*3d3b0591SJens Wiklander         default:
209*3d3b0591SJens Wiklander             ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
210*3d3b0591SJens Wiklander             ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0;
211*3d3b0591SJens Wiklander             ctx->grp_id = grp_id;
212*3d3b0591SJens Wiklander             ecdh_init_internal( &ctx->ctx.mbed_ecdh );
213*3d3b0591SJens Wiklander             return( ecdh_setup_internal( &ctx->ctx.mbed_ecdh, grp_id ) );
214*3d3b0591SJens Wiklander     }
215*3d3b0591SJens Wiklander #endif
216*3d3b0591SJens Wiklander }
217*3d3b0591SJens Wiklander 
218*3d3b0591SJens Wiklander static void ecdh_free_internal( mbedtls_ecdh_context_mbed *ctx )
219*3d3b0591SJens Wiklander {
220*3d3b0591SJens Wiklander     mbedtls_ecp_group_free( &ctx->grp );
221*3d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->d  );
222*3d3b0591SJens Wiklander     mbedtls_ecp_point_free( &ctx->Q   );
223*3d3b0591SJens Wiklander     mbedtls_ecp_point_free( &ctx->Qp  );
224*3d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->z  );
225*3d3b0591SJens Wiklander 
226*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
227*3d3b0591SJens Wiklander     mbedtls_ecp_restart_free( &ctx->rs );
228*3d3b0591SJens Wiklander #endif
229*3d3b0591SJens Wiklander }
230*3d3b0591SJens Wiklander 
231*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
232*3d3b0591SJens Wiklander /*
233*3d3b0591SJens Wiklander  * Enable restartable operations for context
234*3d3b0591SJens Wiklander  */
235*3d3b0591SJens Wiklander void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx )
236*3d3b0591SJens Wiklander {
237*3d3b0591SJens Wiklander     ECDH_VALIDATE( ctx != NULL );
238*3d3b0591SJens Wiklander 
239*3d3b0591SJens Wiklander     ctx->restart_enabled = 1;
240*3d3b0591SJens Wiklander }
241*3d3b0591SJens Wiklander #endif
242*3d3b0591SJens Wiklander 
243817466cbSJens Wiklander /*
244817466cbSJens Wiklander  * Free context
245817466cbSJens Wiklander  */
246817466cbSJens Wiklander void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx )
247817466cbSJens Wiklander {
248817466cbSJens Wiklander     if( ctx == NULL )
249817466cbSJens Wiklander         return;
250817466cbSJens Wiklander 
251*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
252817466cbSJens Wiklander     mbedtls_ecp_point_free( &ctx->Vi );
253817466cbSJens Wiklander     mbedtls_ecp_point_free( &ctx->Vf );
254817466cbSJens Wiklander     mbedtls_mpi_free( &ctx->_d );
255*3d3b0591SJens Wiklander     ecdh_free_internal( ctx );
256*3d3b0591SJens Wiklander #else
257*3d3b0591SJens Wiklander     switch( ctx->var )
258*3d3b0591SJens Wiklander     {
259*3d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
260*3d3b0591SJens Wiklander             ecdh_free_internal( &ctx->ctx.mbed_ecdh );
261*3d3b0591SJens Wiklander             break;
262*3d3b0591SJens Wiklander         default:
263*3d3b0591SJens Wiklander             break;
264*3d3b0591SJens Wiklander     }
265*3d3b0591SJens Wiklander 
266*3d3b0591SJens Wiklander     ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
267*3d3b0591SJens Wiklander     ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
268*3d3b0591SJens Wiklander     ctx->grp_id = MBEDTLS_ECP_DP_NONE;
269*3d3b0591SJens Wiklander #endif
270*3d3b0591SJens Wiklander }
271*3d3b0591SJens Wiklander 
272*3d3b0591SJens Wiklander static int ecdh_make_params_internal( mbedtls_ecdh_context_mbed *ctx,
273*3d3b0591SJens Wiklander                                       size_t *olen, int point_format,
274*3d3b0591SJens Wiklander                                       unsigned char *buf, size_t blen,
275*3d3b0591SJens Wiklander                                       int (*f_rng)(void *,
276*3d3b0591SJens Wiklander                                                    unsigned char *,
277*3d3b0591SJens Wiklander                                                    size_t),
278*3d3b0591SJens Wiklander                                       void *p_rng,
279*3d3b0591SJens Wiklander                                       int restart_enabled )
280*3d3b0591SJens Wiklander {
281*3d3b0591SJens Wiklander     int ret;
282*3d3b0591SJens Wiklander     size_t grp_len, pt_len;
283*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
284*3d3b0591SJens Wiklander     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
285*3d3b0591SJens Wiklander #endif
286*3d3b0591SJens Wiklander 
287*3d3b0591SJens Wiklander     if( ctx->grp.pbits == 0 )
288*3d3b0591SJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
289*3d3b0591SJens Wiklander 
290*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
291*3d3b0591SJens Wiklander     if( restart_enabled )
292*3d3b0591SJens Wiklander         rs_ctx = &ctx->rs;
293*3d3b0591SJens Wiklander #else
294*3d3b0591SJens Wiklander     (void) restart_enabled;
295*3d3b0591SJens Wiklander #endif
296*3d3b0591SJens Wiklander 
297*3d3b0591SJens Wiklander 
298*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
299*3d3b0591SJens Wiklander     if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
300*3d3b0591SJens Wiklander                                              f_rng, p_rng, rs_ctx ) ) != 0 )
301*3d3b0591SJens Wiklander         return( ret );
302*3d3b0591SJens Wiklander #else
303*3d3b0591SJens Wiklander     if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
304*3d3b0591SJens Wiklander                                          f_rng, p_rng ) ) != 0 )
305*3d3b0591SJens Wiklander         return( ret );
306*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */
307*3d3b0591SJens Wiklander 
308*3d3b0591SJens Wiklander     if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf,
309*3d3b0591SJens Wiklander                                              blen ) ) != 0 )
310*3d3b0591SJens Wiklander         return( ret );
311*3d3b0591SJens Wiklander 
312*3d3b0591SJens Wiklander     buf += grp_len;
313*3d3b0591SJens Wiklander     blen -= grp_len;
314*3d3b0591SJens Wiklander 
315*3d3b0591SJens Wiklander     if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format,
316*3d3b0591SJens Wiklander                                              &pt_len, buf, blen ) ) != 0 )
317*3d3b0591SJens Wiklander         return( ret );
318*3d3b0591SJens Wiklander 
319*3d3b0591SJens Wiklander     *olen = grp_len + pt_len;
320*3d3b0591SJens Wiklander     return( 0 );
321817466cbSJens Wiklander }
322817466cbSJens Wiklander 
323817466cbSJens Wiklander /*
324817466cbSJens Wiklander  * Setup and write the ServerKeyExhange parameters (RFC 4492)
325817466cbSJens Wiklander  *      struct {
326817466cbSJens Wiklander  *          ECParameters    curve_params;
327817466cbSJens Wiklander  *          ECPoint         public;
328817466cbSJens Wiklander  *      } ServerECDHParams;
329817466cbSJens Wiklander  */
330817466cbSJens Wiklander int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
331817466cbSJens Wiklander                               unsigned char *buf, size_t blen,
332817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
333817466cbSJens Wiklander                               void *p_rng )
334817466cbSJens Wiklander {
335*3d3b0591SJens Wiklander     int restart_enabled = 0;
336*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
337*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( olen != NULL );
338*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( buf != NULL );
339*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( f_rng != NULL );
340817466cbSJens Wiklander 
341*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
342*3d3b0591SJens Wiklander     restart_enabled = ctx->restart_enabled;
343*3d3b0591SJens Wiklander #else
344*3d3b0591SJens Wiklander     (void) restart_enabled;
345*3d3b0591SJens Wiklander #endif
346817466cbSJens Wiklander 
347*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
348*3d3b0591SJens Wiklander     return( ecdh_make_params_internal( ctx, olen, ctx->point_format, buf, blen,
349*3d3b0591SJens Wiklander                                        f_rng, p_rng, restart_enabled ) );
350*3d3b0591SJens Wiklander #else
351*3d3b0591SJens Wiklander     switch( ctx->var )
352*3d3b0591SJens Wiklander     {
353*3d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
354*3d3b0591SJens Wiklander             return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen,
355*3d3b0591SJens Wiklander                                                ctx->point_format, buf, blen,
356*3d3b0591SJens Wiklander                                                f_rng, p_rng,
357*3d3b0591SJens Wiklander                                                restart_enabled ) );
358*3d3b0591SJens Wiklander         default:
359*3d3b0591SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
360*3d3b0591SJens Wiklander     }
361*3d3b0591SJens Wiklander #endif
362*3d3b0591SJens Wiklander }
363817466cbSJens Wiklander 
364*3d3b0591SJens Wiklander static int ecdh_read_params_internal( mbedtls_ecdh_context_mbed *ctx,
365*3d3b0591SJens Wiklander                                       const unsigned char **buf,
366*3d3b0591SJens Wiklander                                       const unsigned char *end )
367*3d3b0591SJens Wiklander {
368*3d3b0591SJens Wiklander     return( mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf,
369*3d3b0591SJens Wiklander                                         end - *buf ) );
370817466cbSJens Wiklander }
371817466cbSJens Wiklander 
372817466cbSJens Wiklander /*
373817466cbSJens Wiklander  * Read the ServerKeyExhange parameters (RFC 4492)
374817466cbSJens Wiklander  *      struct {
375817466cbSJens Wiklander  *          ECParameters    curve_params;
376817466cbSJens Wiklander  *          ECPoint         public;
377817466cbSJens Wiklander  *      } ServerECDHParams;
378817466cbSJens Wiklander  */
379817466cbSJens Wiklander int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx,
380*3d3b0591SJens Wiklander                               const unsigned char **buf,
381*3d3b0591SJens Wiklander                               const unsigned char *end )
382817466cbSJens Wiklander {
383817466cbSJens Wiklander     int ret;
384*3d3b0591SJens Wiklander     mbedtls_ecp_group_id grp_id;
385*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
386*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( buf != NULL );
387*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( *buf != NULL );
388*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( end != NULL );
389817466cbSJens Wiklander 
390*3d3b0591SJens Wiklander     if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, end - *buf ) )
391817466cbSJens Wiklander             != 0 )
392817466cbSJens Wiklander         return( ret );
393817466cbSJens Wiklander 
394*3d3b0591SJens Wiklander     if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 )
395*3d3b0591SJens Wiklander         return( ret );
396*3d3b0591SJens Wiklander 
397*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
398*3d3b0591SJens Wiklander     return( ecdh_read_params_internal( ctx, buf, end ) );
399*3d3b0591SJens Wiklander #else
400*3d3b0591SJens Wiklander     switch( ctx->var )
401*3d3b0591SJens Wiklander     {
402*3d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
403*3d3b0591SJens Wiklander             return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh,
404*3d3b0591SJens Wiklander                                                buf, end ) );
405*3d3b0591SJens Wiklander         default:
406*3d3b0591SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
407*3d3b0591SJens Wiklander     }
408*3d3b0591SJens Wiklander #endif
409817466cbSJens Wiklander }
410817466cbSJens Wiklander 
411*3d3b0591SJens Wiklander static int ecdh_get_params_internal( mbedtls_ecdh_context_mbed *ctx,
412*3d3b0591SJens Wiklander                                      const mbedtls_ecp_keypair *key,
413817466cbSJens Wiklander                                      mbedtls_ecdh_side side )
414817466cbSJens Wiklander {
415817466cbSJens Wiklander     int ret;
416817466cbSJens Wiklander 
417817466cbSJens Wiklander     /* If it's not our key, just import the public part as Qp */
418817466cbSJens Wiklander     if( side == MBEDTLS_ECDH_THEIRS )
419817466cbSJens Wiklander         return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) );
420817466cbSJens Wiklander 
421817466cbSJens Wiklander     /* Our key: import public (as Q) and private parts */
422817466cbSJens Wiklander     if( side != MBEDTLS_ECDH_OURS )
423817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
424817466cbSJens Wiklander 
425817466cbSJens Wiklander     if( ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 ||
426817466cbSJens Wiklander         ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 )
427817466cbSJens Wiklander         return( ret );
428817466cbSJens Wiklander 
429817466cbSJens Wiklander     return( 0 );
430817466cbSJens Wiklander }
431817466cbSJens Wiklander 
432817466cbSJens Wiklander /*
433*3d3b0591SJens Wiklander  * Get parameters from a keypair
434*3d3b0591SJens Wiklander  */
435*3d3b0591SJens Wiklander int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx,
436*3d3b0591SJens Wiklander                              const mbedtls_ecp_keypair *key,
437*3d3b0591SJens Wiklander                              mbedtls_ecdh_side side )
438*3d3b0591SJens Wiklander {
439*3d3b0591SJens Wiklander     int ret;
440*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
441*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( key != NULL );
442*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( side == MBEDTLS_ECDH_OURS ||
443*3d3b0591SJens Wiklander                        side == MBEDTLS_ECDH_THEIRS );
444*3d3b0591SJens Wiklander 
445*3d3b0591SJens Wiklander     if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 )
446*3d3b0591SJens Wiklander         return( ret );
447*3d3b0591SJens Wiklander 
448*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
449*3d3b0591SJens Wiklander     return( ecdh_get_params_internal( ctx, key, side ) );
450*3d3b0591SJens Wiklander #else
451*3d3b0591SJens Wiklander     switch( ctx->var )
452*3d3b0591SJens Wiklander     {
453*3d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
454*3d3b0591SJens Wiklander             return( ecdh_get_params_internal( &ctx->ctx.mbed_ecdh,
455*3d3b0591SJens Wiklander                                               key, side ) );
456*3d3b0591SJens Wiklander         default:
457*3d3b0591SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
458*3d3b0591SJens Wiklander     }
459*3d3b0591SJens Wiklander #endif
460*3d3b0591SJens Wiklander }
461*3d3b0591SJens Wiklander 
462*3d3b0591SJens Wiklander static int ecdh_make_public_internal( mbedtls_ecdh_context_mbed *ctx,
463*3d3b0591SJens Wiklander                                       size_t *olen, int point_format,
464*3d3b0591SJens Wiklander                                       unsigned char *buf, size_t blen,
465*3d3b0591SJens Wiklander                                       int (*f_rng)(void *,
466*3d3b0591SJens Wiklander                                                    unsigned char *,
467*3d3b0591SJens Wiklander                                                    size_t),
468*3d3b0591SJens Wiklander                                       void *p_rng,
469*3d3b0591SJens Wiklander                                       int restart_enabled )
470*3d3b0591SJens Wiklander {
471*3d3b0591SJens Wiklander     int ret;
472*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
473*3d3b0591SJens Wiklander     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
474*3d3b0591SJens Wiklander #endif
475*3d3b0591SJens Wiklander 
476*3d3b0591SJens Wiklander     if( ctx->grp.pbits == 0 )
477*3d3b0591SJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
478*3d3b0591SJens Wiklander 
479*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
480*3d3b0591SJens Wiklander     if( restart_enabled )
481*3d3b0591SJens Wiklander         rs_ctx = &ctx->rs;
482*3d3b0591SJens Wiklander #else
483*3d3b0591SJens Wiklander     (void) restart_enabled;
484*3d3b0591SJens Wiklander #endif
485*3d3b0591SJens Wiklander 
486*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
487*3d3b0591SJens Wiklander     if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
488*3d3b0591SJens Wiklander                                              f_rng, p_rng, rs_ctx ) ) != 0 )
489*3d3b0591SJens Wiklander         return( ret );
490*3d3b0591SJens Wiklander #else
491*3d3b0591SJens Wiklander     if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
492*3d3b0591SJens Wiklander                                          f_rng, p_rng ) ) != 0 )
493*3d3b0591SJens Wiklander         return( ret );
494*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */
495*3d3b0591SJens Wiklander 
496*3d3b0591SJens Wiklander     return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, olen,
497*3d3b0591SJens Wiklander                                         buf, blen );
498*3d3b0591SJens Wiklander }
499*3d3b0591SJens Wiklander 
500*3d3b0591SJens Wiklander /*
501817466cbSJens Wiklander  * Setup and export the client public value
502817466cbSJens Wiklander  */
503817466cbSJens Wiklander int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen,
504817466cbSJens Wiklander                               unsigned char *buf, size_t blen,
505817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
506817466cbSJens Wiklander                               void *p_rng )
507817466cbSJens Wiklander {
508*3d3b0591SJens Wiklander     int restart_enabled = 0;
509*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
510*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( olen != NULL );
511*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( buf != NULL );
512*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( f_rng != NULL );
513*3d3b0591SJens Wiklander 
514*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
515*3d3b0591SJens Wiklander     restart_enabled = ctx->restart_enabled;
516*3d3b0591SJens Wiklander #endif
517*3d3b0591SJens Wiklander 
518*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
519*3d3b0591SJens Wiklander     return( ecdh_make_public_internal( ctx, olen, ctx->point_format, buf, blen,
520*3d3b0591SJens Wiklander                                        f_rng, p_rng, restart_enabled ) );
521*3d3b0591SJens Wiklander #else
522*3d3b0591SJens Wiklander     switch( ctx->var )
523*3d3b0591SJens Wiklander     {
524*3d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
525*3d3b0591SJens Wiklander             return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen,
526*3d3b0591SJens Wiklander                                                ctx->point_format, buf, blen,
527*3d3b0591SJens Wiklander                                                f_rng, p_rng,
528*3d3b0591SJens Wiklander                                                restart_enabled ) );
529*3d3b0591SJens Wiklander         default:
530*3d3b0591SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
531*3d3b0591SJens Wiklander     }
532*3d3b0591SJens Wiklander #endif
533*3d3b0591SJens Wiklander }
534*3d3b0591SJens Wiklander 
535*3d3b0591SJens Wiklander static int ecdh_read_public_internal( mbedtls_ecdh_context_mbed *ctx,
536*3d3b0591SJens Wiklander                                       const unsigned char *buf, size_t blen )
537*3d3b0591SJens Wiklander {
538817466cbSJens Wiklander     int ret;
539*3d3b0591SJens Wiklander     const unsigned char *p = buf;
540817466cbSJens Wiklander 
541*3d3b0591SJens Wiklander     if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p,
542*3d3b0591SJens Wiklander                                             blen ) ) != 0 )
543817466cbSJens Wiklander         return( ret );
544817466cbSJens Wiklander 
545*3d3b0591SJens Wiklander     if( (size_t)( p - buf ) != blen )
546*3d3b0591SJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
547*3d3b0591SJens Wiklander 
548*3d3b0591SJens Wiklander     return( 0 );
549817466cbSJens Wiklander }
550817466cbSJens Wiklander 
551817466cbSJens Wiklander /*
552817466cbSJens Wiklander  * Parse and import the client's public value
553817466cbSJens Wiklander  */
554817466cbSJens Wiklander int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx,
555817466cbSJens Wiklander                               const unsigned char *buf, size_t blen )
556817466cbSJens Wiklander {
557*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
558*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( buf != NULL );
559*3d3b0591SJens Wiklander 
560*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
561*3d3b0591SJens Wiklander     return( ecdh_read_public_internal( ctx, buf, blen ) );
562*3d3b0591SJens Wiklander #else
563*3d3b0591SJens Wiklander     switch( ctx->var )
564*3d3b0591SJens Wiklander     {
565*3d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
566*3d3b0591SJens Wiklander             return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh,
567*3d3b0591SJens Wiklander                                                        buf, blen ) );
568*3d3b0591SJens Wiklander         default:
569*3d3b0591SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
570*3d3b0591SJens Wiklander     }
571*3d3b0591SJens Wiklander #endif
572*3d3b0591SJens Wiklander }
573*3d3b0591SJens Wiklander 
574*3d3b0591SJens Wiklander static int ecdh_calc_secret_internal( mbedtls_ecdh_context_mbed *ctx,
575*3d3b0591SJens Wiklander                                       size_t *olen, unsigned char *buf,
576*3d3b0591SJens Wiklander                                       size_t blen,
577*3d3b0591SJens Wiklander                                       int (*f_rng)(void *,
578*3d3b0591SJens Wiklander                                                    unsigned char *,
579*3d3b0591SJens Wiklander                                                    size_t),
580*3d3b0591SJens Wiklander                                       void *p_rng,
581*3d3b0591SJens Wiklander                                       int restart_enabled )
582*3d3b0591SJens Wiklander {
583817466cbSJens Wiklander     int ret;
584*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
585*3d3b0591SJens Wiklander     mbedtls_ecp_restart_ctx *rs_ctx = NULL;
586*3d3b0591SJens Wiklander #endif
587817466cbSJens Wiklander 
588*3d3b0591SJens Wiklander     if( ctx == NULL || ctx->grp.pbits == 0 )
589817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
590817466cbSJens Wiklander 
591*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
592*3d3b0591SJens Wiklander     if( restart_enabled )
593*3d3b0591SJens Wiklander         rs_ctx = &ctx->rs;
594*3d3b0591SJens Wiklander #else
595*3d3b0591SJens Wiklander     (void) restart_enabled;
596*3d3b0591SJens Wiklander #endif
597*3d3b0591SJens Wiklander 
598*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
599*3d3b0591SJens Wiklander     if( ( ret = ecdh_compute_shared_restartable( &ctx->grp, &ctx->z, &ctx->Qp,
600*3d3b0591SJens Wiklander                                                  &ctx->d, f_rng, p_rng,
601*3d3b0591SJens Wiklander                                                  rs_ctx ) ) != 0 )
602*3d3b0591SJens Wiklander     {
603817466cbSJens Wiklander         return( ret );
604*3d3b0591SJens Wiklander     }
605*3d3b0591SJens Wiklander #else
606*3d3b0591SJens Wiklander     if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp,
607*3d3b0591SJens Wiklander                                              &ctx->d, f_rng, p_rng ) ) != 0 )
608*3d3b0591SJens Wiklander     {
609*3d3b0591SJens Wiklander         return( ret );
610*3d3b0591SJens Wiklander     }
611*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */
612817466cbSJens Wiklander 
613*3d3b0591SJens Wiklander     if( mbedtls_mpi_size( &ctx->z ) > blen )
614817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
615817466cbSJens Wiklander 
616*3d3b0591SJens Wiklander     *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 );
617*3d3b0591SJens Wiklander     return mbedtls_mpi_write_binary( &ctx->z, buf, *olen );
618817466cbSJens Wiklander }
619817466cbSJens Wiklander 
620817466cbSJens Wiklander /*
621817466cbSJens Wiklander  * Derive and export the shared secret
622817466cbSJens Wiklander  */
623817466cbSJens Wiklander int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen,
624817466cbSJens Wiklander                               unsigned char *buf, size_t blen,
625817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
626817466cbSJens Wiklander                               void *p_rng )
627817466cbSJens Wiklander {
628*3d3b0591SJens Wiklander     int restart_enabled = 0;
629*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( ctx != NULL );
630*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( olen != NULL );
631*3d3b0591SJens Wiklander     ECDH_VALIDATE_RET( buf != NULL );
632817466cbSJens Wiklander 
633*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE)
634*3d3b0591SJens Wiklander     restart_enabled = ctx->restart_enabled;
635*3d3b0591SJens Wiklander #endif
636817466cbSJens Wiklander 
637*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
638*3d3b0591SJens Wiklander     return( ecdh_calc_secret_internal( ctx, olen, buf, blen, f_rng, p_rng,
639*3d3b0591SJens Wiklander                                        restart_enabled ) );
640*3d3b0591SJens Wiklander #else
641*3d3b0591SJens Wiklander     switch( ctx->var )
642817466cbSJens Wiklander     {
643*3d3b0591SJens Wiklander         case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
644*3d3b0591SJens Wiklander             return( ecdh_calc_secret_internal( &ctx->ctx.mbed_ecdh, olen, buf,
645*3d3b0591SJens Wiklander                                                blen, f_rng, p_rng,
646*3d3b0591SJens Wiklander                                                restart_enabled ) );
647*3d3b0591SJens Wiklander         default:
648817466cbSJens Wiklander             return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
649*3d3b0591SJens Wiklander     }
650*3d3b0591SJens Wiklander #endif
651817466cbSJens Wiklander }
652817466cbSJens Wiklander 
653817466cbSJens Wiklander #endif /* MBEDTLS_ECDH_C */
654