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