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