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