1*c6672fdcSEdison 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" 39817466cbSJens Wiklander 40817466cbSJens Wiklander #include <string.h> 41817466cbSJens Wiklander 42817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 43817466cbSJens Wiklander #include "mbedtls/pem.h" 44817466cbSJens Wiklander #endif 45817466cbSJens Wiklander 46817466cbSJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C) 47817466cbSJens Wiklander #include "mbedtls/asn1.h" 48817466cbSJens Wiklander #endif 49817466cbSJens Wiklander 50817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 51817466cbSJens Wiklander #include "mbedtls/platform.h" 52817466cbSJens Wiklander #else 53817466cbSJens Wiklander #include <stdlib.h> 54817466cbSJens Wiklander #include <stdio.h> 55817466cbSJens Wiklander #define mbedtls_printf printf 56817466cbSJens Wiklander #define mbedtls_calloc calloc 57817466cbSJens Wiklander #define mbedtls_free free 58817466cbSJens Wiklander #endif 59817466cbSJens Wiklander 60817466cbSJens Wiklander /* Implementation that should never be optimized out by the compiler */ 61817466cbSJens Wiklander static void mbedtls_zeroize( void *v, size_t n ) { 62817466cbSJens Wiklander volatile unsigned char *p = v; while( n-- ) *p++ = 0; 63817466cbSJens Wiklander } 64817466cbSJens Wiklander 65817466cbSJens Wiklander /* 66817466cbSJens Wiklander * helper to validate the mbedtls_mpi size and import it 67817466cbSJens Wiklander */ 68817466cbSJens Wiklander static int dhm_read_bignum( mbedtls_mpi *X, 69817466cbSJens Wiklander unsigned char **p, 70817466cbSJens Wiklander const unsigned char *end ) 71817466cbSJens Wiklander { 72817466cbSJens Wiklander int ret, n; 73817466cbSJens Wiklander 74817466cbSJens Wiklander if( end - *p < 2 ) 75817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 76817466cbSJens Wiklander 77817466cbSJens Wiklander n = ( (*p)[0] << 8 ) | (*p)[1]; 78817466cbSJens Wiklander (*p) += 2; 79817466cbSJens Wiklander 80817466cbSJens Wiklander if( (int)( end - *p ) < n ) 81817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 82817466cbSJens Wiklander 83817466cbSJens Wiklander if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 ) 84817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret ); 85817466cbSJens Wiklander 86817466cbSJens Wiklander (*p) += n; 87817466cbSJens Wiklander 88817466cbSJens Wiklander return( 0 ); 89817466cbSJens Wiklander } 90817466cbSJens Wiklander 91817466cbSJens Wiklander /* 92817466cbSJens Wiklander * Verify sanity of parameter with regards to P 93817466cbSJens Wiklander * 94817466cbSJens Wiklander * Parameter should be: 2 <= public_param <= P - 2 95817466cbSJens Wiklander * 96817466cbSJens Wiklander * For more information on the attack, see: 97817466cbSJens Wiklander * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf 98817466cbSJens Wiklander * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643 99817466cbSJens Wiklander */ 100817466cbSJens Wiklander static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P ) 101817466cbSJens Wiklander { 102817466cbSJens Wiklander mbedtls_mpi L, U; 103817466cbSJens Wiklander int ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA; 104817466cbSJens Wiklander 105817466cbSJens Wiklander mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U ); 106817466cbSJens Wiklander 107817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) ); 108817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) ); 109817466cbSJens Wiklander 110817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( param, &L ) >= 0 && 111817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( param, &U ) <= 0 ) 112817466cbSJens Wiklander { 113817466cbSJens Wiklander ret = 0; 114817466cbSJens Wiklander } 115817466cbSJens Wiklander 116817466cbSJens Wiklander cleanup: 117817466cbSJens Wiklander mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U ); 118817466cbSJens Wiklander return( ret ); 119817466cbSJens Wiklander } 120817466cbSJens Wiklander 121817466cbSJens Wiklander void mbedtls_dhm_init( mbedtls_dhm_context *ctx ) 122817466cbSJens Wiklander { 123817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_dhm_context ) ); 124817466cbSJens Wiklander } 125817466cbSJens Wiklander 126817466cbSJens Wiklander /* 127817466cbSJens Wiklander * Parse the ServerKeyExchange parameters 128817466cbSJens Wiklander */ 129817466cbSJens Wiklander int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, 130817466cbSJens Wiklander unsigned char **p, 131817466cbSJens Wiklander const unsigned char *end ) 132817466cbSJens Wiklander { 133817466cbSJens Wiklander int ret; 134817466cbSJens Wiklander 135817466cbSJens Wiklander if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 || 136817466cbSJens Wiklander ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 || 137817466cbSJens Wiklander ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 ) 138817466cbSJens Wiklander return( ret ); 139817466cbSJens Wiklander 140817466cbSJens Wiklander if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) 141817466cbSJens Wiklander return( ret ); 142817466cbSJens Wiklander 143817466cbSJens Wiklander ctx->len = mbedtls_mpi_size( &ctx->P ); 144817466cbSJens Wiklander 145817466cbSJens Wiklander return( 0 ); 146817466cbSJens Wiklander } 147817466cbSJens Wiklander 148817466cbSJens Wiklander /* 149817466cbSJens Wiklander * Setup and write the ServerKeyExchange parameters 150817466cbSJens Wiklander */ 151817466cbSJens Wiklander int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, 152817466cbSJens Wiklander unsigned char *output, size_t *olen, 153817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 154817466cbSJens Wiklander void *p_rng ) 155817466cbSJens Wiklander { 156817466cbSJens Wiklander int ret, count = 0; 157817466cbSJens Wiklander size_t n1, n2, n3; 158817466cbSJens Wiklander unsigned char *p; 159817466cbSJens Wiklander 160817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) 161817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 162817466cbSJens Wiklander 163817466cbSJens Wiklander /* 164817466cbSJens Wiklander * Generate X as large as possible ( < P ) 165817466cbSJens Wiklander */ 166817466cbSJens Wiklander do 167817466cbSJens Wiklander { 168817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) ); 169817466cbSJens Wiklander 170817466cbSJens Wiklander while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) 171817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) ); 172817466cbSJens Wiklander 173817466cbSJens Wiklander if( count++ > 10 ) 174817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED ); 175817466cbSJens Wiklander } 176817466cbSJens Wiklander while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); 177817466cbSJens Wiklander 178817466cbSJens Wiklander /* 179817466cbSJens Wiklander * Calculate GX = G^X mod P 180817466cbSJens Wiklander */ 181817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, 182817466cbSJens Wiklander &ctx->P , &ctx->RP ) ); 183817466cbSJens Wiklander 184817466cbSJens Wiklander if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) 185817466cbSJens Wiklander return( ret ); 186817466cbSJens Wiklander 187817466cbSJens Wiklander /* 188817466cbSJens Wiklander * export P, G, GX 189817466cbSJens Wiklander */ 190817466cbSJens Wiklander #define DHM_MPI_EXPORT(X,n) \ 191817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, p + 2, n ) ); \ 192817466cbSJens Wiklander *p++ = (unsigned char)( n >> 8 ); \ 193817466cbSJens Wiklander *p++ = (unsigned char)( n ); p += n; 194817466cbSJens Wiklander 195817466cbSJens Wiklander n1 = mbedtls_mpi_size( &ctx->P ); 196817466cbSJens Wiklander n2 = mbedtls_mpi_size( &ctx->G ); 197817466cbSJens Wiklander n3 = mbedtls_mpi_size( &ctx->GX ); 198817466cbSJens Wiklander 199817466cbSJens Wiklander p = output; 200817466cbSJens Wiklander DHM_MPI_EXPORT( &ctx->P , n1 ); 201817466cbSJens Wiklander DHM_MPI_EXPORT( &ctx->G , n2 ); 202817466cbSJens Wiklander DHM_MPI_EXPORT( &ctx->GX, n3 ); 203817466cbSJens Wiklander 204817466cbSJens Wiklander *olen = p - output; 205817466cbSJens Wiklander 206817466cbSJens Wiklander ctx->len = n1; 207817466cbSJens Wiklander 208817466cbSJens Wiklander cleanup: 209817466cbSJens Wiklander 210817466cbSJens Wiklander if( ret != 0 ) 211817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret ); 212817466cbSJens Wiklander 213817466cbSJens Wiklander return( 0 ); 214817466cbSJens Wiklander } 215817466cbSJens Wiklander 216817466cbSJens Wiklander /* 217817466cbSJens Wiklander * Import the peer's public value G^Y 218817466cbSJens Wiklander */ 219817466cbSJens Wiklander int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, 220817466cbSJens Wiklander const unsigned char *input, size_t ilen ) 221817466cbSJens Wiklander { 222817466cbSJens Wiklander int ret; 223817466cbSJens Wiklander 224817466cbSJens Wiklander if( ctx == NULL || ilen < 1 || ilen > ctx->len ) 225817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 226817466cbSJens Wiklander 227817466cbSJens Wiklander if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 ) 228817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret ); 229817466cbSJens Wiklander 230817466cbSJens Wiklander return( 0 ); 231817466cbSJens Wiklander } 232817466cbSJens Wiklander 233817466cbSJens Wiklander /* 234817466cbSJens Wiklander * Create own private value X and export G^X 235817466cbSJens Wiklander */ 236817466cbSJens Wiklander int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, 237817466cbSJens Wiklander unsigned char *output, size_t olen, 238817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 239817466cbSJens Wiklander void *p_rng ) 240817466cbSJens Wiklander { 241817466cbSJens Wiklander int ret, count = 0; 242817466cbSJens Wiklander 243817466cbSJens Wiklander if( ctx == NULL || olen < 1 || olen > ctx->len ) 244817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 245817466cbSJens Wiklander 246817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) 247817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 248817466cbSJens Wiklander 249817466cbSJens Wiklander /* 250817466cbSJens Wiklander * generate X and calculate GX = G^X mod P 251817466cbSJens Wiklander */ 252817466cbSJens Wiklander do 253817466cbSJens Wiklander { 254817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) ); 255817466cbSJens Wiklander 256817466cbSJens Wiklander while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) 257817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) ); 258817466cbSJens Wiklander 259817466cbSJens Wiklander if( count++ > 10 ) 260817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED ); 261817466cbSJens Wiklander } 262817466cbSJens Wiklander while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); 263817466cbSJens Wiklander 264817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, 265817466cbSJens Wiklander &ctx->P , &ctx->RP ) ); 266817466cbSJens Wiklander 267817466cbSJens Wiklander if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) 268817466cbSJens Wiklander return( ret ); 269817466cbSJens Wiklander 270817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) ); 271817466cbSJens Wiklander 272817466cbSJens Wiklander cleanup: 273817466cbSJens Wiklander 274817466cbSJens Wiklander if( ret != 0 ) 275817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret ); 276817466cbSJens Wiklander 277817466cbSJens Wiklander return( 0 ); 278817466cbSJens Wiklander } 279817466cbSJens Wiklander 280817466cbSJens Wiklander /* 281817466cbSJens Wiklander * Use the blinding method and optimisation suggested in section 10 of: 282817466cbSJens Wiklander * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, 283817466cbSJens Wiklander * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer 284817466cbSJens Wiklander * Berlin Heidelberg, 1996. p. 104-113. 285817466cbSJens Wiklander */ 286817466cbSJens Wiklander static int dhm_update_blinding( mbedtls_dhm_context *ctx, 287817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) 288817466cbSJens Wiklander { 289817466cbSJens Wiklander int ret, count; 290817466cbSJens Wiklander 291817466cbSJens Wiklander /* 292817466cbSJens Wiklander * Don't use any blinding the first time a particular X is used, 293817466cbSJens Wiklander * but remember it to use blinding next time. 294817466cbSJens Wiklander */ 295817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 ) 296817466cbSJens Wiklander { 297817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) ); 298817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) ); 299817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) ); 300817466cbSJens Wiklander 301817466cbSJens Wiklander return( 0 ); 302817466cbSJens Wiklander } 303817466cbSJens Wiklander 304817466cbSJens Wiklander /* 305817466cbSJens Wiklander * Ok, we need blinding. Can we re-use existing values? 306817466cbSJens Wiklander * If yes, just update them by squaring them. 307817466cbSJens Wiklander */ 308817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ) 309817466cbSJens Wiklander { 310817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); 311817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) ); 312817466cbSJens Wiklander 313817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); 314817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) ); 315817466cbSJens Wiklander 316817466cbSJens Wiklander return( 0 ); 317817466cbSJens Wiklander } 318817466cbSJens Wiklander 319817466cbSJens Wiklander /* 320817466cbSJens Wiklander * We need to generate blinding values from scratch 321817466cbSJens Wiklander */ 322817466cbSJens Wiklander 323817466cbSJens Wiklander /* Vi = random( 2, P-1 ) */ 324817466cbSJens Wiklander count = 0; 325817466cbSJens Wiklander do 326817466cbSJens Wiklander { 327817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ) ); 328817466cbSJens Wiklander 329817466cbSJens Wiklander while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 ) 330817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) ); 331817466cbSJens Wiklander 332817466cbSJens Wiklander if( count++ > 10 ) 333817466cbSJens Wiklander return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); 334817466cbSJens Wiklander } 335817466cbSJens Wiklander while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 ); 336817466cbSJens Wiklander 337817466cbSJens Wiklander /* Vf = Vi^-X mod P */ 338817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) ); 339817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) ); 340817466cbSJens Wiklander 341817466cbSJens Wiklander cleanup: 342817466cbSJens Wiklander return( ret ); 343817466cbSJens Wiklander } 344817466cbSJens Wiklander 345817466cbSJens Wiklander /* 346817466cbSJens Wiklander * Derive and export the shared secret (G^Y)^X mod P 347817466cbSJens Wiklander */ 348817466cbSJens Wiklander int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, 349817466cbSJens Wiklander unsigned char *output, size_t output_size, size_t *olen, 350817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 351817466cbSJens Wiklander void *p_rng ) 352817466cbSJens Wiklander { 353817466cbSJens Wiklander int ret; 354817466cbSJens Wiklander mbedtls_mpi GYb; 355817466cbSJens Wiklander 356817466cbSJens Wiklander if( ctx == NULL || output_size < ctx->len ) 357817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); 358817466cbSJens Wiklander 359817466cbSJens Wiklander if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) 360817466cbSJens Wiklander return( ret ); 361817466cbSJens Wiklander 362817466cbSJens Wiklander mbedtls_mpi_init( &GYb ); 363817466cbSJens Wiklander 364817466cbSJens Wiklander /* Blind peer's value */ 365817466cbSJens Wiklander if( f_rng != NULL ) 366817466cbSJens Wiklander { 367817466cbSJens Wiklander MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) ); 368817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) ); 369817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) ); 370817466cbSJens Wiklander } 371817466cbSJens Wiklander else 372817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) ); 373817466cbSJens Wiklander 374817466cbSJens Wiklander /* Do modular exponentiation */ 375817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X, 376817466cbSJens Wiklander &ctx->P, &ctx->RP ) ); 377817466cbSJens Wiklander 378817466cbSJens Wiklander /* Unblind secret value */ 379817466cbSJens Wiklander if( f_rng != NULL ) 380817466cbSJens Wiklander { 381817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) ); 382817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) ); 383817466cbSJens Wiklander } 384817466cbSJens Wiklander 385817466cbSJens Wiklander *olen = mbedtls_mpi_size( &ctx->K ); 386817466cbSJens Wiklander 387817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) ); 388817466cbSJens Wiklander 389817466cbSJens Wiklander cleanup: 390817466cbSJens Wiklander mbedtls_mpi_free( &GYb ); 391817466cbSJens Wiklander 392817466cbSJens Wiklander if( ret != 0 ) 393817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret ); 394817466cbSJens Wiklander 395817466cbSJens Wiklander return( 0 ); 396817466cbSJens Wiklander } 397817466cbSJens Wiklander 398817466cbSJens Wiklander /* 399817466cbSJens Wiklander * Free the components of a DHM key 400817466cbSJens Wiklander */ 401817466cbSJens Wiklander void mbedtls_dhm_free( mbedtls_dhm_context *ctx ) 402817466cbSJens Wiklander { 403817466cbSJens Wiklander mbedtls_mpi_free( &ctx->pX); mbedtls_mpi_free( &ctx->Vf ); mbedtls_mpi_free( &ctx->Vi ); 404817466cbSJens Wiklander mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->K ); mbedtls_mpi_free( &ctx->GY ); 405817466cbSJens Wiklander mbedtls_mpi_free( &ctx->GX ); mbedtls_mpi_free( &ctx->X ); mbedtls_mpi_free( &ctx->G ); 406817466cbSJens Wiklander mbedtls_mpi_free( &ctx->P ); 407817466cbSJens Wiklander 408817466cbSJens Wiklander mbedtls_zeroize( ctx, sizeof( mbedtls_dhm_context ) ); 409817466cbSJens Wiklander } 410817466cbSJens Wiklander 411817466cbSJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C) 412817466cbSJens Wiklander /* 413817466cbSJens Wiklander * Parse DHM parameters 414817466cbSJens Wiklander */ 415817466cbSJens Wiklander int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, 416817466cbSJens Wiklander size_t dhminlen ) 417817466cbSJens Wiklander { 418817466cbSJens Wiklander int ret; 419817466cbSJens Wiklander size_t len; 420817466cbSJens Wiklander unsigned char *p, *end; 421817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 422817466cbSJens Wiklander mbedtls_pem_context pem; 423817466cbSJens Wiklander 424817466cbSJens Wiklander mbedtls_pem_init( &pem ); 425817466cbSJens Wiklander 426817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 427817466cbSJens Wiklander if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' ) 428817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 429817466cbSJens Wiklander else 430817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 431817466cbSJens Wiklander "-----BEGIN DH PARAMETERS-----", 432817466cbSJens Wiklander "-----END DH PARAMETERS-----", 433817466cbSJens Wiklander dhmin, NULL, 0, &dhminlen ); 434817466cbSJens Wiklander 435817466cbSJens Wiklander if( ret == 0 ) 436817466cbSJens Wiklander { 437817466cbSJens Wiklander /* 438817466cbSJens Wiklander * Was PEM encoded 439817466cbSJens Wiklander */ 440817466cbSJens Wiklander dhminlen = pem.buflen; 441817466cbSJens Wiklander } 442817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 443817466cbSJens Wiklander goto exit; 444817466cbSJens Wiklander 445817466cbSJens Wiklander p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin; 446817466cbSJens Wiklander #else 447817466cbSJens Wiklander p = (unsigned char *) dhmin; 448817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 449817466cbSJens Wiklander end = p + dhminlen; 450817466cbSJens Wiklander 451817466cbSJens Wiklander /* 452817466cbSJens Wiklander * DHParams ::= SEQUENCE { 453817466cbSJens Wiklander * prime INTEGER, -- P 454817466cbSJens Wiklander * generator INTEGER, -- g 455817466cbSJens Wiklander * privateValueLength INTEGER OPTIONAL 456817466cbSJens Wiklander * } 457817466cbSJens Wiklander */ 458817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 459817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 460817466cbSJens Wiklander { 461817466cbSJens Wiklander ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; 462817466cbSJens Wiklander goto exit; 463817466cbSJens Wiklander } 464817466cbSJens Wiklander 465817466cbSJens Wiklander end = p + len; 466817466cbSJens Wiklander 467817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P ) ) != 0 || 468817466cbSJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 ) 469817466cbSJens Wiklander { 470817466cbSJens Wiklander ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; 471817466cbSJens Wiklander goto exit; 472817466cbSJens Wiklander } 473817466cbSJens Wiklander 474817466cbSJens Wiklander if( p != end ) 475817466cbSJens Wiklander { 476817466cbSJens Wiklander /* This might be the optional privateValueLength. 477817466cbSJens Wiklander * If so, we can cleanly discard it */ 478817466cbSJens Wiklander mbedtls_mpi rec; 479817466cbSJens Wiklander mbedtls_mpi_init( &rec ); 480817466cbSJens Wiklander ret = mbedtls_asn1_get_mpi( &p, end, &rec ); 481817466cbSJens Wiklander mbedtls_mpi_free( &rec ); 482817466cbSJens Wiklander if ( ret != 0 ) 483817466cbSJens Wiklander { 484817466cbSJens Wiklander ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; 485817466cbSJens Wiklander goto exit; 486817466cbSJens Wiklander } 487817466cbSJens Wiklander if ( p != end ) 488817466cbSJens Wiklander { 489817466cbSJens Wiklander ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + 490817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; 491817466cbSJens Wiklander goto exit; 492817466cbSJens Wiklander } 493817466cbSJens Wiklander } 494817466cbSJens Wiklander 495817466cbSJens Wiklander ret = 0; 496817466cbSJens Wiklander 497817466cbSJens Wiklander dhm->len = mbedtls_mpi_size( &dhm->P ); 498817466cbSJens Wiklander 499817466cbSJens Wiklander exit: 500817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 501817466cbSJens Wiklander mbedtls_pem_free( &pem ); 502817466cbSJens Wiklander #endif 503817466cbSJens Wiklander if( ret != 0 ) 504817466cbSJens Wiklander mbedtls_dhm_free( dhm ); 505817466cbSJens Wiklander 506817466cbSJens Wiklander return( ret ); 507817466cbSJens Wiklander } 508817466cbSJens Wiklander 509817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 510817466cbSJens Wiklander /* 511817466cbSJens Wiklander * Load all data from a file into a given buffer. 512817466cbSJens Wiklander * 513817466cbSJens Wiklander * The file is expected to contain either PEM or DER encoded data. 514817466cbSJens Wiklander * A terminating null byte is always appended. It is included in the announced 515817466cbSJens Wiklander * length only if the data looks like it is PEM encoded. 516817466cbSJens Wiklander */ 517817466cbSJens Wiklander static int load_file( const char *path, unsigned char **buf, size_t *n ) 518817466cbSJens Wiklander { 519817466cbSJens Wiklander FILE *f; 520817466cbSJens Wiklander long size; 521817466cbSJens Wiklander 522817466cbSJens Wiklander if( ( f = fopen( path, "rb" ) ) == NULL ) 523817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); 524817466cbSJens Wiklander 525817466cbSJens Wiklander fseek( f, 0, SEEK_END ); 526817466cbSJens Wiklander if( ( size = ftell( f ) ) == -1 ) 527817466cbSJens Wiklander { 528817466cbSJens Wiklander fclose( f ); 529817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); 530817466cbSJens Wiklander } 531817466cbSJens Wiklander fseek( f, 0, SEEK_SET ); 532817466cbSJens Wiklander 533817466cbSJens Wiklander *n = (size_t) size; 534817466cbSJens Wiklander 535817466cbSJens Wiklander if( *n + 1 == 0 || 536817466cbSJens Wiklander ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) 537817466cbSJens Wiklander { 538817466cbSJens Wiklander fclose( f ); 539817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_ALLOC_FAILED ); 540817466cbSJens Wiklander } 541817466cbSJens Wiklander 542817466cbSJens Wiklander if( fread( *buf, 1, *n, f ) != *n ) 543817466cbSJens Wiklander { 544817466cbSJens Wiklander fclose( f ); 545817466cbSJens Wiklander mbedtls_free( *buf ); 546817466cbSJens Wiklander return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); 547817466cbSJens Wiklander } 548817466cbSJens Wiklander 549817466cbSJens Wiklander fclose( f ); 550817466cbSJens Wiklander 551817466cbSJens Wiklander (*buf)[*n] = '\0'; 552817466cbSJens Wiklander 553817466cbSJens Wiklander if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) 554817466cbSJens Wiklander ++*n; 555817466cbSJens Wiklander 556817466cbSJens Wiklander return( 0 ); 557817466cbSJens Wiklander } 558817466cbSJens Wiklander 559817466cbSJens Wiklander /* 560817466cbSJens Wiklander * Load and parse DHM parameters 561817466cbSJens Wiklander */ 562817466cbSJens Wiklander int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ) 563817466cbSJens Wiklander { 564817466cbSJens Wiklander int ret; 565817466cbSJens Wiklander size_t n; 566817466cbSJens Wiklander unsigned char *buf; 567817466cbSJens Wiklander 568817466cbSJens Wiklander if( ( ret = load_file( path, &buf, &n ) ) != 0 ) 569817466cbSJens Wiklander return( ret ); 570817466cbSJens Wiklander 571817466cbSJens Wiklander ret = mbedtls_dhm_parse_dhm( dhm, buf, n ); 572817466cbSJens Wiklander 573817466cbSJens Wiklander mbedtls_zeroize( buf, n ); 574817466cbSJens Wiklander mbedtls_free( buf ); 575817466cbSJens Wiklander 576817466cbSJens Wiklander return( ret ); 577817466cbSJens Wiklander } 578817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 579817466cbSJens Wiklander #endif /* MBEDTLS_ASN1_PARSE_C */ 580817466cbSJens Wiklander 581817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 582817466cbSJens Wiklander 583817466cbSJens Wiklander static const char mbedtls_test_dhm_params[] = 584817466cbSJens Wiklander "-----BEGIN DH PARAMETERS-----\r\n" 585817466cbSJens Wiklander "MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n" 586817466cbSJens Wiklander "1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n" 587817466cbSJens Wiklander "9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n" 588817466cbSJens Wiklander "-----END DH PARAMETERS-----\r\n"; 589817466cbSJens Wiklander 590817466cbSJens Wiklander static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params ); 591817466cbSJens Wiklander 592817466cbSJens Wiklander /* 593817466cbSJens Wiklander * Checkup routine 594817466cbSJens Wiklander */ 595817466cbSJens Wiklander int mbedtls_dhm_self_test( int verbose ) 596817466cbSJens Wiklander { 597817466cbSJens Wiklander int ret; 598817466cbSJens Wiklander mbedtls_dhm_context dhm; 599817466cbSJens Wiklander 600817466cbSJens Wiklander mbedtls_dhm_init( &dhm ); 601817466cbSJens Wiklander 602817466cbSJens Wiklander if( verbose != 0 ) 603817466cbSJens Wiklander mbedtls_printf( " DHM parameter load: " ); 604817466cbSJens Wiklander 605817466cbSJens Wiklander if( ( ret = mbedtls_dhm_parse_dhm( &dhm, 606817466cbSJens Wiklander (const unsigned char *) mbedtls_test_dhm_params, 607817466cbSJens Wiklander mbedtls_test_dhm_params_len ) ) != 0 ) 608817466cbSJens Wiklander { 609817466cbSJens Wiklander if( verbose != 0 ) 610817466cbSJens Wiklander mbedtls_printf( "failed\n" ); 611817466cbSJens Wiklander 612817466cbSJens Wiklander ret = 1; 613817466cbSJens Wiklander goto exit; 614817466cbSJens Wiklander } 615817466cbSJens Wiklander 616817466cbSJens Wiklander if( verbose != 0 ) 617817466cbSJens Wiklander mbedtls_printf( "passed\n\n" ); 618817466cbSJens Wiklander 619817466cbSJens Wiklander exit: 620817466cbSJens Wiklander mbedtls_dhm_free( &dhm ); 621817466cbSJens Wiklander 622817466cbSJens Wiklander return( ret ); 623817466cbSJens Wiklander } 624817466cbSJens Wiklander 625817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 626817466cbSJens Wiklander 627817466cbSJens Wiklander #endif /* MBEDTLS_DHM_C */ 628