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