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