mbed os with nrf51 internal bandgap enabled to read battery level

Dependents:   BLE_file_test BLE_Blink ExternalEncoder

Committer:
elessair
Date:
Sun Oct 23 15:10:02 2016 +0000
Revision:
0:f269e3021894
Initial commit

Who changed what in which revision?

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