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