xref: /optee_os/lib/libmbedtls/mbedtls/library/dhm.c (revision 5b25c76ac40f830867e3d60800120ffd7874e8dc)
1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0
2817466cbSJens Wiklander /*
3817466cbSJens Wiklander  *  Diffie-Hellman-Merkle key exchange
4817466cbSJens Wiklander  *
5817466cbSJens Wiklander  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  *
19817466cbSJens Wiklander  *  This file is part of mbed TLS (https://tls.mbed.org)
20817466cbSJens Wiklander  */
21817466cbSJens Wiklander /*
22817466cbSJens Wiklander  *  The following sources were referenced in the design of this implementation
23817466cbSJens Wiklander  *  of the Diffie-Hellman-Merkle algorithm:
24817466cbSJens Wiklander  *
25817466cbSJens Wiklander  *  [1] Handbook of Applied Cryptography - 1997, Chapter 12
26817466cbSJens Wiklander  *      Menezes, van Oorschot and Vanstone
27817466cbSJens Wiklander  *
28817466cbSJens Wiklander  */
29817466cbSJens Wiklander 
30817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
31817466cbSJens Wiklander #include "mbedtls/config.h"
32817466cbSJens Wiklander #else
33817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE
34817466cbSJens Wiklander #endif
35817466cbSJens Wiklander 
36817466cbSJens Wiklander #if defined(MBEDTLS_DHM_C)
37817466cbSJens Wiklander 
38817466cbSJens Wiklander #include "mbedtls/dhm.h"
393d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
40817466cbSJens Wiklander 
41817466cbSJens Wiklander #include <string.h>
42817466cbSJens Wiklander 
43817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
44817466cbSJens Wiklander #include "mbedtls/pem.h"
45817466cbSJens Wiklander #endif
46817466cbSJens Wiklander 
47817466cbSJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C)
48817466cbSJens Wiklander #include "mbedtls/asn1.h"
49817466cbSJens Wiklander #endif
50817466cbSJens Wiklander 
51817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
52817466cbSJens Wiklander #include "mbedtls/platform.h"
53817466cbSJens Wiklander #else
54817466cbSJens Wiklander #include <stdlib.h>
55817466cbSJens Wiklander #include <stdio.h>
56817466cbSJens Wiklander #define mbedtls_printf     printf
57817466cbSJens Wiklander #define mbedtls_calloc    calloc
58817466cbSJens Wiklander #define mbedtls_free       free
59817466cbSJens Wiklander #endif
60817466cbSJens Wiklander 
613d3b0591SJens Wiklander #if !defined(MBEDTLS_DHM_ALT)
623d3b0591SJens Wiklander 
633d3b0591SJens Wiklander #define DHM_VALIDATE_RET( cond )    \
643d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA )
653d3b0591SJens Wiklander #define DHM_VALIDATE( cond )        \
663d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE( cond )
67817466cbSJens Wiklander 
68817466cbSJens Wiklander /*
69817466cbSJens Wiklander  * helper to validate the mbedtls_mpi size and import it
70817466cbSJens Wiklander  */
71817466cbSJens Wiklander static int dhm_read_bignum( mbedtls_mpi *X,
72817466cbSJens Wiklander                             unsigned char **p,
73817466cbSJens Wiklander                             const unsigned char *end )
74817466cbSJens Wiklander {
75817466cbSJens Wiklander     int ret, n;
76817466cbSJens Wiklander 
77817466cbSJens Wiklander     if( end - *p < 2 )
78817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
79817466cbSJens Wiklander 
80817466cbSJens Wiklander     n = ( (*p)[0] << 8 ) | (*p)[1];
81817466cbSJens Wiklander     (*p) += 2;
82817466cbSJens Wiklander 
83817466cbSJens Wiklander     if( (int)( end - *p ) < n )
84817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
85817466cbSJens Wiklander 
86817466cbSJens Wiklander     if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 )
87817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret );
88817466cbSJens Wiklander 
89817466cbSJens Wiklander     (*p) += n;
90817466cbSJens Wiklander 
91817466cbSJens Wiklander     return( 0 );
92817466cbSJens Wiklander }
93817466cbSJens Wiklander 
94817466cbSJens Wiklander /*
95817466cbSJens Wiklander  * Verify sanity of parameter with regards to P
96817466cbSJens Wiklander  *
97817466cbSJens Wiklander  * Parameter should be: 2 <= public_param <= P - 2
98817466cbSJens Wiklander  *
993d3b0591SJens Wiklander  * This means that we need to return an error if
1003d3b0591SJens Wiklander  *              public_param < 2 or public_param > P-2
1013d3b0591SJens Wiklander  *
102817466cbSJens Wiklander  * For more information on the attack, see:
103817466cbSJens Wiklander  *  http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
104817466cbSJens Wiklander  *  http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
105817466cbSJens Wiklander  */
106817466cbSJens Wiklander static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P )
107817466cbSJens Wiklander {
108817466cbSJens Wiklander     mbedtls_mpi L, U;
1093d3b0591SJens Wiklander     int ret = 0;
110817466cbSJens Wiklander 
111817466cbSJens Wiklander     mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U );
112817466cbSJens Wiklander 
113817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) );
114817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) );
115817466cbSJens Wiklander 
1163d3b0591SJens Wiklander     if( mbedtls_mpi_cmp_mpi( param, &L ) < 0 ||
1173d3b0591SJens Wiklander         mbedtls_mpi_cmp_mpi( param, &U ) > 0 )
118817466cbSJens Wiklander     {
1193d3b0591SJens Wiklander         ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
120817466cbSJens Wiklander     }
121817466cbSJens Wiklander 
122817466cbSJens Wiklander cleanup:
123817466cbSJens Wiklander     mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U );
124817466cbSJens Wiklander     return( ret );
125817466cbSJens Wiklander }
126817466cbSJens Wiklander 
127817466cbSJens Wiklander void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
128817466cbSJens Wiklander {
1293d3b0591SJens Wiklander     DHM_VALIDATE( ctx != NULL );
130817466cbSJens Wiklander     memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
131817466cbSJens Wiklander }
132817466cbSJens Wiklander 
133817466cbSJens Wiklander /*
134817466cbSJens Wiklander  * Parse the ServerKeyExchange parameters
135817466cbSJens Wiklander  */
136817466cbSJens Wiklander int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
137817466cbSJens Wiklander                      unsigned char **p,
138817466cbSJens Wiklander                      const unsigned char *end )
139817466cbSJens Wiklander {
140817466cbSJens Wiklander     int ret;
1413d3b0591SJens Wiklander     DHM_VALIDATE_RET( ctx != NULL );
1423d3b0591SJens Wiklander     DHM_VALIDATE_RET( p != NULL && *p != NULL );
1433d3b0591SJens Wiklander     DHM_VALIDATE_RET( end != NULL );
144817466cbSJens Wiklander 
145817466cbSJens Wiklander     if( ( ret = dhm_read_bignum( &ctx->P,  p, end ) ) != 0 ||
146817466cbSJens Wiklander         ( ret = dhm_read_bignum( &ctx->G,  p, end ) ) != 0 ||
147817466cbSJens Wiklander         ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
148817466cbSJens Wiklander         return( ret );
149817466cbSJens Wiklander 
150817466cbSJens Wiklander     if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
151817466cbSJens Wiklander         return( ret );
152817466cbSJens Wiklander 
153817466cbSJens Wiklander     ctx->len = mbedtls_mpi_size( &ctx->P );
154817466cbSJens Wiklander 
155817466cbSJens Wiklander     return( 0 );
156817466cbSJens Wiklander }
157817466cbSJens Wiklander 
158817466cbSJens Wiklander /*
159817466cbSJens Wiklander  * Setup and write the ServerKeyExchange parameters
160817466cbSJens Wiklander  */
161817466cbSJens Wiklander int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size,
162817466cbSJens Wiklander                      unsigned char *output, size_t *olen,
163817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
164817466cbSJens Wiklander                      void *p_rng )
165817466cbSJens Wiklander {
166817466cbSJens Wiklander     int ret, count = 0;
167817466cbSJens Wiklander     size_t n1, n2, n3;
168817466cbSJens Wiklander     unsigned char *p;
1693d3b0591SJens Wiklander     DHM_VALIDATE_RET( ctx != NULL );
1703d3b0591SJens Wiklander     DHM_VALIDATE_RET( output != NULL );
1713d3b0591SJens Wiklander     DHM_VALIDATE_RET( olen != NULL );
1723d3b0591SJens Wiklander     DHM_VALIDATE_RET( f_rng != NULL );
173817466cbSJens Wiklander 
174817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
175817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
176817466cbSJens Wiklander 
177817466cbSJens Wiklander     /*
178817466cbSJens Wiklander      * Generate X as large as possible ( < P )
179817466cbSJens Wiklander      */
180817466cbSJens Wiklander     do
181817466cbSJens Wiklander     {
182817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
183817466cbSJens Wiklander 
184817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
185817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
186817466cbSJens Wiklander 
187817466cbSJens Wiklander         if( count++ > 10 )
188817466cbSJens Wiklander             return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED );
189817466cbSJens Wiklander     }
190817466cbSJens Wiklander     while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
191817466cbSJens Wiklander 
192817466cbSJens Wiklander     /*
193817466cbSJens Wiklander      * Calculate GX = G^X mod P
194817466cbSJens Wiklander      */
195817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
196817466cbSJens Wiklander                           &ctx->P , &ctx->RP ) );
197817466cbSJens Wiklander 
198817466cbSJens Wiklander     if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
199817466cbSJens Wiklander         return( ret );
200817466cbSJens Wiklander 
201817466cbSJens Wiklander     /*
202817466cbSJens Wiklander      * export P, G, GX
203817466cbSJens Wiklander      */
204817466cbSJens Wiklander #define DHM_MPI_EXPORT( X, n )                                          \
2053d3b0591SJens Wiklander     do {                                                                \
2063d3b0591SJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( ( X ),               \
2073d3b0591SJens Wiklander                                                    p + 2,               \
2083d3b0591SJens Wiklander                                                    ( n ) ) );           \
2093d3b0591SJens Wiklander         *p++ = (unsigned char)( ( n ) >> 8 );                           \
2103d3b0591SJens Wiklander         *p++ = (unsigned char)( ( n )      );                           \
2113d3b0591SJens Wiklander         p += ( n );                                                     \
2123d3b0591SJens Wiklander     } while( 0 )
213817466cbSJens Wiklander 
214817466cbSJens Wiklander     n1 = mbedtls_mpi_size( &ctx->P  );
215817466cbSJens Wiklander     n2 = mbedtls_mpi_size( &ctx->G  );
216817466cbSJens Wiklander     n3 = mbedtls_mpi_size( &ctx->GX );
217817466cbSJens Wiklander 
218817466cbSJens Wiklander     p = output;
219817466cbSJens Wiklander     DHM_MPI_EXPORT( &ctx->P , n1 );
220817466cbSJens Wiklander     DHM_MPI_EXPORT( &ctx->G , n2 );
221817466cbSJens Wiklander     DHM_MPI_EXPORT( &ctx->GX, n3 );
222817466cbSJens Wiklander 
223817466cbSJens Wiklander     *olen = p - output;
224817466cbSJens Wiklander 
225817466cbSJens Wiklander     ctx->len = n1;
226817466cbSJens Wiklander 
227817466cbSJens Wiklander cleanup:
228817466cbSJens Wiklander 
229817466cbSJens Wiklander     if( ret != 0 )
230817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret );
231817466cbSJens Wiklander 
232817466cbSJens Wiklander     return( 0 );
233817466cbSJens Wiklander }
234817466cbSJens Wiklander 
235817466cbSJens Wiklander /*
2363d3b0591SJens Wiklander  * Set prime modulus and generator
2373d3b0591SJens Wiklander  */
2383d3b0591SJens Wiklander int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx,
2393d3b0591SJens Wiklander                            const mbedtls_mpi *P,
2403d3b0591SJens Wiklander                            const mbedtls_mpi *G )
2413d3b0591SJens Wiklander {
2423d3b0591SJens Wiklander     int ret;
2433d3b0591SJens Wiklander     DHM_VALIDATE_RET( ctx != NULL );
2443d3b0591SJens Wiklander     DHM_VALIDATE_RET( P != NULL );
2453d3b0591SJens Wiklander     DHM_VALIDATE_RET( G != NULL );
2463d3b0591SJens Wiklander 
2473d3b0591SJens Wiklander     if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ||
2483d3b0591SJens Wiklander         ( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 )
2493d3b0591SJens Wiklander     {
2503d3b0591SJens Wiklander         return( MBEDTLS_ERR_DHM_SET_GROUP_FAILED + ret );
2513d3b0591SJens Wiklander     }
2523d3b0591SJens Wiklander 
2533d3b0591SJens Wiklander     ctx->len = mbedtls_mpi_size( &ctx->P );
2543d3b0591SJens Wiklander     return( 0 );
2553d3b0591SJens Wiklander }
2563d3b0591SJens Wiklander 
2573d3b0591SJens Wiklander /*
258817466cbSJens Wiklander  * Import the peer's public value G^Y
259817466cbSJens Wiklander  */
260817466cbSJens Wiklander int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,
261817466cbSJens Wiklander                      const unsigned char *input, size_t ilen )
262817466cbSJens Wiklander {
263817466cbSJens Wiklander     int ret;
2643d3b0591SJens Wiklander     DHM_VALIDATE_RET( ctx != NULL );
2653d3b0591SJens Wiklander     DHM_VALIDATE_RET( input != NULL );
266817466cbSJens Wiklander 
2673d3b0591SJens Wiklander     if( ilen < 1 || ilen > ctx->len )
268817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
269817466cbSJens Wiklander 
270817466cbSJens Wiklander     if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
271817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret );
272817466cbSJens Wiklander 
273817466cbSJens Wiklander     return( 0 );
274817466cbSJens Wiklander }
275817466cbSJens Wiklander 
276817466cbSJens Wiklander /*
277817466cbSJens Wiklander  * Create own private value X and export G^X
278817466cbSJens Wiklander  */
279817466cbSJens Wiklander int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size,
280817466cbSJens Wiklander                      unsigned char *output, size_t olen,
281817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
282817466cbSJens Wiklander                      void *p_rng )
283817466cbSJens Wiklander {
284817466cbSJens Wiklander     int ret, count = 0;
2853d3b0591SJens Wiklander     DHM_VALIDATE_RET( ctx != NULL );
2863d3b0591SJens Wiklander     DHM_VALIDATE_RET( output != NULL );
2873d3b0591SJens Wiklander     DHM_VALIDATE_RET( f_rng != NULL );
288817466cbSJens Wiklander 
2893d3b0591SJens Wiklander     if( olen < 1 || olen > ctx->len )
290817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
291817466cbSJens Wiklander 
292817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
293817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
294817466cbSJens Wiklander 
295817466cbSJens Wiklander     /*
296817466cbSJens Wiklander      * generate X and calculate GX = G^X mod P
297817466cbSJens Wiklander      */
298817466cbSJens Wiklander     do
299817466cbSJens Wiklander     {
300817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
301817466cbSJens Wiklander 
302817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
303817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
304817466cbSJens Wiklander 
305817466cbSJens Wiklander         if( count++ > 10 )
306817466cbSJens Wiklander             return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED );
307817466cbSJens Wiklander     }
308817466cbSJens Wiklander     while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
309817466cbSJens Wiklander 
310817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
311817466cbSJens Wiklander                           &ctx->P , &ctx->RP ) );
312817466cbSJens Wiklander 
313817466cbSJens Wiklander     if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
314817466cbSJens Wiklander         return( ret );
315817466cbSJens Wiklander 
316817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) );
317817466cbSJens Wiklander 
318817466cbSJens Wiklander cleanup:
319817466cbSJens Wiklander 
320817466cbSJens Wiklander     if( ret != 0 )
321817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret );
322817466cbSJens Wiklander 
323817466cbSJens Wiklander     return( 0 );
324817466cbSJens Wiklander }
325817466cbSJens Wiklander 
326817466cbSJens Wiklander /*
327817466cbSJens Wiklander  * Use the blinding method and optimisation suggested in section 10 of:
328817466cbSJens Wiklander  *  KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
329817466cbSJens Wiklander  *  DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
330817466cbSJens Wiklander  *  Berlin Heidelberg, 1996. p. 104-113.
331817466cbSJens Wiklander  */
332817466cbSJens Wiklander static int dhm_update_blinding( mbedtls_dhm_context *ctx,
333817466cbSJens Wiklander                     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
334817466cbSJens Wiklander {
335817466cbSJens Wiklander     int ret, count;
336817466cbSJens Wiklander 
337817466cbSJens Wiklander     /*
338817466cbSJens Wiklander      * Don't use any blinding the first time a particular X is used,
339817466cbSJens Wiklander      * but remember it to use blinding next time.
340817466cbSJens Wiklander      */
341817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 )
342817466cbSJens Wiklander     {
343817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) );
344817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) );
345817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) );
346817466cbSJens Wiklander 
347817466cbSJens Wiklander         return( 0 );
348817466cbSJens Wiklander     }
349817466cbSJens Wiklander 
350817466cbSJens Wiklander     /*
351817466cbSJens Wiklander      * Ok, we need blinding. Can we re-use existing values?
352817466cbSJens Wiklander      * If yes, just update them by squaring them.
353817466cbSJens Wiklander      */
354817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 )
355817466cbSJens Wiklander     {
356817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
357817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) );
358817466cbSJens Wiklander 
359817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
360817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
361817466cbSJens Wiklander 
362817466cbSJens Wiklander         return( 0 );
363817466cbSJens Wiklander     }
364817466cbSJens Wiklander 
365817466cbSJens Wiklander     /*
366817466cbSJens Wiklander      * We need to generate blinding values from scratch
367817466cbSJens Wiklander      */
368817466cbSJens Wiklander 
369817466cbSJens Wiklander     /* Vi = random( 2, P-1 ) */
370817466cbSJens Wiklander     count = 0;
371817466cbSJens Wiklander     do
372817466cbSJens Wiklander     {
373817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ) );
374817466cbSJens Wiklander 
375817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 )
376817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) );
377817466cbSJens Wiklander 
378817466cbSJens Wiklander         if( count++ > 10 )
379817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
380817466cbSJens Wiklander     }
381817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 );
382817466cbSJens Wiklander 
383817466cbSJens Wiklander     /* Vf = Vi^-X mod P */
384817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) );
385817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) );
386817466cbSJens Wiklander 
387817466cbSJens Wiklander cleanup:
388817466cbSJens Wiklander     return( ret );
389817466cbSJens Wiklander }
390817466cbSJens Wiklander 
391817466cbSJens Wiklander /*
392817466cbSJens Wiklander  * Derive and export the shared secret (G^Y)^X mod P
393817466cbSJens Wiklander  */
394817466cbSJens Wiklander int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx,
395817466cbSJens Wiklander                      unsigned char *output, size_t output_size, size_t *olen,
396817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
397817466cbSJens Wiklander                      void *p_rng )
398817466cbSJens Wiklander {
399817466cbSJens Wiklander     int ret;
400817466cbSJens Wiklander     mbedtls_mpi GYb;
4013d3b0591SJens Wiklander     DHM_VALIDATE_RET( ctx != NULL );
4023d3b0591SJens Wiklander     DHM_VALIDATE_RET( output != NULL );
4033d3b0591SJens Wiklander     DHM_VALIDATE_RET( olen != NULL );
404817466cbSJens Wiklander 
4053d3b0591SJens Wiklander     if( output_size < ctx->len )
406817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
407817466cbSJens Wiklander 
408817466cbSJens Wiklander     if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
409817466cbSJens Wiklander         return( ret );
410817466cbSJens Wiklander 
411817466cbSJens Wiklander     mbedtls_mpi_init( &GYb );
412817466cbSJens Wiklander 
413817466cbSJens Wiklander     /* Blind peer's value */
414817466cbSJens Wiklander     if( f_rng != NULL )
415817466cbSJens Wiklander     {
416817466cbSJens Wiklander         MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) );
417817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) );
418817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) );
419817466cbSJens Wiklander     }
420817466cbSJens Wiklander     else
421817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) );
422817466cbSJens Wiklander 
423817466cbSJens Wiklander     /* Do modular exponentiation */
424817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X,
425817466cbSJens Wiklander                           &ctx->P, &ctx->RP ) );
426817466cbSJens Wiklander 
427817466cbSJens Wiklander     /* Unblind secret value */
428817466cbSJens Wiklander     if( f_rng != NULL )
429817466cbSJens Wiklander     {
430817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) );
431817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) );
432817466cbSJens Wiklander     }
433817466cbSJens Wiklander 
434817466cbSJens Wiklander     *olen = mbedtls_mpi_size( &ctx->K );
435817466cbSJens Wiklander 
436817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) );
437817466cbSJens Wiklander 
438817466cbSJens Wiklander cleanup:
439817466cbSJens Wiklander     mbedtls_mpi_free( &GYb );
440817466cbSJens Wiklander 
441817466cbSJens Wiklander     if( ret != 0 )
442817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret );
443817466cbSJens Wiklander 
444817466cbSJens Wiklander     return( 0 );
445817466cbSJens Wiklander }
446817466cbSJens Wiklander 
447817466cbSJens Wiklander /*
448817466cbSJens Wiklander  * Free the components of a DHM key
449817466cbSJens Wiklander  */
450817466cbSJens Wiklander void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
451817466cbSJens Wiklander {
4523d3b0591SJens Wiklander     if( ctx == NULL )
4533d3b0591SJens Wiklander         return;
4543d3b0591SJens Wiklander 
4553d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->pX );
4563d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->Vf );
4573d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->Vi );
4583d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->RP );
4593d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->K  );
4603d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->GY );
4613d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->GX );
4623d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->X  );
4633d3b0591SJens Wiklander     mbedtls_mpi_free( &ctx->G  );
464817466cbSJens Wiklander     mbedtls_mpi_free( &ctx->P  );
465817466cbSJens Wiklander 
4663d3b0591SJens Wiklander     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_dhm_context ) );
467817466cbSJens Wiklander }
468817466cbSJens Wiklander 
469817466cbSJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C)
470817466cbSJens Wiklander /*
471817466cbSJens Wiklander  * Parse DHM parameters
472817466cbSJens Wiklander  */
473817466cbSJens Wiklander int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
474817466cbSJens Wiklander                    size_t dhminlen )
475817466cbSJens Wiklander {
476817466cbSJens Wiklander     int ret;
477817466cbSJens Wiklander     size_t len;
478817466cbSJens Wiklander     unsigned char *p, *end;
479817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
480817466cbSJens Wiklander     mbedtls_pem_context pem;
4813d3b0591SJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */
482817466cbSJens Wiklander 
4833d3b0591SJens Wiklander     DHM_VALIDATE_RET( dhm != NULL );
4843d3b0591SJens Wiklander     DHM_VALIDATE_RET( dhmin != NULL );
4853d3b0591SJens Wiklander 
4863d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
487817466cbSJens Wiklander     mbedtls_pem_init( &pem );
488817466cbSJens Wiklander 
489817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
490817466cbSJens Wiklander     if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' )
491817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
492817466cbSJens Wiklander     else
493817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer( &pem,
494817466cbSJens Wiklander                                "-----BEGIN DH PARAMETERS-----",
495817466cbSJens Wiklander                                "-----END DH PARAMETERS-----",
496817466cbSJens Wiklander                                dhmin, NULL, 0, &dhminlen );
497817466cbSJens Wiklander 
498817466cbSJens Wiklander     if( ret == 0 )
499817466cbSJens Wiklander     {
500817466cbSJens Wiklander         /*
501817466cbSJens Wiklander          * Was PEM encoded
502817466cbSJens Wiklander          */
503817466cbSJens Wiklander         dhminlen = pem.buflen;
504817466cbSJens Wiklander     }
505817466cbSJens Wiklander     else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
506817466cbSJens Wiklander         goto exit;
507817466cbSJens Wiklander 
508817466cbSJens Wiklander     p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin;
509817466cbSJens Wiklander #else
510817466cbSJens Wiklander     p = (unsigned char *) dhmin;
511817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */
512817466cbSJens Wiklander     end = p + dhminlen;
513817466cbSJens Wiklander 
514817466cbSJens Wiklander     /*
515817466cbSJens Wiklander      *  DHParams ::= SEQUENCE {
516817466cbSJens Wiklander      *      prime              INTEGER,  -- P
517817466cbSJens Wiklander      *      generator          INTEGER,  -- g
518817466cbSJens Wiklander      *      privateValueLength INTEGER OPTIONAL
519817466cbSJens Wiklander      *  }
520817466cbSJens Wiklander      */
521817466cbSJens Wiklander     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
522817466cbSJens Wiklander             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
523817466cbSJens Wiklander     {
524817466cbSJens Wiklander         ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
525817466cbSJens Wiklander         goto exit;
526817466cbSJens Wiklander     }
527817466cbSJens Wiklander 
528817466cbSJens Wiklander     end = p + len;
529817466cbSJens Wiklander 
530817466cbSJens Wiklander     if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P  ) ) != 0 ||
531817466cbSJens Wiklander         ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 )
532817466cbSJens Wiklander     {
533817466cbSJens Wiklander         ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
534817466cbSJens Wiklander         goto exit;
535817466cbSJens Wiklander     }
536817466cbSJens Wiklander 
537817466cbSJens Wiklander     if( p != end )
538817466cbSJens Wiklander     {
539817466cbSJens Wiklander         /* This might be the optional privateValueLength.
540817466cbSJens Wiklander          * If so, we can cleanly discard it */
541817466cbSJens Wiklander         mbedtls_mpi rec;
542817466cbSJens Wiklander         mbedtls_mpi_init( &rec );
543817466cbSJens Wiklander         ret = mbedtls_asn1_get_mpi( &p, end, &rec );
544817466cbSJens Wiklander         mbedtls_mpi_free( &rec );
545817466cbSJens Wiklander         if ( ret != 0 )
546817466cbSJens Wiklander         {
547817466cbSJens Wiklander             ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
548817466cbSJens Wiklander             goto exit;
549817466cbSJens Wiklander         }
550817466cbSJens Wiklander         if ( p != end )
551817466cbSJens Wiklander         {
552817466cbSJens Wiklander             ret = MBEDTLS_ERR_DHM_INVALID_FORMAT +
553817466cbSJens Wiklander                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
554817466cbSJens Wiklander             goto exit;
555817466cbSJens Wiklander         }
556817466cbSJens Wiklander     }
557817466cbSJens Wiklander 
558817466cbSJens Wiklander     ret = 0;
559817466cbSJens Wiklander 
560817466cbSJens Wiklander     dhm->len = mbedtls_mpi_size( &dhm->P );
561817466cbSJens Wiklander 
562817466cbSJens Wiklander exit:
563817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
564817466cbSJens Wiklander     mbedtls_pem_free( &pem );
565817466cbSJens Wiklander #endif
566817466cbSJens Wiklander     if( ret != 0 )
567817466cbSJens Wiklander         mbedtls_dhm_free( dhm );
568817466cbSJens Wiklander 
569817466cbSJens Wiklander     return( ret );
570817466cbSJens Wiklander }
571817466cbSJens Wiklander 
572817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
573817466cbSJens Wiklander /*
574817466cbSJens Wiklander  * Load all data from a file into a given buffer.
575817466cbSJens Wiklander  *
576817466cbSJens Wiklander  * The file is expected to contain either PEM or DER encoded data.
577817466cbSJens Wiklander  * A terminating null byte is always appended. It is included in the announced
578817466cbSJens Wiklander  * length only if the data looks like it is PEM encoded.
579817466cbSJens Wiklander  */
580817466cbSJens Wiklander static int load_file( const char *path, unsigned char **buf, size_t *n )
581817466cbSJens Wiklander {
582817466cbSJens Wiklander     FILE *f;
583817466cbSJens Wiklander     long size;
584817466cbSJens Wiklander 
585817466cbSJens Wiklander     if( ( f = fopen( path, "rb" ) ) == NULL )
586817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
587817466cbSJens Wiklander 
588817466cbSJens Wiklander     fseek( f, 0, SEEK_END );
589817466cbSJens Wiklander     if( ( size = ftell( f ) ) == -1 )
590817466cbSJens Wiklander     {
591817466cbSJens Wiklander         fclose( f );
592817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
593817466cbSJens Wiklander     }
594817466cbSJens Wiklander     fseek( f, 0, SEEK_SET );
595817466cbSJens Wiklander 
596817466cbSJens Wiklander     *n = (size_t) size;
597817466cbSJens Wiklander 
598817466cbSJens Wiklander     if( *n + 1 == 0 ||
599817466cbSJens Wiklander         ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
600817466cbSJens Wiklander     {
601817466cbSJens Wiklander         fclose( f );
602817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_ALLOC_FAILED );
603817466cbSJens Wiklander     }
604817466cbSJens Wiklander 
605817466cbSJens Wiklander     if( fread( *buf, 1, *n, f ) != *n )
606817466cbSJens Wiklander     {
607817466cbSJens Wiklander         fclose( f );
6083d3b0591SJens Wiklander 
6093d3b0591SJens Wiklander         mbedtls_platform_zeroize( *buf, *n + 1 );
610817466cbSJens Wiklander         mbedtls_free( *buf );
6113d3b0591SJens Wiklander 
612817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
613817466cbSJens Wiklander     }
614817466cbSJens Wiklander 
615817466cbSJens Wiklander     fclose( f );
616817466cbSJens Wiklander 
617817466cbSJens Wiklander     (*buf)[*n] = '\0';
618817466cbSJens Wiklander 
619817466cbSJens Wiklander     if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
620817466cbSJens Wiklander         ++*n;
621817466cbSJens Wiklander 
622817466cbSJens Wiklander     return( 0 );
623817466cbSJens Wiklander }
624817466cbSJens Wiklander 
625817466cbSJens Wiklander /*
626817466cbSJens Wiklander  * Load and parse DHM parameters
627817466cbSJens Wiklander  */
628817466cbSJens Wiklander int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
629817466cbSJens Wiklander {
630817466cbSJens Wiklander     int ret;
631817466cbSJens Wiklander     size_t n;
632817466cbSJens Wiklander     unsigned char *buf;
6333d3b0591SJens Wiklander     DHM_VALIDATE_RET( dhm != NULL );
6343d3b0591SJens Wiklander     DHM_VALIDATE_RET( path != NULL );
635817466cbSJens Wiklander 
636817466cbSJens Wiklander     if( ( ret = load_file( path, &buf, &n ) ) != 0 )
637817466cbSJens Wiklander         return( ret );
638817466cbSJens Wiklander 
639817466cbSJens Wiklander     ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
640817466cbSJens Wiklander 
6413d3b0591SJens Wiklander     mbedtls_platform_zeroize( buf, n );
642817466cbSJens Wiklander     mbedtls_free( buf );
643817466cbSJens Wiklander 
644817466cbSJens Wiklander     return( ret );
645817466cbSJens Wiklander }
646817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
647817466cbSJens Wiklander #endif /* MBEDTLS_ASN1_PARSE_C */
6483d3b0591SJens Wiklander #endif /* MBEDTLS_DHM_ALT */
649817466cbSJens Wiklander 
650817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
651817466cbSJens Wiklander 
652*5b25c76aSJerome Forissier #if defined(MBEDTLS_PEM_PARSE_C)
653817466cbSJens Wiklander static const char mbedtls_test_dhm_params[] =
654817466cbSJens Wiklander "-----BEGIN DH PARAMETERS-----\r\n"
655817466cbSJens Wiklander "MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n"
656817466cbSJens Wiklander "1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n"
657817466cbSJens Wiklander "9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n"
658817466cbSJens Wiklander "-----END DH PARAMETERS-----\r\n";
659*5b25c76aSJerome Forissier #else /* MBEDTLS_PEM_PARSE_C */
660*5b25c76aSJerome Forissier static const char mbedtls_test_dhm_params[] = {
661*5b25c76aSJerome Forissier   0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x35, 0xf4, 0x30, 0x44,
662*5b25c76aSJerome Forissier   0x3a, 0x09, 0x90, 0x4f, 0x3a, 0x39, 0xa9, 0x79, 0x79, 0x7d, 0x07, 0x0d,
663*5b25c76aSJerome Forissier   0xf5, 0x33, 0x78, 0xe7, 0x9c, 0x24, 0x38, 0xbe, 0xf4, 0xe7, 0x61, 0xf3,
664*5b25c76aSJerome Forissier   0xc7, 0x14, 0x55, 0x33, 0x28, 0x58, 0x9b, 0x04, 0x1c, 0x80, 0x9b, 0xe1,
665*5b25c76aSJerome Forissier   0xd6, 0xc6, 0xb5, 0xf1, 0xfc, 0x9f, 0x47, 0xd3, 0xa2, 0x54, 0x43, 0x18,
666*5b25c76aSJerome Forissier   0x82, 0x53, 0xa9, 0x92, 0xa5, 0x68, 0x18, 0xb3, 0x7b, 0xa9, 0xde, 0x5a,
667*5b25c76aSJerome Forissier   0x40, 0xd3, 0x62, 0xe5, 0x6e, 0xff, 0x0b, 0xe5, 0x41, 0x74, 0x74, 0xc1,
668*5b25c76aSJerome Forissier   0x25, 0xc1, 0x99, 0x27, 0x2c, 0x8f, 0xe4, 0x1d, 0xea, 0x73, 0x3d, 0xf6,
669*5b25c76aSJerome Forissier   0xf6, 0x62, 0xc9, 0x2a, 0xe7, 0x65, 0x56, 0xe7, 0x55, 0xd1, 0x0c, 0x64,
670*5b25c76aSJerome Forissier   0xe6, 0xa5, 0x09, 0x68, 0xf6, 0x7f, 0xc6, 0xea, 0x73, 0xd0, 0xdc, 0xa8,
671*5b25c76aSJerome Forissier   0x56, 0x9b, 0xe2, 0xba, 0x20, 0x4e, 0x23, 0x58, 0x0d, 0x8b, 0xca, 0x2f,
672*5b25c76aSJerome Forissier   0x49, 0x75, 0xb3, 0x02, 0x01, 0x02 };
673*5b25c76aSJerome Forissier #endif /* MBEDTLS_PEM_PARSE_C */
674817466cbSJens Wiklander 
675817466cbSJens Wiklander static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params );
676817466cbSJens Wiklander 
677817466cbSJens Wiklander /*
678817466cbSJens Wiklander  * Checkup routine
679817466cbSJens Wiklander  */
680817466cbSJens Wiklander int mbedtls_dhm_self_test( int verbose )
681817466cbSJens Wiklander {
682817466cbSJens Wiklander     int ret;
683817466cbSJens Wiklander     mbedtls_dhm_context dhm;
684817466cbSJens Wiklander 
685817466cbSJens Wiklander     mbedtls_dhm_init( &dhm );
686817466cbSJens Wiklander 
687817466cbSJens Wiklander     if( verbose != 0 )
688817466cbSJens Wiklander         mbedtls_printf( "  DHM parameter load: " );
689817466cbSJens Wiklander 
690817466cbSJens Wiklander     if( ( ret = mbedtls_dhm_parse_dhm( &dhm,
691817466cbSJens Wiklander                     (const unsigned char *) mbedtls_test_dhm_params,
692817466cbSJens Wiklander                     mbedtls_test_dhm_params_len ) ) != 0 )
693817466cbSJens Wiklander     {
694817466cbSJens Wiklander         if( verbose != 0 )
695817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
696817466cbSJens Wiklander 
697817466cbSJens Wiklander         ret = 1;
698817466cbSJens Wiklander         goto exit;
699817466cbSJens Wiklander     }
700817466cbSJens Wiklander 
701817466cbSJens Wiklander     if( verbose != 0 )
702817466cbSJens Wiklander         mbedtls_printf( "passed\n\n" );
703817466cbSJens Wiklander 
704817466cbSJens Wiklander exit:
705817466cbSJens Wiklander     mbedtls_dhm_free( &dhm );
706817466cbSJens Wiklander 
707817466cbSJens Wiklander     return( ret );
708817466cbSJens Wiklander }
709817466cbSJens Wiklander 
710817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
711817466cbSJens Wiklander 
712817466cbSJens Wiklander #endif /* MBEDTLS_DHM_C */
713