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