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