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