1*817466cbSJens Wiklander /* 2*817466cbSJens Wiklander * Elliptic curve Diffie-Hellman 3*817466cbSJens Wiklander * 4*817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 5*817466cbSJens Wiklander * SPDX-License-Identifier: Apache-2.0 6*817466cbSJens Wiklander * 7*817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8*817466cbSJens Wiklander * not use this file except in compliance with the License. 9*817466cbSJens Wiklander * You may obtain a copy of the License at 10*817466cbSJens Wiklander * 11*817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12*817466cbSJens Wiklander * 13*817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14*817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15*817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16*817466cbSJens Wiklander * See the License for the specific language governing permissions and 17*817466cbSJens Wiklander * limitations under the License. 18*817466cbSJens Wiklander * 19*817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 20*817466cbSJens Wiklander */ 21*817466cbSJens Wiklander 22*817466cbSJens Wiklander /* 23*817466cbSJens Wiklander * References: 24*817466cbSJens Wiklander * 25*817466cbSJens Wiklander * SEC1 http://www.secg.org/index.php?action=secg,docs_secg 26*817466cbSJens Wiklander * RFC 4492 27*817466cbSJens Wiklander */ 28*817466cbSJens Wiklander 29*817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 30*817466cbSJens Wiklander #include "mbedtls/config.h" 31*817466cbSJens Wiklander #else 32*817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 33*817466cbSJens Wiklander #endif 34*817466cbSJens Wiklander 35*817466cbSJens Wiklander #if defined(MBEDTLS_ECDH_C) 36*817466cbSJens Wiklander 37*817466cbSJens Wiklander #include "mbedtls/ecdh.h" 38*817466cbSJens Wiklander 39*817466cbSJens Wiklander #include <string.h> 40*817466cbSJens Wiklander 41*817466cbSJens Wiklander /* 42*817466cbSJens Wiklander * Generate public key: simple wrapper around mbedtls_ecp_gen_keypair 43*817466cbSJens Wiklander */ 44*817466cbSJens Wiklander int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, 45*817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 46*817466cbSJens Wiklander void *p_rng ) 47*817466cbSJens Wiklander { 48*817466cbSJens Wiklander return mbedtls_ecp_gen_keypair( grp, d, Q, f_rng, p_rng ); 49*817466cbSJens Wiklander } 50*817466cbSJens Wiklander 51*817466cbSJens Wiklander /* 52*817466cbSJens Wiklander * Compute shared secret (SEC1 3.3.1) 53*817466cbSJens Wiklander */ 54*817466cbSJens Wiklander int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, 55*817466cbSJens Wiklander const mbedtls_ecp_point *Q, const mbedtls_mpi *d, 56*817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 57*817466cbSJens Wiklander void *p_rng ) 58*817466cbSJens Wiklander { 59*817466cbSJens Wiklander int ret; 60*817466cbSJens Wiklander mbedtls_ecp_point P; 61*817466cbSJens Wiklander 62*817466cbSJens Wiklander mbedtls_ecp_point_init( &P ); 63*817466cbSJens Wiklander 64*817466cbSJens Wiklander /* 65*817466cbSJens Wiklander * Make sure Q is a valid pubkey before using it 66*817466cbSJens Wiklander */ 67*817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); 68*817466cbSJens Wiklander 69*817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) ); 70*817466cbSJens Wiklander 71*817466cbSJens Wiklander if( mbedtls_ecp_is_zero( &P ) ) 72*817466cbSJens Wiklander { 73*817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 74*817466cbSJens Wiklander goto cleanup; 75*817466cbSJens Wiklander } 76*817466cbSJens Wiklander 77*817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) ); 78*817466cbSJens Wiklander 79*817466cbSJens Wiklander cleanup: 80*817466cbSJens Wiklander mbedtls_ecp_point_free( &P ); 81*817466cbSJens Wiklander 82*817466cbSJens Wiklander return( ret ); 83*817466cbSJens Wiklander } 84*817466cbSJens Wiklander 85*817466cbSJens Wiklander /* 86*817466cbSJens Wiklander * Initialize context 87*817466cbSJens Wiklander */ 88*817466cbSJens Wiklander void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) 89*817466cbSJens Wiklander { 90*817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_ecdh_context ) ); 91*817466cbSJens Wiklander } 92*817466cbSJens Wiklander 93*817466cbSJens Wiklander /* 94*817466cbSJens Wiklander * Free context 95*817466cbSJens Wiklander */ 96*817466cbSJens Wiklander void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) 97*817466cbSJens Wiklander { 98*817466cbSJens Wiklander if( ctx == NULL ) 99*817466cbSJens Wiklander return; 100*817466cbSJens Wiklander 101*817466cbSJens Wiklander mbedtls_ecp_group_free( &ctx->grp ); 102*817466cbSJens Wiklander mbedtls_ecp_point_free( &ctx->Q ); 103*817466cbSJens Wiklander mbedtls_ecp_point_free( &ctx->Qp ); 104*817466cbSJens Wiklander mbedtls_ecp_point_free( &ctx->Vi ); 105*817466cbSJens Wiklander mbedtls_ecp_point_free( &ctx->Vf ); 106*817466cbSJens Wiklander mbedtls_mpi_free( &ctx->d ); 107*817466cbSJens Wiklander mbedtls_mpi_free( &ctx->z ); 108*817466cbSJens Wiklander mbedtls_mpi_free( &ctx->_d ); 109*817466cbSJens Wiklander } 110*817466cbSJens Wiklander 111*817466cbSJens Wiklander /* 112*817466cbSJens Wiklander * Setup and write the ServerKeyExhange parameters (RFC 4492) 113*817466cbSJens Wiklander * struct { 114*817466cbSJens Wiklander * ECParameters curve_params; 115*817466cbSJens Wiklander * ECPoint public; 116*817466cbSJens Wiklander * } ServerECDHParams; 117*817466cbSJens Wiklander */ 118*817466cbSJens Wiklander int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, 119*817466cbSJens Wiklander unsigned char *buf, size_t blen, 120*817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 121*817466cbSJens Wiklander void *p_rng ) 122*817466cbSJens Wiklander { 123*817466cbSJens Wiklander int ret; 124*817466cbSJens Wiklander size_t grp_len, pt_len; 125*817466cbSJens Wiklander 126*817466cbSJens Wiklander if( ctx == NULL || ctx->grp.pbits == 0 ) 127*817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 128*817466cbSJens Wiklander 129*817466cbSJens Wiklander if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) 130*817466cbSJens Wiklander != 0 ) 131*817466cbSJens Wiklander return( ret ); 132*817466cbSJens Wiklander 133*817466cbSJens Wiklander if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, blen ) ) 134*817466cbSJens Wiklander != 0 ) 135*817466cbSJens Wiklander return( ret ); 136*817466cbSJens Wiklander 137*817466cbSJens Wiklander buf += grp_len; 138*817466cbSJens Wiklander blen -= grp_len; 139*817466cbSJens Wiklander 140*817466cbSJens Wiklander if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, 141*817466cbSJens Wiklander &pt_len, buf, blen ) ) != 0 ) 142*817466cbSJens Wiklander return( ret ); 143*817466cbSJens Wiklander 144*817466cbSJens Wiklander *olen = grp_len + pt_len; 145*817466cbSJens Wiklander return( 0 ); 146*817466cbSJens Wiklander } 147*817466cbSJens Wiklander 148*817466cbSJens Wiklander /* 149*817466cbSJens Wiklander * Read the ServerKeyExhange parameters (RFC 4492) 150*817466cbSJens Wiklander * struct { 151*817466cbSJens Wiklander * ECParameters curve_params; 152*817466cbSJens Wiklander * ECPoint public; 153*817466cbSJens Wiklander * } ServerECDHParams; 154*817466cbSJens Wiklander */ 155*817466cbSJens Wiklander int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, 156*817466cbSJens Wiklander const unsigned char **buf, const unsigned char *end ) 157*817466cbSJens Wiklander { 158*817466cbSJens Wiklander int ret; 159*817466cbSJens Wiklander 160*817466cbSJens Wiklander if( ( ret = mbedtls_ecp_tls_read_group( &ctx->grp, buf, end - *buf ) ) != 0 ) 161*817466cbSJens Wiklander return( ret ); 162*817466cbSJens Wiklander 163*817466cbSJens Wiklander if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, end - *buf ) ) 164*817466cbSJens Wiklander != 0 ) 165*817466cbSJens Wiklander return( ret ); 166*817466cbSJens Wiklander 167*817466cbSJens Wiklander return( 0 ); 168*817466cbSJens Wiklander } 169*817466cbSJens Wiklander 170*817466cbSJens Wiklander /* 171*817466cbSJens Wiklander * Get parameters from a keypair 172*817466cbSJens Wiklander */ 173*817466cbSJens Wiklander int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key, 174*817466cbSJens Wiklander mbedtls_ecdh_side side ) 175*817466cbSJens Wiklander { 176*817466cbSJens Wiklander int ret; 177*817466cbSJens Wiklander 178*817466cbSJens Wiklander if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 ) 179*817466cbSJens Wiklander return( ret ); 180*817466cbSJens Wiklander 181*817466cbSJens Wiklander /* If it's not our key, just import the public part as Qp */ 182*817466cbSJens Wiklander if( side == MBEDTLS_ECDH_THEIRS ) 183*817466cbSJens Wiklander return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) ); 184*817466cbSJens Wiklander 185*817466cbSJens Wiklander /* Our key: import public (as Q) and private parts */ 186*817466cbSJens Wiklander if( side != MBEDTLS_ECDH_OURS ) 187*817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 188*817466cbSJens Wiklander 189*817466cbSJens Wiklander if( ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 || 190*817466cbSJens Wiklander ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 ) 191*817466cbSJens Wiklander return( ret ); 192*817466cbSJens Wiklander 193*817466cbSJens Wiklander return( 0 ); 194*817466cbSJens Wiklander } 195*817466cbSJens Wiklander 196*817466cbSJens Wiklander /* 197*817466cbSJens Wiklander * Setup and export the client public value 198*817466cbSJens Wiklander */ 199*817466cbSJens Wiklander int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, 200*817466cbSJens Wiklander unsigned char *buf, size_t blen, 201*817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 202*817466cbSJens Wiklander void *p_rng ) 203*817466cbSJens Wiklander { 204*817466cbSJens Wiklander int ret; 205*817466cbSJens Wiklander 206*817466cbSJens Wiklander if( ctx == NULL || ctx->grp.pbits == 0 ) 207*817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 208*817466cbSJens Wiklander 209*817466cbSJens Wiklander if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) 210*817466cbSJens Wiklander != 0 ) 211*817466cbSJens Wiklander return( ret ); 212*817466cbSJens Wiklander 213*817466cbSJens Wiklander return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, 214*817466cbSJens Wiklander olen, buf, blen ); 215*817466cbSJens Wiklander } 216*817466cbSJens Wiklander 217*817466cbSJens Wiklander /* 218*817466cbSJens Wiklander * Parse and import the client's public value 219*817466cbSJens Wiklander */ 220*817466cbSJens Wiklander int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, 221*817466cbSJens Wiklander const unsigned char *buf, size_t blen ) 222*817466cbSJens Wiklander { 223*817466cbSJens Wiklander int ret; 224*817466cbSJens Wiklander const unsigned char *p = buf; 225*817466cbSJens Wiklander 226*817466cbSJens Wiklander if( ctx == NULL ) 227*817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 228*817466cbSJens Wiklander 229*817466cbSJens Wiklander if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, blen ) ) != 0 ) 230*817466cbSJens Wiklander return( ret ); 231*817466cbSJens Wiklander 232*817466cbSJens Wiklander if( (size_t)( p - buf ) != blen ) 233*817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 234*817466cbSJens Wiklander 235*817466cbSJens Wiklander return( 0 ); 236*817466cbSJens Wiklander } 237*817466cbSJens Wiklander 238*817466cbSJens Wiklander /* 239*817466cbSJens Wiklander * Derive and export the shared secret 240*817466cbSJens Wiklander */ 241*817466cbSJens Wiklander int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, 242*817466cbSJens Wiklander unsigned char *buf, size_t blen, 243*817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 244*817466cbSJens Wiklander void *p_rng ) 245*817466cbSJens Wiklander { 246*817466cbSJens Wiklander int ret; 247*817466cbSJens Wiklander 248*817466cbSJens Wiklander if( ctx == NULL ) 249*817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 250*817466cbSJens Wiklander 251*817466cbSJens Wiklander if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d, 252*817466cbSJens Wiklander f_rng, p_rng ) ) != 0 ) 253*817466cbSJens Wiklander { 254*817466cbSJens Wiklander return( ret ); 255*817466cbSJens Wiklander } 256*817466cbSJens Wiklander 257*817466cbSJens Wiklander if( mbedtls_mpi_size( &ctx->z ) > blen ) 258*817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 259*817466cbSJens Wiklander 260*817466cbSJens Wiklander *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 ); 261*817466cbSJens Wiklander return mbedtls_mpi_write_binary( &ctx->z, buf, *olen ); 262*817466cbSJens Wiklander } 263*817466cbSJens Wiklander 264*817466cbSJens Wiklander #endif /* MBEDTLS_ECDH_C */ 265