1 /* 2 * Elliptic curve Diffie-Hellman 3 * 4 * Copyright The Mbed TLS Contributors 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 47 /* 48 * References: 49 * 50 * SEC1 http://www.secg.org/index.php?action=secg,docs_secg 51 * RFC 4492 52 */ 53 54 #if !defined(MBEDTLS_CONFIG_FILE) 55 #include "mbedtls/config.h" 56 #else 57 #include MBEDTLS_CONFIG_FILE 58 #endif 59 60 #if defined(MBEDTLS_ECDH_C) 61 62 #include "mbedtls/ecdh.h" 63 #include "mbedtls/platform_util.h" 64 65 #include <string.h> 66 67 /* Parameter validation macros based on platform_util.h */ 68 #define ECDH_VALIDATE_RET( cond ) \ 69 MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) 70 #define ECDH_VALIDATE( cond ) \ 71 MBEDTLS_INTERNAL_VALIDATE( cond ) 72 73 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 74 typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed; 75 #endif 76 77 static mbedtls_ecp_group_id mbedtls_ecdh_grp_id( 78 const mbedtls_ecdh_context *ctx ) 79 { 80 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 81 return( ctx->grp.id ); 82 #else 83 return( ctx->grp_id ); 84 #endif 85 } 86 87 #if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) 88 /* 89 * Generate public key (restartable version) 90 * 91 * Note: this internal function relies on its caller preserving the value of 92 * the output parameter 'd' across continuation calls. This would not be 93 * acceptable for a public function but is OK here as we control call sites. 94 */ 95 static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp, 96 mbedtls_mpi *d, mbedtls_ecp_point *Q, 97 int (*f_rng)(void *, unsigned char *, size_t), 98 void *p_rng, 99 mbedtls_ecp_restart_ctx *rs_ctx ) 100 { 101 int ret; 102 103 /* If multiplication is in progress, we already generated a privkey */ 104 #if defined(MBEDTLS_ECP_RESTARTABLE) 105 if( rs_ctx == NULL || rs_ctx->rsm == NULL ) 106 #endif 107 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) ); 108 109 MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G, 110 f_rng, p_rng, rs_ctx ) ); 111 112 cleanup: 113 return( ret ); 114 } 115 116 /* 117 * Generate public key 118 */ 119 int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, 120 int (*f_rng)(void *, unsigned char *, size_t), 121 void *p_rng ) 122 { 123 ECDH_VALIDATE_RET( grp != NULL ); 124 ECDH_VALIDATE_RET( d != NULL ); 125 ECDH_VALIDATE_RET( Q != NULL ); 126 ECDH_VALIDATE_RET( f_rng != NULL ); 127 return( ecdh_gen_public_restartable( grp, d, Q, f_rng, p_rng, NULL ) ); 128 } 129 #endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */ 130 131 #if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) 132 /* 133 * Compute shared secret (SEC1 3.3.1) 134 */ 135 static int ecdh_compute_shared_restartable( mbedtls_ecp_group *grp, 136 mbedtls_mpi *z, 137 const mbedtls_ecp_point *Q, const mbedtls_mpi *d, 138 int (*f_rng)(void *, unsigned char *, size_t), 139 void *p_rng, 140 mbedtls_ecp_restart_ctx *rs_ctx ) 141 { 142 int ret; 143 mbedtls_ecp_point P; 144 145 mbedtls_ecp_point_init( &P ); 146 147 MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &P, d, Q, 148 f_rng, p_rng, rs_ctx ) ); 149 150 if( mbedtls_ecp_is_zero( &P ) ) 151 { 152 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 153 goto cleanup; 154 } 155 156 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) ); 157 158 cleanup: 159 mbedtls_ecp_point_free( &P ); 160 161 return( ret ); 162 } 163 164 /* 165 * Compute shared secret (SEC1 3.3.1) 166 */ 167 int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, 168 const mbedtls_ecp_point *Q, const mbedtls_mpi *d, 169 int (*f_rng)(void *, unsigned char *, size_t), 170 void *p_rng ) 171 { 172 ECDH_VALIDATE_RET( grp != NULL ); 173 ECDH_VALIDATE_RET( Q != NULL ); 174 ECDH_VALIDATE_RET( d != NULL ); 175 ECDH_VALIDATE_RET( z != NULL ); 176 return( ecdh_compute_shared_restartable( grp, z, Q, d, 177 f_rng, p_rng, NULL ) ); 178 } 179 #endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */ 180 181 static void ecdh_init_internal( mbedtls_ecdh_context_mbed *ctx ) 182 { 183 mbedtls_ecp_group_init( &ctx->grp ); 184 mbedtls_mpi_init( &ctx->d ); 185 mbedtls_ecp_point_init( &ctx->Q ); 186 mbedtls_ecp_point_init( &ctx->Qp ); 187 mbedtls_mpi_init( &ctx->z ); 188 189 #if defined(MBEDTLS_ECP_RESTARTABLE) 190 mbedtls_ecp_restart_init( &ctx->rs ); 191 #endif 192 } 193 194 /* 195 * Initialize context 196 */ 197 void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) 198 { 199 ECDH_VALIDATE( ctx != NULL ); 200 201 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 202 ecdh_init_internal( ctx ); 203 mbedtls_ecp_point_init( &ctx->Vi ); 204 mbedtls_ecp_point_init( &ctx->Vf ); 205 mbedtls_mpi_init( &ctx->_d ); 206 #else 207 memset( ctx, 0, sizeof( mbedtls_ecdh_context ) ); 208 209 ctx->var = MBEDTLS_ECDH_VARIANT_NONE; 210 #endif 211 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; 212 #if defined(MBEDTLS_ECP_RESTARTABLE) 213 ctx->restart_enabled = 0; 214 #endif 215 } 216 217 static int ecdh_setup_internal( mbedtls_ecdh_context_mbed *ctx, 218 mbedtls_ecp_group_id grp_id ) 219 { 220 int ret; 221 222 ret = mbedtls_ecp_group_load( &ctx->grp, grp_id ); 223 if( ret != 0 ) 224 { 225 return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); 226 } 227 228 return( 0 ); 229 } 230 231 /* 232 * Setup context 233 */ 234 int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id ) 235 { 236 ECDH_VALIDATE_RET( ctx != NULL ); 237 238 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 239 return( ecdh_setup_internal( ctx, grp_id ) ); 240 #else 241 switch( grp_id ) 242 { 243 default: 244 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; 245 ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0; 246 ctx->grp_id = grp_id; 247 ecdh_init_internal( &ctx->ctx.mbed_ecdh ); 248 return( ecdh_setup_internal( &ctx->ctx.mbed_ecdh, grp_id ) ); 249 } 250 #endif 251 } 252 253 static void ecdh_free_internal( mbedtls_ecdh_context_mbed *ctx ) 254 { 255 mbedtls_ecp_group_free( &ctx->grp ); 256 mbedtls_mpi_free( &ctx->d ); 257 mbedtls_ecp_point_free( &ctx->Q ); 258 mbedtls_ecp_point_free( &ctx->Qp ); 259 mbedtls_mpi_free( &ctx->z ); 260 261 #if defined(MBEDTLS_ECP_RESTARTABLE) 262 mbedtls_ecp_restart_free( &ctx->rs ); 263 #endif 264 } 265 266 #if defined(MBEDTLS_ECP_RESTARTABLE) 267 /* 268 * Enable restartable operations for context 269 */ 270 void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx ) 271 { 272 ECDH_VALIDATE( ctx != NULL ); 273 274 ctx->restart_enabled = 1; 275 } 276 #endif 277 278 /* 279 * Free context 280 */ 281 void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) 282 { 283 if( ctx == NULL ) 284 return; 285 286 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 287 mbedtls_ecp_point_free( &ctx->Vi ); 288 mbedtls_ecp_point_free( &ctx->Vf ); 289 mbedtls_mpi_free( &ctx->_d ); 290 ecdh_free_internal( ctx ); 291 #else 292 switch( ctx->var ) 293 { 294 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 295 ecdh_free_internal( &ctx->ctx.mbed_ecdh ); 296 break; 297 default: 298 break; 299 } 300 301 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; 302 ctx->var = MBEDTLS_ECDH_VARIANT_NONE; 303 ctx->grp_id = MBEDTLS_ECP_DP_NONE; 304 #endif 305 } 306 307 static int ecdh_make_params_internal( mbedtls_ecdh_context_mbed *ctx, 308 size_t *olen, int point_format, 309 unsigned char *buf, size_t blen, 310 int (*f_rng)(void *, 311 unsigned char *, 312 size_t), 313 void *p_rng, 314 int restart_enabled ) 315 { 316 int ret; 317 size_t grp_len, pt_len; 318 #if defined(MBEDTLS_ECP_RESTARTABLE) 319 mbedtls_ecp_restart_ctx *rs_ctx = NULL; 320 #endif 321 322 if( ctx->grp.pbits == 0 ) 323 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 324 325 #if defined(MBEDTLS_ECP_RESTARTABLE) 326 if( restart_enabled ) 327 rs_ctx = &ctx->rs; 328 #else 329 (void) restart_enabled; 330 #endif 331 332 333 #if defined(MBEDTLS_ECP_RESTARTABLE) 334 if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, 335 f_rng, p_rng, rs_ctx ) ) != 0 ) 336 return( ret ); 337 #else 338 if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, 339 f_rng, p_rng ) ) != 0 ) 340 return( ret ); 341 #endif /* MBEDTLS_ECP_RESTARTABLE */ 342 343 if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, 344 blen ) ) != 0 ) 345 return( ret ); 346 347 buf += grp_len; 348 blen -= grp_len; 349 350 if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, 351 &pt_len, buf, blen ) ) != 0 ) 352 return( ret ); 353 354 *olen = grp_len + pt_len; 355 return( 0 ); 356 } 357 358 /* 359 * Setup and write the ServerKeyExhange parameters (RFC 4492) 360 * struct { 361 * ECParameters curve_params; 362 * ECPoint public; 363 * } ServerECDHParams; 364 */ 365 int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, 366 unsigned char *buf, size_t blen, 367 int (*f_rng)(void *, unsigned char *, size_t), 368 void *p_rng ) 369 { 370 int restart_enabled = 0; 371 ECDH_VALIDATE_RET( ctx != NULL ); 372 ECDH_VALIDATE_RET( olen != NULL ); 373 ECDH_VALIDATE_RET( buf != NULL ); 374 ECDH_VALIDATE_RET( f_rng != NULL ); 375 376 #if defined(MBEDTLS_ECP_RESTARTABLE) 377 restart_enabled = ctx->restart_enabled; 378 #else 379 (void) restart_enabled; 380 #endif 381 382 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 383 return( ecdh_make_params_internal( ctx, olen, ctx->point_format, buf, blen, 384 f_rng, p_rng, restart_enabled ) ); 385 #else 386 switch( ctx->var ) 387 { 388 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 389 return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen, 390 ctx->point_format, buf, blen, 391 f_rng, p_rng, 392 restart_enabled ) ); 393 default: 394 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 395 } 396 #endif 397 } 398 399 static int ecdh_read_params_internal( mbedtls_ecdh_context_mbed *ctx, 400 const unsigned char **buf, 401 const unsigned char *end ) 402 { 403 return( mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, 404 end - *buf ) ); 405 } 406 407 /* 408 * Read the ServerKeyExhange parameters (RFC 4492) 409 * struct { 410 * ECParameters curve_params; 411 * ECPoint public; 412 * } ServerECDHParams; 413 */ 414 int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, 415 const unsigned char **buf, 416 const unsigned char *end ) 417 { 418 int ret; 419 mbedtls_ecp_group_id grp_id; 420 ECDH_VALIDATE_RET( ctx != NULL ); 421 ECDH_VALIDATE_RET( buf != NULL ); 422 ECDH_VALIDATE_RET( *buf != NULL ); 423 ECDH_VALIDATE_RET( end != NULL ); 424 425 if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, end - *buf ) ) 426 != 0 ) 427 return( ret ); 428 429 if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 ) 430 return( ret ); 431 432 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 433 return( ecdh_read_params_internal( ctx, buf, end ) ); 434 #else 435 switch( ctx->var ) 436 { 437 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 438 return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh, 439 buf, end ) ); 440 default: 441 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 442 } 443 #endif 444 } 445 446 static int ecdh_get_params_internal( mbedtls_ecdh_context_mbed *ctx, 447 const mbedtls_ecp_keypair *key, 448 mbedtls_ecdh_side side ) 449 { 450 int ret; 451 452 /* If it's not our key, just import the public part as Qp */ 453 if( side == MBEDTLS_ECDH_THEIRS ) 454 return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) ); 455 456 /* Our key: import public (as Q) and private parts */ 457 if( side != MBEDTLS_ECDH_OURS ) 458 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 459 460 if( ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 || 461 ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 ) 462 return( ret ); 463 464 return( 0 ); 465 } 466 467 /* 468 * Get parameters from a keypair 469 */ 470 int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, 471 const mbedtls_ecp_keypair *key, 472 mbedtls_ecdh_side side ) 473 { 474 int ret; 475 ECDH_VALIDATE_RET( ctx != NULL ); 476 ECDH_VALIDATE_RET( key != NULL ); 477 ECDH_VALIDATE_RET( side == MBEDTLS_ECDH_OURS || 478 side == MBEDTLS_ECDH_THEIRS ); 479 480 if( mbedtls_ecdh_grp_id( ctx ) == MBEDTLS_ECP_DP_NONE ) 481 { 482 /* This is the first call to get_params(). Set up the context 483 * for use with the group. */ 484 if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 ) 485 return( ret ); 486 } 487 else 488 { 489 /* This is not the first call to get_params(). Check that the 490 * current key's group is the same as the context's, which was set 491 * from the first key's group. */ 492 if( mbedtls_ecdh_grp_id( ctx ) != key->grp.id ) 493 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 494 } 495 496 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 497 return( ecdh_get_params_internal( ctx, key, side ) ); 498 #else 499 switch( ctx->var ) 500 { 501 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 502 return( ecdh_get_params_internal( &ctx->ctx.mbed_ecdh, 503 key, side ) ); 504 default: 505 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 506 } 507 #endif 508 } 509 510 static int ecdh_make_public_internal( mbedtls_ecdh_context_mbed *ctx, 511 size_t *olen, int point_format, 512 unsigned char *buf, size_t blen, 513 int (*f_rng)(void *, 514 unsigned char *, 515 size_t), 516 void *p_rng, 517 int restart_enabled ) 518 { 519 int ret; 520 #if defined(MBEDTLS_ECP_RESTARTABLE) 521 mbedtls_ecp_restart_ctx *rs_ctx = NULL; 522 #endif 523 524 if( ctx->grp.pbits == 0 ) 525 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 526 527 #if defined(MBEDTLS_ECP_RESTARTABLE) 528 if( restart_enabled ) 529 rs_ctx = &ctx->rs; 530 #else 531 (void) restart_enabled; 532 #endif 533 534 #if defined(MBEDTLS_ECP_RESTARTABLE) 535 if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, 536 f_rng, p_rng, rs_ctx ) ) != 0 ) 537 return( ret ); 538 #else 539 if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, 540 f_rng, p_rng ) ) != 0 ) 541 return( ret ); 542 #endif /* MBEDTLS_ECP_RESTARTABLE */ 543 544 return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, olen, 545 buf, blen ); 546 } 547 548 /* 549 * Setup and export the client public value 550 */ 551 int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, 552 unsigned char *buf, size_t blen, 553 int (*f_rng)(void *, unsigned char *, size_t), 554 void *p_rng ) 555 { 556 int restart_enabled = 0; 557 ECDH_VALIDATE_RET( ctx != NULL ); 558 ECDH_VALIDATE_RET( olen != NULL ); 559 ECDH_VALIDATE_RET( buf != NULL ); 560 ECDH_VALIDATE_RET( f_rng != NULL ); 561 562 #if defined(MBEDTLS_ECP_RESTARTABLE) 563 restart_enabled = ctx->restart_enabled; 564 #endif 565 566 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 567 return( ecdh_make_public_internal( ctx, olen, ctx->point_format, buf, blen, 568 f_rng, p_rng, restart_enabled ) ); 569 #else 570 switch( ctx->var ) 571 { 572 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 573 return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen, 574 ctx->point_format, buf, blen, 575 f_rng, p_rng, 576 restart_enabled ) ); 577 default: 578 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 579 } 580 #endif 581 } 582 583 static int ecdh_read_public_internal( mbedtls_ecdh_context_mbed *ctx, 584 const unsigned char *buf, size_t blen ) 585 { 586 int ret; 587 const unsigned char *p = buf; 588 589 if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, 590 blen ) ) != 0 ) 591 return( ret ); 592 593 if( (size_t)( p - buf ) != blen ) 594 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 595 596 return( 0 ); 597 } 598 599 /* 600 * Parse and import the client's public value 601 */ 602 int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, 603 const unsigned char *buf, size_t blen ) 604 { 605 ECDH_VALIDATE_RET( ctx != NULL ); 606 ECDH_VALIDATE_RET( buf != NULL ); 607 608 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 609 return( ecdh_read_public_internal( ctx, buf, blen ) ); 610 #else 611 switch( ctx->var ) 612 { 613 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 614 return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh, 615 buf, blen ) ); 616 default: 617 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 618 } 619 #endif 620 } 621 622 static int ecdh_calc_secret_internal( mbedtls_ecdh_context_mbed *ctx, 623 size_t *olen, unsigned char *buf, 624 size_t blen, 625 int (*f_rng)(void *, 626 unsigned char *, 627 size_t), 628 void *p_rng, 629 int restart_enabled ) 630 { 631 int ret; 632 #if defined(MBEDTLS_ECP_RESTARTABLE) 633 mbedtls_ecp_restart_ctx *rs_ctx = NULL; 634 #endif 635 636 if( ctx == NULL || ctx->grp.pbits == 0 ) 637 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 638 639 #if defined(MBEDTLS_ECP_RESTARTABLE) 640 if( restart_enabled ) 641 rs_ctx = &ctx->rs; 642 #else 643 (void) restart_enabled; 644 #endif 645 646 #if defined(MBEDTLS_ECP_RESTARTABLE) 647 if( ( ret = ecdh_compute_shared_restartable( &ctx->grp, &ctx->z, &ctx->Qp, 648 &ctx->d, f_rng, p_rng, 649 rs_ctx ) ) != 0 ) 650 { 651 return( ret ); 652 } 653 #else 654 if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, 655 &ctx->d, f_rng, p_rng ) ) != 0 ) 656 { 657 return( ret ); 658 } 659 #endif /* MBEDTLS_ECP_RESTARTABLE */ 660 661 if( mbedtls_mpi_size( &ctx->z ) > blen ) 662 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 663 664 *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 ); 665 return mbedtls_mpi_write_binary( &ctx->z, buf, *olen ); 666 } 667 668 /* 669 * Derive and export the shared secret 670 */ 671 int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, 672 unsigned char *buf, size_t blen, 673 int (*f_rng)(void *, unsigned char *, size_t), 674 void *p_rng ) 675 { 676 int restart_enabled = 0; 677 ECDH_VALIDATE_RET( ctx != NULL ); 678 ECDH_VALIDATE_RET( olen != NULL ); 679 ECDH_VALIDATE_RET( buf != NULL ); 680 681 #if defined(MBEDTLS_ECP_RESTARTABLE) 682 restart_enabled = ctx->restart_enabled; 683 #endif 684 685 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 686 return( ecdh_calc_secret_internal( ctx, olen, buf, blen, f_rng, p_rng, 687 restart_enabled ) ); 688 #else 689 switch( ctx->var ) 690 { 691 case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 692 return( ecdh_calc_secret_internal( &ctx->ctx.mbed_ecdh, olen, buf, 693 blen, f_rng, p_rng, 694 restart_enabled ) ); 695 default: 696 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 697 } 698 #endif 699 } 700 701 #endif /* MBEDTLS_ECDH_C */ 702