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