RTC auf true

Committer:
kevman
Date:
Wed Nov 28 15:10:15 2018 +0000
Revision:
0:38ceb79fef03
RTC modified

Who changed what in which revision?

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