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