1 /* 2 * Diffie-Hellman-Merkle key exchange 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 * The following sources were referenced in the design of this implementation 48 * of the Diffie-Hellman-Merkle algorithm: 49 * 50 * [1] Handbook of Applied Cryptography - 1997, Chapter 12 51 * Menezes, van Oorschot and Vanstone 52 * 53 */ 54 55 #if !defined(MBEDTLS_CONFIG_FILE) 56 #include "mbedtls/config.h" 57 #else 58 #include MBEDTLS_CONFIG_FILE 59 #endif 60 61 #if defined(MBEDTLS_DHM_C) 62 63 #include "mbedtls/dhm.h" 64 #include "mbedtls/platform_util.h" 65 66 #include <string.h> 67 68 #if defined(MBEDTLS_PEM_PARSE_C) 69 #include "mbedtls/pem.h" 70 #endif 71 72 #if defined(MBEDTLS_ASN1_PARSE_C) 73 #include "mbedtls/asn1.h" 74 #endif 75 76 #if defined(MBEDTLS_PLATFORM_C) 77 #include "mbedtls/platform.h" 78 #else 79 #include <stdlib.h> 80 #include <stdio.h> 81 #define mbedtls_printf printf 82 #define mbedtls_calloc calloc 83 #define mbedtls_free free 84 #endif 85 86 #if !defined(MBEDTLS_DHM_ALT) 87 88 #define DHM_VALIDATE_RET( cond ) \ 89 MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA ) 90 #define DHM_VALIDATE( cond ) \ 91 MBEDTLS_INTERNAL_VALIDATE( cond ) 92 93 /* 94 * helper to validate the mbedtls_mpi size and import it 95 */ 96 static int dhm_read_bignum( mbedtls_mpi *X, 97 unsigned char **p, 98 const unsigned char *end ) 99 { 100 int ret, n; 101 102 if( end - *p < 2 ) 103 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 104 105 n = ( (*p)[0] << 8 ) | (*p)[1]; 106 (*p) += 2; 107 108 if( (int)( end - *p ) < n ) 109 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 110 111 if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 ) 112 return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret ); 113 114 (*p) += n; 115 116 return( 0 ); 117 } 118 119 /* 120 * Verify sanity of parameter with regards to P 121 * 122 * Parameter should be: 2 <= public_param <= P - 2 123 * 124 * This means that we need to return an error if 125 * public_param < 2 or public_param > P-2 126 * 127 * For more information on the attack, see: 128 * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf 129 * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643 130 */ 131 static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P ) 132 { 133 mbedtls_mpi U; 134 int ret = 0; 135 136 mbedtls_mpi_init( &U ); 137 138 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) ); 139 140 if( mbedtls_mpi_cmp_int( param, 2 ) < 0 || 141 mbedtls_mpi_cmp_mpi( param, &U ) > 0 ) 142 { 143 ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA; 144 } 145 146 cleanup: 147 mbedtls_mpi_free( &U ); 148 return( ret ); 149 } 150 151 void mbedtls_dhm_init( mbedtls_dhm_context *ctx ) 152 { 153 DHM_VALIDATE( ctx != NULL ); 154 memset( ctx, 0, sizeof( mbedtls_dhm_context ) ); 155 } 156 157 /* 158 * Parse the ServerKeyExchange parameters 159 */ 160 int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, 161 unsigned char **p, 162 const unsigned char *end ) 163 { 164 int ret; 165 DHM_VALIDATE_RET( ctx != NULL ); 166 DHM_VALIDATE_RET( p != NULL && *p != NULL ); 167 DHM_VALIDATE_RET( end != NULL ); 168 169 if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 || 170 ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 || 171 ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 ) 172 return( ret ); 173 174 if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) 175 return( ret ); 176 177 ctx->len = mbedtls_mpi_size( &ctx->P ); 178 179 return( 0 ); 180 } 181 182 /* 183 * Pick a random R in the range [2, M-2] for blinding or key generation. 184 */ 185 static int dhm_random_below( mbedtls_mpi *R, const mbedtls_mpi *M, 186 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) 187 { 188 int ret, count; 189 size_t m_size = mbedtls_mpi_size( M ); 190 size_t m_bitlen = mbedtls_mpi_bitlen( M ); 191 192 count = 0; 193 do 194 { 195 if( count++ > 30 ) 196 return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); 197 198 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( R, m_size, f_rng, p_rng ) ); 199 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( R, ( m_size * 8 ) - m_bitlen ) ); 200 } 201 while( dhm_check_range( R, M ) != 0 ); 202 203 cleanup: 204 return( ret ); 205 } 206 207 static int dhm_make_common( mbedtls_dhm_context *ctx, int x_size, 208 int (*f_rng)(void *, unsigned char *, size_t), 209 void *p_rng ) 210 { 211 int ret = 0; 212 213 if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) 214 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 215 if( x_size < 0 ) 216 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 217 218 if( (unsigned) x_size < mbedtls_mpi_size( &ctx->P ) ) 219 { 220 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) ); 221 } 222 else 223 { 224 /* Generate X as large as possible ( <= P - 2 ) */ 225 ret = dhm_random_below( &ctx->X, &ctx->P, f_rng, p_rng ); 226 if( ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) 227 return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED ); 228 if( ret != 0 ) 229 return( ret ); 230 } 231 232 /* 233 * Calculate GX = G^X mod P 234 */ 235 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, 236 &ctx->P , &ctx->RP ) ); 237 238 if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) 239 return( ret ); 240 241 cleanup: 242 return( ret ); 243 } 244 245 /* 246 * Setup and write the ServerKeyExchange parameters 247 */ 248 int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, 249 unsigned char *output, size_t *olen, 250 int (*f_rng)(void *, unsigned char *, size_t), 251 void *p_rng ) 252 { 253 int ret; 254 size_t n1, n2, n3; 255 unsigned char *p; 256 DHM_VALIDATE_RET( ctx != NULL ); 257 DHM_VALIDATE_RET( output != NULL ); 258 DHM_VALIDATE_RET( olen != NULL ); 259 DHM_VALIDATE_RET( f_rng != NULL ); 260 261 ret = dhm_make_common( ctx, x_size, f_rng, p_rng ); 262 if( ret != 0 ) 263 goto cleanup; 264 265 /* 266 * Export P, G, GX. RFC 5246 §4.4 states that "leading zero octets are 267 * not required". We omit leading zeros for compactness. 268 */ 269 #define DHM_MPI_EXPORT( X, n ) \ 270 do { \ 271 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( ( X ), \ 272 p + 2, \ 273 ( n ) ) ); \ 274 *p++ = (unsigned char)( ( n ) >> 8 ); \ 275 *p++ = (unsigned char)( ( n ) ); \ 276 p += ( n ); \ 277 } while( 0 ) 278 279 n1 = mbedtls_mpi_size( &ctx->P ); 280 n2 = mbedtls_mpi_size( &ctx->G ); 281 n3 = mbedtls_mpi_size( &ctx->GX ); 282 283 p = output; 284 DHM_MPI_EXPORT( &ctx->P , n1 ); 285 DHM_MPI_EXPORT( &ctx->G , n2 ); 286 DHM_MPI_EXPORT( &ctx->GX, n3 ); 287 288 *olen = p - output; 289 290 ctx->len = n1; 291 292 cleanup: 293 if( ret != 0 && ret > -128 ) 294 return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret ); 295 return( ret ); 296 } 297 298 /* 299 * Set prime modulus and generator 300 */ 301 int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx, 302 const mbedtls_mpi *P, 303 const mbedtls_mpi *G ) 304 { 305 int ret; 306 DHM_VALIDATE_RET( ctx != NULL ); 307 DHM_VALIDATE_RET( P != NULL ); 308 DHM_VALIDATE_RET( G != NULL ); 309 310 if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 || 311 ( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 ) 312 { 313 return( MBEDTLS_ERR_DHM_SET_GROUP_FAILED + ret ); 314 } 315 316 ctx->len = mbedtls_mpi_size( &ctx->P ); 317 return( 0 ); 318 } 319 320 /* 321 * Import the peer's public value G^Y 322 */ 323 int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, 324 const unsigned char *input, size_t ilen ) 325 { 326 int ret; 327 DHM_VALIDATE_RET( ctx != NULL ); 328 DHM_VALIDATE_RET( input != NULL ); 329 330 if( ilen < 1 || ilen > ctx->len ) 331 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 332 333 if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 ) 334 return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret ); 335 336 return( 0 ); 337 } 338 339 /* 340 * Create own private value X and export G^X 341 */ 342 int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, 343 unsigned char *output, size_t olen, 344 int (*f_rng)(void *, unsigned char *, size_t), 345 void *p_rng ) 346 { 347 int ret; 348 DHM_VALIDATE_RET( ctx != NULL ); 349 DHM_VALIDATE_RET( output != NULL ); 350 DHM_VALIDATE_RET( f_rng != NULL ); 351 352 if( olen < 1 || olen > ctx->len ) 353 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 354 355 ret = dhm_make_common( ctx, x_size, f_rng, p_rng ); 356 if( ret == MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED ) 357 return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED ); 358 if( ret != 0 ) 359 goto cleanup; 360 361 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) ); 362 363 cleanup: 364 if( ret != 0 && ret > -128 ) 365 return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret ); 366 367 return( ret ); 368 } 369 370 371 /* 372 * Use the blinding method and optimisation suggested in section 10 of: 373 * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, 374 * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer 375 * Berlin Heidelberg, 1996. p. 104-113. 376 */ 377 static int dhm_update_blinding( mbedtls_dhm_context *ctx, 378 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) 379 { 380 int ret; 381 mbedtls_mpi R; 382 383 mbedtls_mpi_init( &R ); 384 385 /* 386 * Don't use any blinding the first time a particular X is used, 387 * but remember it to use blinding next time. 388 */ 389 if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 ) 390 { 391 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) ); 392 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) ); 393 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) ); 394 395 return( 0 ); 396 } 397 398 /* 399 * Ok, we need blinding. Can we re-use existing values? 400 * If yes, just update them by squaring them. 401 */ 402 if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ) 403 { 404 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); 405 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) ); 406 407 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); 408 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) ); 409 410 return( 0 ); 411 } 412 413 /* 414 * We need to generate blinding values from scratch 415 */ 416 417 /* Vi = random( 2, P-2 ) */ 418 MBEDTLS_MPI_CHK( dhm_random_below( &ctx->Vi, &ctx->P, f_rng, p_rng ) ); 419 420 /* Vf = Vi^-X mod P 421 * First compute Vi^-1 = R * (R Vi)^-1, (avoiding leaks from inv_mod), 422 * then elevate to the Xth power. */ 423 MBEDTLS_MPI_CHK( dhm_random_below( &R, &ctx->P, f_rng, p_rng ) ); 424 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vi, &R ) ); 425 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) ); 426 MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vf, &ctx->P ) ); 427 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &R ) ); 428 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) ); 429 430 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) ); 431 432 cleanup: 433 mbedtls_mpi_free( &R ); 434 435 return( ret ); 436 } 437 438 /* 439 * Derive and export the shared secret (G^Y)^X mod P 440 */ 441 int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, 442 unsigned char *output, size_t output_size, size_t *olen, 443 int (*f_rng)(void *, unsigned char *, size_t), 444 void *p_rng ) 445 { 446 int ret; 447 mbedtls_mpi GYb; 448 DHM_VALIDATE_RET( ctx != NULL ); 449 DHM_VALIDATE_RET( output != NULL ); 450 DHM_VALIDATE_RET( olen != NULL ); 451 452 if( output_size < ctx->len ) 453 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 454 455 if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) 456 return( ret ); 457 458 mbedtls_mpi_init( &GYb ); 459 460 /* Blind peer's value */ 461 if( f_rng != NULL ) 462 { 463 MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) ); 464 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) ); 465 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) ); 466 } 467 else 468 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) ); 469 470 /* Do modular exponentiation */ 471 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X, 472 &ctx->P, &ctx->RP ) ); 473 474 /* Unblind secret value */ 475 if( f_rng != NULL ) 476 { 477 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) ); 478 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) ); 479 } 480 481 /* Output the secret without any leading zero byte. This is mandatory 482 * for TLS per RFC 5246 §8.1.2. */ 483 *olen = mbedtls_mpi_size( &ctx->K ); 484 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) ); 485 486 cleanup: 487 mbedtls_mpi_free( &GYb ); 488 489 if( ret != 0 ) 490 return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret ); 491 492 return( 0 ); 493 } 494 495 /* 496 * Free the components of a DHM key 497 */ 498 void mbedtls_dhm_free( mbedtls_dhm_context *ctx ) 499 { 500 if( ctx == NULL ) 501 return; 502 503 mbedtls_mpi_free( &ctx->pX ); 504 mbedtls_mpi_free( &ctx->Vf ); 505 mbedtls_mpi_free( &ctx->Vi ); 506 mbedtls_mpi_free( &ctx->RP ); 507 mbedtls_mpi_free( &ctx->K ); 508 mbedtls_mpi_free( &ctx->GY ); 509 mbedtls_mpi_free( &ctx->GX ); 510 mbedtls_mpi_free( &ctx->X ); 511 mbedtls_mpi_free( &ctx->G ); 512 mbedtls_mpi_free( &ctx->P ); 513 514 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_dhm_context ) ); 515 } 516 517 #if defined(MBEDTLS_ASN1_PARSE_C) 518 /* 519 * Parse DHM parameters 520 */ 521 int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, 522 size_t dhminlen ) 523 { 524 int ret; 525 size_t len; 526 unsigned char *p, *end; 527 #if defined(MBEDTLS_PEM_PARSE_C) 528 mbedtls_pem_context pem; 529 #endif /* MBEDTLS_PEM_PARSE_C */ 530 531 DHM_VALIDATE_RET( dhm != NULL ); 532 DHM_VALIDATE_RET( dhmin != NULL ); 533 534 #if defined(MBEDTLS_PEM_PARSE_C) 535 mbedtls_pem_init( &pem ); 536 537 /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 538 if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' ) 539 ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 540 else 541 ret = mbedtls_pem_read_buffer( &pem, 542 "-----BEGIN DH PARAMETERS-----", 543 "-----END DH PARAMETERS-----", 544 dhmin, NULL, 0, &dhminlen ); 545 546 if( ret == 0 ) 547 { 548 /* 549 * Was PEM encoded 550 */ 551 dhminlen = pem.buflen; 552 } 553 else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 554 goto exit; 555 556 p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin; 557 #else 558 p = (unsigned char *) dhmin; 559 #endif /* MBEDTLS_PEM_PARSE_C */ 560 end = p + dhminlen; 561 562 /* 563 * DHParams ::= SEQUENCE { 564 * prime INTEGER, -- P 565 * generator INTEGER, -- g 566 * privateValueLength INTEGER OPTIONAL 567 * } 568 */ 569 if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 570 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 571 { 572 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; 573 goto exit; 574 } 575 576 end = p + len; 577 578 if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P ) ) != 0 || 579 ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 ) 580 { 581 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; 582 goto exit; 583 } 584 585 if( p != end ) 586 { 587 /* This might be the optional privateValueLength. 588 * If so, we can cleanly discard it */ 589 mbedtls_mpi rec; 590 mbedtls_mpi_init( &rec ); 591 ret = mbedtls_asn1_get_mpi( &p, end, &rec ); 592 mbedtls_mpi_free( &rec ); 593 if ( ret != 0 ) 594 { 595 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; 596 goto exit; 597 } 598 if ( p != end ) 599 { 600 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + 601 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; 602 goto exit; 603 } 604 } 605 606 ret = 0; 607 608 dhm->len = mbedtls_mpi_size( &dhm->P ); 609 610 exit: 611 #if defined(MBEDTLS_PEM_PARSE_C) 612 mbedtls_pem_free( &pem ); 613 #endif 614 if( ret != 0 ) 615 mbedtls_dhm_free( dhm ); 616 617 return( ret ); 618 } 619 620 #if defined(MBEDTLS_FS_IO) 621 /* 622 * Load all data from a file into a given buffer. 623 * 624 * The file is expected to contain either PEM or DER encoded data. 625 * A terminating null byte is always appended. It is included in the announced 626 * length only if the data looks like it is PEM encoded. 627 */ 628 static int load_file( const char *path, unsigned char **buf, size_t *n ) 629 { 630 FILE *f; 631 long size; 632 633 if( ( f = fopen( path, "rb" ) ) == NULL ) 634 return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); 635 636 fseek( f, 0, SEEK_END ); 637 if( ( size = ftell( f ) ) == -1 ) 638 { 639 fclose( f ); 640 return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); 641 } 642 fseek( f, 0, SEEK_SET ); 643 644 *n = (size_t) size; 645 646 if( *n + 1 == 0 || 647 ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) 648 { 649 fclose( f ); 650 return( MBEDTLS_ERR_DHM_ALLOC_FAILED ); 651 } 652 653 if( fread( *buf, 1, *n, f ) != *n ) 654 { 655 fclose( f ); 656 657 mbedtls_platform_zeroize( *buf, *n + 1 ); 658 mbedtls_free( *buf ); 659 660 return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); 661 } 662 663 fclose( f ); 664 665 (*buf)[*n] = '\0'; 666 667 if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) 668 ++*n; 669 670 return( 0 ); 671 } 672 673 /* 674 * Load and parse DHM parameters 675 */ 676 int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ) 677 { 678 int ret; 679 size_t n; 680 unsigned char *buf; 681 DHM_VALIDATE_RET( dhm != NULL ); 682 DHM_VALIDATE_RET( path != NULL ); 683 684 if( ( ret = load_file( path, &buf, &n ) ) != 0 ) 685 return( ret ); 686 687 ret = mbedtls_dhm_parse_dhm( dhm, buf, n ); 688 689 mbedtls_platform_zeroize( buf, n ); 690 mbedtls_free( buf ); 691 692 return( ret ); 693 } 694 #endif /* MBEDTLS_FS_IO */ 695 #endif /* MBEDTLS_ASN1_PARSE_C */ 696 #endif /* MBEDTLS_DHM_ALT */ 697 698 #if defined(MBEDTLS_SELF_TEST) 699 700 #if defined(MBEDTLS_PEM_PARSE_C) 701 static const char mbedtls_test_dhm_params[] = 702 "-----BEGIN DH PARAMETERS-----\r\n" 703 "MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n" 704 "1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n" 705 "9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n" 706 "-----END DH PARAMETERS-----\r\n"; 707 #else /* MBEDTLS_PEM_PARSE_C */ 708 static const char mbedtls_test_dhm_params[] = { 709 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x35, 0xf4, 0x30, 0x44, 710 0x3a, 0x09, 0x90, 0x4f, 0x3a, 0x39, 0xa9, 0x79, 0x79, 0x7d, 0x07, 0x0d, 711 0xf5, 0x33, 0x78, 0xe7, 0x9c, 0x24, 0x38, 0xbe, 0xf4, 0xe7, 0x61, 0xf3, 712 0xc7, 0x14, 0x55, 0x33, 0x28, 0x58, 0x9b, 0x04, 0x1c, 0x80, 0x9b, 0xe1, 713 0xd6, 0xc6, 0xb5, 0xf1, 0xfc, 0x9f, 0x47, 0xd3, 0xa2, 0x54, 0x43, 0x18, 714 0x82, 0x53, 0xa9, 0x92, 0xa5, 0x68, 0x18, 0xb3, 0x7b, 0xa9, 0xde, 0x5a, 715 0x40, 0xd3, 0x62, 0xe5, 0x6e, 0xff, 0x0b, 0xe5, 0x41, 0x74, 0x74, 0xc1, 716 0x25, 0xc1, 0x99, 0x27, 0x2c, 0x8f, 0xe4, 0x1d, 0xea, 0x73, 0x3d, 0xf6, 717 0xf6, 0x62, 0xc9, 0x2a, 0xe7, 0x65, 0x56, 0xe7, 0x55, 0xd1, 0x0c, 0x64, 718 0xe6, 0xa5, 0x09, 0x68, 0xf6, 0x7f, 0xc6, 0xea, 0x73, 0xd0, 0xdc, 0xa8, 719 0x56, 0x9b, 0xe2, 0xba, 0x20, 0x4e, 0x23, 0x58, 0x0d, 0x8b, 0xca, 0x2f, 720 0x49, 0x75, 0xb3, 0x02, 0x01, 0x02 }; 721 #endif /* MBEDTLS_PEM_PARSE_C */ 722 723 static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params ); 724 725 /* 726 * Checkup routine 727 */ 728 int mbedtls_dhm_self_test( int verbose ) 729 { 730 int ret; 731 mbedtls_dhm_context dhm; 732 733 mbedtls_dhm_init( &dhm ); 734 735 if( verbose != 0 ) 736 mbedtls_printf( " DHM parameter load: " ); 737 738 if( ( ret = mbedtls_dhm_parse_dhm( &dhm, 739 (const unsigned char *) mbedtls_test_dhm_params, 740 mbedtls_test_dhm_params_len ) ) != 0 ) 741 { 742 if( verbose != 0 ) 743 mbedtls_printf( "failed\n" ); 744 745 ret = 1; 746 goto exit; 747 } 748 749 if( verbose != 0 ) 750 mbedtls_printf( "passed\n\n" ); 751 752 exit: 753 mbedtls_dhm_free( &dhm ); 754 755 return( ret ); 756 } 757 758 #endif /* MBEDTLS_SELF_TEST */ 759 760 #endif /* MBEDTLS_DHM_C */ 761