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