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