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" 39*3d3b0591SJens 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 61*3d3b0591SJens Wiklander #if !defined(MBEDTLS_DHM_ALT) 62*3d3b0591SJens Wiklander 63*3d3b0591SJens Wiklander #define DHM_VALIDATE_RET( cond ) \ 64*3d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA ) 65*3d3b0591SJens Wiklander #define DHM_VALIDATE( cond ) \ 66*3d3b0591SJens 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 * 99*3d3b0591SJens Wiklander * This means that we need to return an error if 100*3d3b0591SJens Wiklander * public_param < 2 or public_param > P-2 101*3d3b0591SJens 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; 109*3d3b0591SJens 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 116*3d3b0591SJens Wiklander if( mbedtls_mpi_cmp_mpi( param, &L ) < 0 || 117*3d3b0591SJens Wiklander mbedtls_mpi_cmp_mpi( param, &U ) > 0 ) 118817466cbSJens Wiklander { 119*3d3b0591SJens 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 { 129*3d3b0591SJens 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; 141*3d3b0591SJens Wiklander DHM_VALIDATE_RET( ctx != NULL ); 142*3d3b0591SJens Wiklander DHM_VALIDATE_RET( p != NULL && *p != NULL ); 143*3d3b0591SJens 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; 169*3d3b0591SJens Wiklander DHM_VALIDATE_RET( ctx != NULL ); 170*3d3b0591SJens Wiklander DHM_VALIDATE_RET( output != NULL ); 171*3d3b0591SJens Wiklander DHM_VALIDATE_RET( olen != NULL ); 172*3d3b0591SJens 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 ) \ 205*3d3b0591SJens Wiklander do { \ 206*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( ( X ), \ 207*3d3b0591SJens Wiklander p + 2, \ 208*3d3b0591SJens Wiklander ( n ) ) ); \ 209*3d3b0591SJens Wiklander *p++ = (unsigned char)( ( n ) >> 8 ); \ 210*3d3b0591SJens Wiklander *p++ = (unsigned char)( ( n ) ); \ 211*3d3b0591SJens Wiklander p += ( n ); \ 212*3d3b0591SJens 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 /* 236*3d3b0591SJens Wiklander * Set prime modulus and generator 237*3d3b0591SJens Wiklander */ 238*3d3b0591SJens Wiklander int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx, 239*3d3b0591SJens Wiklander const mbedtls_mpi *P, 240*3d3b0591SJens Wiklander const mbedtls_mpi *G ) 241*3d3b0591SJens Wiklander { 242*3d3b0591SJens Wiklander int ret; 243*3d3b0591SJens Wiklander DHM_VALIDATE_RET( ctx != NULL ); 244*3d3b0591SJens Wiklander DHM_VALIDATE_RET( P != NULL ); 245*3d3b0591SJens Wiklander DHM_VALIDATE_RET( G != NULL ); 246*3d3b0591SJens Wiklander 247*3d3b0591SJens Wiklander if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 || 248*3d3b0591SJens Wiklander ( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 ) 249*3d3b0591SJens Wiklander { 250*3d3b0591SJens Wiklander return( MBEDTLS_ERR_DHM_SET_GROUP_FAILED + ret ); 251*3d3b0591SJens Wiklander } 252*3d3b0591SJens Wiklander 253*3d3b0591SJens Wiklander ctx->len = mbedtls_mpi_size( &ctx->P ); 254*3d3b0591SJens Wiklander return( 0 ); 255*3d3b0591SJens Wiklander } 256*3d3b0591SJens Wiklander 257*3d3b0591SJens 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; 264*3d3b0591SJens Wiklander DHM_VALIDATE_RET( ctx != NULL ); 265*3d3b0591SJens Wiklander DHM_VALIDATE_RET( input != NULL ); 266817466cbSJens Wiklander 267*3d3b0591SJens 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; 285*3d3b0591SJens Wiklander DHM_VALIDATE_RET( ctx != NULL ); 286*3d3b0591SJens Wiklander DHM_VALIDATE_RET( output != NULL ); 287*3d3b0591SJens Wiklander DHM_VALIDATE_RET( f_rng != NULL ); 288817466cbSJens Wiklander 289*3d3b0591SJens 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; 401*3d3b0591SJens Wiklander DHM_VALIDATE_RET( ctx != NULL ); 402*3d3b0591SJens Wiklander DHM_VALIDATE_RET( output != NULL ); 403*3d3b0591SJens Wiklander DHM_VALIDATE_RET( olen != NULL ); 404817466cbSJens Wiklander 405*3d3b0591SJens 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 { 452*3d3b0591SJens Wiklander if( ctx == NULL ) 453*3d3b0591SJens Wiklander return; 454*3d3b0591SJens Wiklander 455*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->pX ); 456*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->Vf ); 457*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->Vi ); 458*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->RP ); 459*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->K ); 460*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->GY ); 461*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->GX ); 462*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->X ); 463*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->G ); 464817466cbSJens Wiklander mbedtls_mpi_free( &ctx->P ); 465817466cbSJens Wiklander 466*3d3b0591SJens 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; 481*3d3b0591SJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 482817466cbSJens Wiklander 483*3d3b0591SJens Wiklander DHM_VALIDATE_RET( dhm != NULL ); 484*3d3b0591SJens Wiklander DHM_VALIDATE_RET( dhmin != NULL ); 485*3d3b0591SJens Wiklander 486*3d3b0591SJens 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 ); 608*3d3b0591SJens Wiklander 609*3d3b0591SJens Wiklander mbedtls_platform_zeroize( *buf, *n + 1 ); 610817466cbSJens Wiklander mbedtls_free( *buf ); 611*3d3b0591SJens 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; 633*3d3b0591SJens Wiklander DHM_VALIDATE_RET( dhm != NULL ); 634*3d3b0591SJens 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 641*3d3b0591SJens 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 */ 648*3d3b0591SJens Wiklander #endif /* MBEDTLS_DHM_ALT */ 649817466cbSJens Wiklander 650817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 651817466cbSJens Wiklander 652817466cbSJens Wiklander static const char mbedtls_test_dhm_params[] = 653817466cbSJens Wiklander "-----BEGIN DH PARAMETERS-----\r\n" 654817466cbSJens Wiklander "MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n" 655817466cbSJens Wiklander "1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n" 656817466cbSJens Wiklander "9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n" 657817466cbSJens Wiklander "-----END DH PARAMETERS-----\r\n"; 658817466cbSJens Wiklander 659817466cbSJens Wiklander static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params ); 660817466cbSJens Wiklander 661817466cbSJens Wiklander /* 662817466cbSJens Wiklander * Checkup routine 663817466cbSJens Wiklander */ 664817466cbSJens Wiklander int mbedtls_dhm_self_test( int verbose ) 665817466cbSJens Wiklander { 666817466cbSJens Wiklander int ret; 667817466cbSJens Wiklander mbedtls_dhm_context dhm; 668817466cbSJens Wiklander 669817466cbSJens Wiklander mbedtls_dhm_init( &dhm ); 670817466cbSJens Wiklander 671817466cbSJens Wiklander if( verbose != 0 ) 672817466cbSJens Wiklander mbedtls_printf( " DHM parameter load: " ); 673817466cbSJens Wiklander 674817466cbSJens Wiklander if( ( ret = mbedtls_dhm_parse_dhm( &dhm, 675817466cbSJens Wiklander (const unsigned char *) mbedtls_test_dhm_params, 676817466cbSJens Wiklander mbedtls_test_dhm_params_len ) ) != 0 ) 677817466cbSJens Wiklander { 678817466cbSJens Wiklander if( verbose != 0 ) 679817466cbSJens Wiklander mbedtls_printf( "failed\n" ); 680817466cbSJens Wiklander 681817466cbSJens Wiklander ret = 1; 682817466cbSJens Wiklander goto exit; 683817466cbSJens Wiklander } 684817466cbSJens Wiklander 685817466cbSJens Wiklander if( verbose != 0 ) 686817466cbSJens Wiklander mbedtls_printf( "passed\n\n" ); 687817466cbSJens Wiklander 688817466cbSJens Wiklander exit: 689817466cbSJens Wiklander mbedtls_dhm_free( &dhm ); 690817466cbSJens Wiklander 691817466cbSJens Wiklander return( ret ); 692817466cbSJens Wiklander } 693817466cbSJens Wiklander 694817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 695817466cbSJens Wiklander 696817466cbSJens Wiklander #endif /* MBEDTLS_DHM_C */ 697