Commit 863dfb59 authored by Nathaniel Wesley Filardo's avatar Nathaniel Wesley Filardo Committed by Marcel Stör
Browse files

SSL rampage (#2938)

* Remove stale putative MD2 support

This hasn't worked in a while, presumably since one of our upstream
merges.  Don't bother making it work, since MD2 is generally considered
insecure.

* Land mbedtls 2.16.3-77-gf02988e57

* TLS: remove some dead code from espconn_mbedtls

There was some... frankly kind of scary buffer and data shuffling if
ESP8266_PLATFORM was defined.  Since we don't, in fact, define that
preprocessor symbol, just drop the code lest anyone (possibly future-me)
be scared.

* TLS: espconn_mbedtls: run through astyle

No functional changes

* TLS: espconn_mbedtls: put the file_params on the stack

There's no need to malloc a structure that's used only locally.

* TLS: Further minor tidying of mbedtls glue

What an absolute shitshow this is.  mbedtls should absolutely not
be mentioned inside sys/socket.h and app/mbedtls/app/lwIPSocket.c is not
so much glue as it as a complete copy of a random subset of lwIP; it
should go, but we aren't there yet.

Get rid of the mysterious "mbedlts_record" struct, which housed merely a
length of bytes sent solely for gating the "record sent" callback.

Remove spurious __attribute__((weak)) from symbols not otherwise
defined and rename them to emphasize that they are not actually part of
mbedtls proper.

* TLS: Rampage esp mbedtls glue and delete unused code

This at least makes the shitshow smaller

* TLS: lwip: fix some memp definitions

I presume these also need the new arguments

* TLS: Remove more non-NodeMCU code from our mbedtls

* TLS: drop support for 1.1

Depending on who you ask it's either EOL already or EOL soon, so
we may as well get rid of it now.
parent f5672207
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#if defined(MBEDTLS_DHM_C) #if defined(MBEDTLS_DHM_C)
#include "mbedtls/dhm.h" #include "mbedtls/dhm.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
...@@ -58,10 +59,11 @@ ...@@ -58,10 +59,11 @@
#endif #endif
#if !defined(MBEDTLS_DHM_ALT) #if !defined(MBEDTLS_DHM_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) { #define DHM_VALIDATE_RET( cond ) \
volatile unsigned char *p = v; while( n-- ) *p++ = 0; MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA )
} #define DHM_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
/* /*
* helper to validate the mbedtls_mpi size and import it * helper to validate the mbedtls_mpi size and import it
...@@ -124,6 +126,7 @@ cleanup: ...@@ -124,6 +126,7 @@ cleanup:
void mbedtls_dhm_init( mbedtls_dhm_context *ctx ) void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
{ {
DHM_VALIDATE( ctx != NULL );
memset( ctx, 0, sizeof( mbedtls_dhm_context ) ); memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
} }
...@@ -135,6 +138,9 @@ int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, ...@@ -135,6 +138,9 @@ int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
const unsigned char *end ) const unsigned char *end )
{ {
int ret; int ret;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( p != NULL && *p != NULL );
DHM_VALIDATE_RET( end != NULL );
if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 || if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 ||
( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 || ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 ||
...@@ -160,6 +166,10 @@ int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, ...@@ -160,6 +166,10 @@ int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size,
int ret, count = 0; int ret, count = 0;
size_t n1, n2, n3; size_t n1, n2, n3;
unsigned char *p; unsigned char *p;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( output != NULL );
DHM_VALIDATE_RET( olen != NULL );
DHM_VALIDATE_RET( f_rng != NULL );
if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
...@@ -230,9 +240,9 @@ int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx, ...@@ -230,9 +240,9 @@ int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx,
const mbedtls_mpi *G ) const mbedtls_mpi *G )
{ {
int ret; int ret;
DHM_VALIDATE_RET( ctx != NULL );
if( ctx == NULL || P == NULL || G == NULL ) DHM_VALIDATE_RET( P != NULL );
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); DHM_VALIDATE_RET( G != NULL );
if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 || if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ||
( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 ) ( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 )
...@@ -251,8 +261,10 @@ int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, ...@@ -251,8 +261,10 @@ int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,
const unsigned char *input, size_t ilen ) const unsigned char *input, size_t ilen )
{ {
int ret; int ret;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( input != NULL );
if( ctx == NULL || ilen < 1 || ilen > ctx->len ) if( ilen < 1 || ilen > ctx->len )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 ) if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
...@@ -270,8 +282,11 @@ int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, ...@@ -270,8 +282,11 @@ int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size,
void *p_rng ) void *p_rng )
{ {
int ret, count = 0; int ret, count = 0;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( output != NULL );
DHM_VALIDATE_RET( f_rng != NULL );
if( ctx == NULL || olen < 1 || olen > ctx->len ) if( olen < 1 || olen > ctx->len )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
...@@ -383,8 +398,11 @@ int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, ...@@ -383,8 +398,11 @@ int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx,
{ {
int ret; int ret;
mbedtls_mpi GYb; mbedtls_mpi GYb;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( output != NULL );
DHM_VALIDATE_RET( olen != NULL );
if( ctx == NULL || output_size < ctx->len ) if( output_size < ctx->len )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
...@@ -431,13 +449,21 @@ cleanup: ...@@ -431,13 +449,21 @@ cleanup:
*/ */
void mbedtls_dhm_free( mbedtls_dhm_context *ctx ) void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
{ {
mbedtls_mpi_free( &ctx->pX ); mbedtls_mpi_free( &ctx->Vf ); if( ctx == NULL )
mbedtls_mpi_free( &ctx->Vi ); mbedtls_mpi_free( &ctx->RP ); return;
mbedtls_mpi_free( &ctx->K ); mbedtls_mpi_free( &ctx->GY );
mbedtls_mpi_free( &ctx->GX ); mbedtls_mpi_free( &ctx->X ); mbedtls_mpi_free( &ctx->pX );
mbedtls_mpi_free( &ctx->G ); mbedtls_mpi_free( &ctx->P ); mbedtls_mpi_free( &ctx->Vf );
mbedtls_mpi_free( &ctx->Vi );
mbedtls_zeroize( ctx, sizeof( mbedtls_dhm_context ) ); mbedtls_mpi_free( &ctx->RP );
mbedtls_mpi_free( &ctx->K );
mbedtls_mpi_free( &ctx->GY );
mbedtls_mpi_free( &ctx->GX );
mbedtls_mpi_free( &ctx->X );
mbedtls_mpi_free( &ctx->G );
mbedtls_mpi_free( &ctx->P );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_dhm_context ) );
} }
#if defined(MBEDTLS_ASN1_PARSE_C) #if defined(MBEDTLS_ASN1_PARSE_C)
...@@ -452,7 +478,12 @@ int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, ...@@ -452,7 +478,12 @@ int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
unsigned char *p, *end; unsigned char *p, *end;
#if defined(MBEDTLS_PEM_PARSE_C) #if defined(MBEDTLS_PEM_PARSE_C)
mbedtls_pem_context pem; mbedtls_pem_context pem;
#endif /* MBEDTLS_PEM_PARSE_C */
DHM_VALIDATE_RET( dhm != NULL );
DHM_VALIDATE_RET( dhmin != NULL );
#if defined(MBEDTLS_PEM_PARSE_C)
mbedtls_pem_init( &pem ); mbedtls_pem_init( &pem );
/* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
...@@ -575,7 +606,7 @@ static int load_file( const char *path, unsigned char **buf, size_t *n ) ...@@ -575,7 +606,7 @@ static int load_file( const char *path, unsigned char **buf, size_t *n )
{ {
fclose( f ); fclose( f );
mbedtls_zeroize( *buf, *n + 1 ); mbedtls_platform_zeroize( *buf, *n + 1 );
mbedtls_free( *buf ); mbedtls_free( *buf );
return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
...@@ -599,13 +630,15 @@ int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ) ...@@ -599,13 +630,15 @@ int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
int ret; int ret;
size_t n; size_t n;
unsigned char *buf; unsigned char *buf;
DHM_VALIDATE_RET( dhm != NULL );
DHM_VALIDATE_RET( path != NULL );
if( ( ret = load_file( path, &buf, &n ) ) != 0 ) if( ( ret = load_file( path, &buf, &n ) ) != 0 )
return( ret ); return( ret );
ret = mbedtls_dhm_parse_dhm( dhm, buf, n ); ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
mbedtls_zeroize( buf, n ); mbedtls_platform_zeroize( buf, n );
mbedtls_free( buf ); mbedtls_free( buf );
return( ret ); return( ret );
...@@ -616,12 +649,28 @@ int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ) ...@@ -616,12 +649,28 @@ int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
#if defined(MBEDTLS_SELF_TEST) #if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PEM_PARSE_C)
static const char mbedtls_test_dhm_params[] = static const char mbedtls_test_dhm_params[] =
"-----BEGIN DH PARAMETERS-----\r\n" "-----BEGIN DH PARAMETERS-----\r\n"
"MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n" "MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n"
"1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n" "1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n"
"9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n" "9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n"
"-----END DH PARAMETERS-----\r\n"; "-----END DH PARAMETERS-----\r\n";
#else /* MBEDTLS_PEM_PARSE_C */
static const char mbedtls_test_dhm_params[] = {
0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x35, 0xf4, 0x30, 0x44,
0x3a, 0x09, 0x90, 0x4f, 0x3a, 0x39, 0xa9, 0x79, 0x79, 0x7d, 0x07, 0x0d,
0xf5, 0x33, 0x78, 0xe7, 0x9c, 0x24, 0x38, 0xbe, 0xf4, 0xe7, 0x61, 0xf3,
0xc7, 0x14, 0x55, 0x33, 0x28, 0x58, 0x9b, 0x04, 0x1c, 0x80, 0x9b, 0xe1,
0xd6, 0xc6, 0xb5, 0xf1, 0xfc, 0x9f, 0x47, 0xd3, 0xa2, 0x54, 0x43, 0x18,
0x82, 0x53, 0xa9, 0x92, 0xa5, 0x68, 0x18, 0xb3, 0x7b, 0xa9, 0xde, 0x5a,
0x40, 0xd3, 0x62, 0xe5, 0x6e, 0xff, 0x0b, 0xe5, 0x41, 0x74, 0x74, 0xc1,
0x25, 0xc1, 0x99, 0x27, 0x2c, 0x8f, 0xe4, 0x1d, 0xea, 0x73, 0x3d, 0xf6,
0xf6, 0x62, 0xc9, 0x2a, 0xe7, 0x65, 0x56, 0xe7, 0x55, 0xd1, 0x0c, 0x64,
0xe6, 0xa5, 0x09, 0x68, 0xf6, 0x7f, 0xc6, 0xea, 0x73, 0xd0, 0xdc, 0xa8,
0x56, 0x9b, 0xe2, 0xba, 0x20, 0x4e, 0x23, 0x58, 0x0d, 0x8b, 0xca, 0x2f,
0x49, 0x75, 0xb3, 0x02, 0x01, 0x02 };
#endif /* MBEDTLS_PEM_PARSE_C */
static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params ); static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params );
......
...@@ -35,41 +35,92 @@ ...@@ -35,41 +35,92 @@
#if defined(MBEDTLS_ECDH_C) #if defined(MBEDTLS_ECDH_C)
#include "mbedtls/ecdh.h" #include "mbedtls/ecdh.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
/* Parameter validation macros based on platform_util.h */
#define ECDH_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA )
#define ECDH_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed;
#endif
static mbedtls_ecp_group_id mbedtls_ecdh_grp_id(
const mbedtls_ecdh_context *ctx )
{
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ctx->grp.id );
#else
return( ctx->grp_id );
#endif
}
#if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) #if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)
/* /*
* Generate public key: simple wrapper around mbedtls_ecp_gen_keypair * Generate public key (restartable version)
*
* Note: this internal function relies on its caller preserving the value of
* the output parameter 'd' across continuation calls. This would not be
* acceptable for a public function but is OK here as we control call sites.
*/
static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp,
mbedtls_mpi *d, mbedtls_ecp_point *Q,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx )
{
int ret;
/* If multiplication is in progress, we already generated a privkey */
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx == NULL || rs_ctx->rsm == NULL )
#endif
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G,
f_rng, p_rng, rs_ctx ) );
cleanup:
return( ret );
}
/*
* Generate public key
*/ */
int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,
int (*f_rng)(void *, unsigned char *, size_t), int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng ) void *p_rng )
{ {
return mbedtls_ecp_gen_keypair( grp, d, Q, f_rng, p_rng ); ECDH_VALIDATE_RET( grp != NULL );
ECDH_VALIDATE_RET( d != NULL );
ECDH_VALIDATE_RET( Q != NULL );
ECDH_VALIDATE_RET( f_rng != NULL );
return( ecdh_gen_public_restartable( grp, d, Q, f_rng, p_rng, NULL ) );
} }
#endif /* MBEDTLS_ECDH_GEN_PUBLIC_ALT */ #endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */
#if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) #if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT)
/* /*
* Compute shared secret (SEC1 3.3.1) * Compute shared secret (SEC1 3.3.1)
*/ */
int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, static int ecdh_compute_shared_restartable( mbedtls_ecp_group *grp,
mbedtls_mpi *z,
const mbedtls_ecp_point *Q, const mbedtls_mpi *d, const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
int (*f_rng)(void *, unsigned char *, size_t), int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng ) void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx )
{ {
int ret; int ret;
mbedtls_ecp_point P; mbedtls_ecp_point P;
mbedtls_ecp_point_init( &P ); mbedtls_ecp_point_init( &P );
/* MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &P, d, Q,
* Make sure Q is a valid pubkey before using it f_rng, p_rng, rs_ctx ) );
*/
MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) );
if( mbedtls_ecp_is_zero( &P ) ) if( mbedtls_ecp_is_zero( &P ) )
{ {
...@@ -84,71 +135,250 @@ cleanup: ...@@ -84,71 +135,250 @@ cleanup:
return( ret ); return( ret );
} }
#endif /* MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
/*
* Compute shared secret (SEC1 3.3.1)
*/
int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,
const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
ECDH_VALIDATE_RET( grp != NULL );
ECDH_VALIDATE_RET( Q != NULL );
ECDH_VALIDATE_RET( d != NULL );
ECDH_VALIDATE_RET( z != NULL );
return( ecdh_compute_shared_restartable( grp, z, Q, d,
f_rng, p_rng, NULL ) );
}
#endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
static void ecdh_init_internal( mbedtls_ecdh_context_mbed *ctx )
{
mbedtls_ecp_group_init( &ctx->grp );
mbedtls_mpi_init( &ctx->d );
mbedtls_ecp_point_init( &ctx->Q );
mbedtls_ecp_point_init( &ctx->Qp );
mbedtls_mpi_init( &ctx->z );
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_init( &ctx->rs );
#endif
}
/* /*
* Initialize context * Initialize context
*/ */
void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx )
{ {
ECDH_VALIDATE( ctx != NULL );
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
ecdh_init_internal( ctx );
mbedtls_ecp_point_init( &ctx->Vi );
mbedtls_ecp_point_init( &ctx->Vf );
mbedtls_mpi_init( &ctx->_d );
#else
memset( ctx, 0, sizeof( mbedtls_ecdh_context ) ); memset( ctx, 0, sizeof( mbedtls_ecdh_context ) );
ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
#endif
ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
#if defined(MBEDTLS_ECP_RESTARTABLE)
ctx->restart_enabled = 0;
#endif
}
static int ecdh_setup_internal( mbedtls_ecdh_context_mbed *ctx,
mbedtls_ecp_group_id grp_id )
{
int ret;
ret = mbedtls_ecp_group_load( &ctx->grp, grp_id );
if( ret != 0 )
{
return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
}
return( 0 );
} }
/* /*
* Free context * Setup context
*/ */
void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id )
{ {
if( ctx == NULL ) ECDH_VALIDATE_RET( ctx != NULL );
return;
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_setup_internal( ctx, grp_id ) );
#else
switch( grp_id )
{
default:
ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0;
ctx->grp_id = grp_id;
ecdh_init_internal( &ctx->ctx.mbed_ecdh );
return( ecdh_setup_internal( &ctx->ctx.mbed_ecdh, grp_id ) );
}
#endif
}
static void ecdh_free_internal( mbedtls_ecdh_context_mbed *ctx )
{
mbedtls_ecp_group_free( &ctx->grp ); mbedtls_ecp_group_free( &ctx->grp );
mbedtls_mpi_free( &ctx->d );
mbedtls_ecp_point_free( &ctx->Q ); mbedtls_ecp_point_free( &ctx->Q );
mbedtls_ecp_point_free( &ctx->Qp ); mbedtls_ecp_point_free( &ctx->Qp );
mbedtls_ecp_point_free( &ctx->Vi );
mbedtls_ecp_point_free( &ctx->Vf );
mbedtls_mpi_free( &ctx->d );
mbedtls_mpi_free( &ctx->z ); mbedtls_mpi_free( &ctx->z );
mbedtls_mpi_free( &ctx->_d );
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_free( &ctx->rs );
#endif
} }
#if defined(MBEDTLS_ECP_RESTARTABLE)
/* /*
* Setup and write the ServerKeyExhange parameters (RFC 4492) * Enable restartable operations for context
* struct {
* ECParameters curve_params;
* ECPoint public;
* } ServerECDHParams;
*/ */
int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx )
unsigned char *buf, size_t blen, {
int (*f_rng)(void *, unsigned char *, size_t), ECDH_VALIDATE( ctx != NULL );
void *p_rng )
ctx->restart_enabled = 1;
}
#endif
/*
* Free context
*/
void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx )
{
if( ctx == NULL )
return;
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
mbedtls_ecp_point_free( &ctx->Vi );
mbedtls_ecp_point_free( &ctx->Vf );
mbedtls_mpi_free( &ctx->_d );
ecdh_free_internal( ctx );
#else
switch( ctx->var )
{
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
ecdh_free_internal( &ctx->ctx.mbed_ecdh );
break;
default:
break;
}
ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
ctx->grp_id = MBEDTLS_ECP_DP_NONE;
#endif
}
static int ecdh_make_params_internal( mbedtls_ecdh_context_mbed *ctx,
size_t *olen, int point_format,
unsigned char *buf, size_t blen,
int (*f_rng)(void *,
unsigned char *,
size_t),
void *p_rng,
int restart_enabled )
{ {
int ret; int ret;
size_t grp_len, pt_len; size_t grp_len, pt_len;
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_ctx *rs_ctx = NULL;
#endif
if( ctx == NULL || ctx->grp.pbits == 0 ) if( ctx->grp.pbits == 0 )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) #if defined(MBEDTLS_ECP_RESTARTABLE)
!= 0 ) if( restart_enabled )
rs_ctx = &ctx->rs;
#else
(void) restart_enabled;
#endif
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
f_rng, p_rng, rs_ctx ) ) != 0 )
return( ret );
#else
if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
f_rng, p_rng ) ) != 0 )
return( ret ); return( ret );
#endif /* MBEDTLS_ECP_RESTARTABLE */
if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, blen ) ) if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf,
!= 0 ) blen ) ) != 0 )
return( ret ); return( ret );
buf += grp_len; buf += grp_len;
blen -= grp_len; blen -= grp_len;
if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format,
&pt_len, buf, blen ) ) != 0 ) &pt_len, buf, blen ) ) != 0 )
return( ret ); return( ret );
*olen = grp_len + pt_len; *olen = grp_len + pt_len;
return( 0 ); return( 0 );
} }
/*
* Setup and write the ServerKeyExhange parameters (RFC 4492)
* struct {
* ECParameters curve_params;
* ECPoint public;
* } ServerECDHParams;
*/
int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int restart_enabled = 0;
ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( olen != NULL );
ECDH_VALIDATE_RET( buf != NULL );
ECDH_VALIDATE_RET( f_rng != NULL );
#if defined(MBEDTLS_ECP_RESTARTABLE)
restart_enabled = ctx->restart_enabled;
#else
(void) restart_enabled;
#endif
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_make_params_internal( ctx, olen, ctx->point_format, buf, blen,
f_rng, p_rng, restart_enabled ) );
#else
switch( ctx->var )
{
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen,
ctx->point_format, buf, blen,
f_rng, p_rng,
restart_enabled ) );
default:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif
}
static int ecdh_read_params_internal( mbedtls_ecdh_context_mbed *ctx,
const unsigned char **buf,
const unsigned char *end )
{
return( mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf,
end - *buf ) );
}
/* /*
* Read the ServerKeyExhange parameters (RFC 4492) * Read the ServerKeyExhange parameters (RFC 4492)
* struct { * struct {
...@@ -157,31 +387,43 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, ...@@ -157,31 +387,43 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
* } ServerECDHParams; * } ServerECDHParams;
*/ */
int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx,
const unsigned char **buf, const unsigned char *end ) const unsigned char **buf,
const unsigned char *end )
{ {
int ret; int ret;
mbedtls_ecp_group_id grp_id;
if( ( ret = mbedtls_ecp_tls_read_group( &ctx->grp, buf, end - *buf ) ) != 0 ) ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( buf != NULL );
ECDH_VALIDATE_RET( *buf != NULL );
ECDH_VALIDATE_RET( end != NULL );
if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, end - *buf ) )
!= 0 )
return( ret ); return( ret );
if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, end - *buf ) ) if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 )
!= 0 )
return( ret ); return( ret );
return( 0 ); #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_read_params_internal( ctx, buf, end ) );
#else
switch( ctx->var )
{
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh,
buf, end ) );
default:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif
} }
/* static int ecdh_get_params_internal( mbedtls_ecdh_context_mbed *ctx,
* Get parameters from a keypair const mbedtls_ecp_keypair *key,
*/ mbedtls_ecdh_side side )
int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key,
mbedtls_ecdh_side side )
{ {
int ret; int ret;
if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 )
return( ret );
/* If it's not our key, just import the public part as Qp */ /* If it's not our key, just import the public part as Qp */
if( side == MBEDTLS_ECDH_THEIRS ) if( side == MBEDTLS_ECDH_THEIRS )
return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) ); return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) );
...@@ -198,39 +440,129 @@ int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypai ...@@ -198,39 +440,129 @@ int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypai
} }
/* /*
* Setup and export the client public value * Get parameters from a keypair
*/ */
int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx,
unsigned char *buf, size_t blen, const mbedtls_ecp_keypair *key,
int (*f_rng)(void *, unsigned char *, size_t), mbedtls_ecdh_side side )
void *p_rng )
{ {
int ret; int ret;
ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( key != NULL );
ECDH_VALIDATE_RET( side == MBEDTLS_ECDH_OURS ||
side == MBEDTLS_ECDH_THEIRS );
if( ctx == NULL || ctx->grp.pbits == 0 ) if( mbedtls_ecdh_grp_id( ctx ) == MBEDTLS_ECP_DP_NONE )
{
/* This is the first call to get_params(). Set up the context
* for use with the group. */
if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 )
return( ret );
}
else
{
/* This is not the first call to get_params(). Check that the
* current key's group is the same as the context's, which was set
* from the first key's group. */
if( mbedtls_ecdh_grp_id( ctx ) != key->grp.id )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
}
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_get_params_internal( ctx, key, side ) );
#else
switch( ctx->var )
{
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_get_params_internal( &ctx->ctx.mbed_ecdh,
key, side ) );
default:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif
}
static int ecdh_make_public_internal( mbedtls_ecdh_context_mbed *ctx,
size_t *olen, int point_format,
unsigned char *buf, size_t blen,
int (*f_rng)(void *,
unsigned char *,
size_t),
void *p_rng,
int restart_enabled )
{
int ret;
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_ctx *rs_ctx = NULL;
#endif
if( ctx->grp.pbits == 0 )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) #if defined(MBEDTLS_ECP_RESTARTABLE)
!= 0 ) if( restart_enabled )
rs_ctx = &ctx->rs;
#else
(void) restart_enabled;
#endif
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
f_rng, p_rng, rs_ctx ) ) != 0 )
return( ret );
#else
if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
f_rng, p_rng ) ) != 0 )
return( ret ); return( ret );
#endif /* MBEDTLS_ECP_RESTARTABLE */
return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, olen,
olen, buf, blen ); buf, blen );
} }
/* /*
* Parse and import the client's public value * Setup and export the client public value
*/ */
int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen,
const unsigned char *buf, size_t blen ) unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int restart_enabled = 0;
ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( olen != NULL );
ECDH_VALIDATE_RET( buf != NULL );
ECDH_VALIDATE_RET( f_rng != NULL );
#if defined(MBEDTLS_ECP_RESTARTABLE)
restart_enabled = ctx->restart_enabled;
#endif
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_make_public_internal( ctx, olen, ctx->point_format, buf, blen,
f_rng, p_rng, restart_enabled ) );
#else
switch( ctx->var )
{
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen,
ctx->point_format, buf, blen,
f_rng, p_rng,
restart_enabled ) );
default:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif
}
static int ecdh_read_public_internal( mbedtls_ecdh_context_mbed *ctx,
const unsigned char *buf, size_t blen )
{ {
int ret; int ret;
const unsigned char *p = buf; const unsigned char *p = buf;
if( ctx == NULL ) if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p,
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); blen ) ) != 0 )
if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, blen ) ) != 0 )
return( ret ); return( ret );
if( (size_t)( p - buf ) != blen ) if( (size_t)( p - buf ) != blen )
...@@ -240,23 +572,66 @@ int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, ...@@ -240,23 +572,66 @@ int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx,
} }
/* /*
* Derive and export the shared secret * Parse and import the client's public value
*/ */
int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx,
unsigned char *buf, size_t blen, const unsigned char *buf, size_t blen )
int (*f_rng)(void *, unsigned char *, size_t), {
void *p_rng ) ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( buf != NULL );
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_read_public_internal( ctx, buf, blen ) );
#else
switch( ctx->var )
{
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh,
buf, blen ) );
default:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif
}
static int ecdh_calc_secret_internal( mbedtls_ecdh_context_mbed *ctx,
size_t *olen, unsigned char *buf,
size_t blen,
int (*f_rng)(void *,
unsigned char *,
size_t),
void *p_rng,
int restart_enabled )
{ {
int ret; int ret;
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_ctx *rs_ctx = NULL;
#endif
if( ctx == NULL ) if( ctx == NULL || ctx->grp.pbits == 0 )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d, #if defined(MBEDTLS_ECP_RESTARTABLE)
f_rng, p_rng ) ) != 0 ) if( restart_enabled )
rs_ctx = &ctx->rs;
#else
(void) restart_enabled;
#endif
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( ( ret = ecdh_compute_shared_restartable( &ctx->grp, &ctx->z, &ctx->Qp,
&ctx->d, f_rng, p_rng,
rs_ctx ) ) != 0 )
{
return( ret );
}
#else
if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp,
&ctx->d, f_rng, p_rng ) ) != 0 )
{ {
return( ret ); return( ret );
} }
#endif /* MBEDTLS_ECP_RESTARTABLE */
if( mbedtls_mpi_size( &ctx->z ) > blen ) if( mbedtls_mpi_size( &ctx->z ) > blen )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
...@@ -265,4 +640,37 @@ int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, ...@@ -265,4 +640,37 @@ int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen,
return mbedtls_mpi_write_binary( &ctx->z, buf, *olen ); return mbedtls_mpi_write_binary( &ctx->z, buf, *olen );
} }
/*
* Derive and export the shared secret
*/
int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int restart_enabled = 0;
ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( olen != NULL );
ECDH_VALIDATE_RET( buf != NULL );
#if defined(MBEDTLS_ECP_RESTARTABLE)
restart_enabled = ctx->restart_enabled;
#endif
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_calc_secret_internal( ctx, olen, buf, blen, f_rng, p_rng,
restart_enabled ) );
#else
switch( ctx->var )
{
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_calc_secret_internal( &ctx->ctx.mbed_ecdh, olen, buf,
blen, f_rng, p_rng,
restart_enabled ) );
default:
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
}
#endif
}
#endif /* MBEDTLS_ECDH_C */ #endif /* MBEDTLS_ECDH_C */
...@@ -42,6 +42,186 @@ ...@@ -42,6 +42,186 @@
#include "mbedtls/hmac_drbg.h" #include "mbedtls/hmac_drbg.h"
#endif #endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
#include "mbedtls/platform_util.h"
/* Parameter validation macros based on platform_util.h */
#define ECDSA_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA )
#define ECDSA_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#if defined(MBEDTLS_ECP_RESTARTABLE)
/*
* Sub-context for ecdsa_verify()
*/
struct mbedtls_ecdsa_restart_ver
{
mbedtls_mpi u1, u2; /* intermediate values */
enum { /* what to do next? */
ecdsa_ver_init = 0, /* getting started */
ecdsa_ver_muladd, /* muladd step */
} state;
};
/*
* Init verify restart sub-context
*/
static void ecdsa_restart_ver_init( mbedtls_ecdsa_restart_ver_ctx *ctx )
{
mbedtls_mpi_init( &ctx->u1 );
mbedtls_mpi_init( &ctx->u2 );
ctx->state = ecdsa_ver_init;
}
/*
* Free the components of a verify restart sub-context
*/
static void ecdsa_restart_ver_free( mbedtls_ecdsa_restart_ver_ctx *ctx )
{
if( ctx == NULL )
return;
mbedtls_mpi_free( &ctx->u1 );
mbedtls_mpi_free( &ctx->u2 );
ecdsa_restart_ver_init( ctx );
}
/*
* Sub-context for ecdsa_sign()
*/
struct mbedtls_ecdsa_restart_sig
{
int sign_tries;
int key_tries;
mbedtls_mpi k; /* per-signature random */
mbedtls_mpi r; /* r value */
enum { /* what to do next? */
ecdsa_sig_init = 0, /* getting started */
ecdsa_sig_mul, /* doing ecp_mul() */
ecdsa_sig_modn, /* mod N computations */
} state;
};
/*
* Init verify sign sub-context
*/
static void ecdsa_restart_sig_init( mbedtls_ecdsa_restart_sig_ctx *ctx )
{
ctx->sign_tries = 0;
ctx->key_tries = 0;
mbedtls_mpi_init( &ctx->k );
mbedtls_mpi_init( &ctx->r );
ctx->state = ecdsa_sig_init;
}
/*
* Free the components of a sign restart sub-context
*/
static void ecdsa_restart_sig_free( mbedtls_ecdsa_restart_sig_ctx *ctx )
{
if( ctx == NULL )
return;
mbedtls_mpi_free( &ctx->k );
mbedtls_mpi_free( &ctx->r );
}
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
/*
* Sub-context for ecdsa_sign_det()
*/
struct mbedtls_ecdsa_restart_det
{
mbedtls_hmac_drbg_context rng_ctx; /* DRBG state */
enum { /* what to do next? */
ecdsa_det_init = 0, /* getting started */
ecdsa_det_sign, /* make signature */
} state;
};
/*
* Init verify sign_det sub-context
*/
static void ecdsa_restart_det_init( mbedtls_ecdsa_restart_det_ctx *ctx )
{
mbedtls_hmac_drbg_init( &ctx->rng_ctx );
ctx->state = ecdsa_det_init;
}
/*
* Free the components of a sign_det restart sub-context
*/
static void ecdsa_restart_det_free( mbedtls_ecdsa_restart_det_ctx *ctx )
{
if( ctx == NULL )
return;
mbedtls_hmac_drbg_free( &ctx->rng_ctx );
ecdsa_restart_det_init( ctx );
}
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
#define ECDSA_RS_ECP ( rs_ctx == NULL ? NULL : &rs_ctx->ecp )
/* Utility macro for checking and updating ops budget */
#define ECDSA_BUDGET( ops ) \
MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, ECDSA_RS_ECP, ops ) );
/* Call this when entering a function that needs its own sub-context */
#define ECDSA_RS_ENTER( SUB ) do { \
/* reset ops count for this call if top-level */ \
if( rs_ctx != NULL && rs_ctx->ecp.depth++ == 0 ) \
rs_ctx->ecp.ops_done = 0; \
\
/* set up our own sub-context if needed */ \
if( mbedtls_ecp_restart_is_enabled() && \
rs_ctx != NULL && rs_ctx->SUB == NULL ) \
{ \
rs_ctx->SUB = mbedtls_calloc( 1, sizeof( *rs_ctx->SUB ) ); \
if( rs_ctx->SUB == NULL ) \
return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); \
\
ecdsa_restart_## SUB ##_init( rs_ctx->SUB ); \
} \
} while( 0 )
/* Call this when leaving a function that needs its own sub-context */
#define ECDSA_RS_LEAVE( SUB ) do { \
/* clear our sub-context when not in progress (done or error) */ \
if( rs_ctx != NULL && rs_ctx->SUB != NULL && \
ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) \
{ \
ecdsa_restart_## SUB ##_free( rs_ctx->SUB ); \
mbedtls_free( rs_ctx->SUB ); \
rs_ctx->SUB = NULL; \
} \
\
if( rs_ctx != NULL ) \
rs_ctx->ecp.depth--; \
} while( 0 )
#else /* MBEDTLS_ECP_RESTARTABLE */
#define ECDSA_RS_ECP NULL
#define ECDSA_BUDGET( ops ) /* no-op; for compatibility */
#define ECDSA_RS_ENTER( SUB ) (void) rs_ctx
#define ECDSA_RS_LEAVE( SUB ) (void) rs_ctx
#endif /* MBEDTLS_ECP_RESTARTABLE */
/* /*
* Derive a suitable integer for group grp from a buffer of length len * Derive a suitable integer for group grp from a buffer of length len
* SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3
...@@ -70,13 +250,19 @@ cleanup: ...@@ -70,13 +250,19 @@ cleanup:
* Compute ECDSA signature of a hashed message (SEC1 4.1.3) * Compute ECDSA signature of a hashed message (SEC1 4.1.3)
* Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message)
*/ */
int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, static int ecdsa_sign_restartable( mbedtls_ecp_group *grp,
mbedtls_mpi *r, mbedtls_mpi *s,
const mbedtls_mpi *d, const unsigned char *buf, size_t blen, const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
int (*f_rng_blind)(void *, unsigned char *, size_t),
void *p_rng_blind,
mbedtls_ecdsa_restart_ctx *rs_ctx )
{ {
int ret, key_tries, sign_tries, blind_tries; int ret, key_tries, sign_tries;
int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries;
mbedtls_ecp_point R; mbedtls_ecp_point R;
mbedtls_mpi k, e, t; mbedtls_mpi k, e, t;
mbedtls_mpi *pk = &k, *pr = r;
/* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */
if( grp->N.p == NULL ) if( grp->N.p == NULL )
...@@ -89,26 +275,74 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, ...@@ -89,26 +275,74 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
mbedtls_ecp_point_init( &R ); mbedtls_ecp_point_init( &R );
mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t );
sign_tries = 0; ECDSA_RS_ENTER( sig );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->sig != NULL )
{
/* redirect to our context */
p_sign_tries = &rs_ctx->sig->sign_tries;
p_key_tries = &rs_ctx->sig->key_tries;
pk = &rs_ctx->sig->k;
pr = &rs_ctx->sig->r;
/* jump to current step */
if( rs_ctx->sig->state == ecdsa_sig_mul )
goto mul;
if( rs_ctx->sig->state == ecdsa_sig_modn )
goto modn;
}
#endif /* MBEDTLS_ECP_RESTARTABLE */
*p_sign_tries = 0;
do do
{ {
if( *p_sign_tries++ > 10 )
{
ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
goto cleanup;
}
/* /*
* Steps 1-3: generate a suitable ephemeral keypair * Steps 1-3: generate a suitable ephemeral keypair
* and set r = xR mod n * and set r = xR mod n
*/ */
key_tries = 0; *p_key_tries = 0;
do do
{ {
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) ); if( *p_key_tries++ > 10 )
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) );
if( key_tries++ > 10 )
{ {
ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
goto cleanup; goto cleanup;
} }
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, pk, f_rng, p_rng ) );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->sig != NULL )
rs_ctx->sig->state = ecdsa_sig_mul;
mul:
#endif
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &R, pk, &grp->G,
f_rng_blind,
p_rng_blind,
ECDSA_RS_ECP ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pr, &R.X, &grp->N ) );
} }
while( mbedtls_mpi_cmp_int( r, 0 ) == 0 ); while( mbedtls_mpi_cmp_int( pr, 0 ) == 0 );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->sig != NULL )
rs_ctx->sig->state = ecdsa_sig_modn;
modn:
#endif
/*
* Accounting for everything up to the end of the loop
* (step 6, but checking now avoids saving e and t)
*/
ECDSA_BUDGET( MBEDTLS_ECP_OPS_INV + 4 );
/* /*
* Step 5: derive MPI from hashed message * Step 5: derive MPI from hashed message
...@@ -119,57 +353,71 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, ...@@ -119,57 +353,71 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
* Generate a random value to blind inv_mod in next step, * Generate a random value to blind inv_mod in next step,
* avoiding a potential timing leak. * avoiding a potential timing leak.
*/ */
blind_tries = 0; MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng_blind,
do p_rng_blind ) );
{
size_t n_size = ( grp->nbits + 7 ) / 8;
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) );
/* See mbedtls_ecp_gen_keypair() */
if( ++blind_tries > 30 )
return( MBEDTLS_ERR_ECP_RANDOM_FAILED );
}
while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 ||
mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 );
/* /*
* Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n
*/ */
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, d ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, pr, d ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &k, &k, &t ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pk, pk, &t ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, pk, &grp->N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) );
if( sign_tries++ > 10 )
{
ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
goto cleanup;
}
} }
while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); while( mbedtls_mpi_cmp_int( s, 0 ) == 0 );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->sig != NULL )
mbedtls_mpi_copy( r, pr );
#endif
cleanup: cleanup:
mbedtls_ecp_point_free( &R ); mbedtls_ecp_point_free( &R );
mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t );
ECDSA_RS_LEAVE( sig );
return( ret ); return( ret );
} }
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
/*
* Compute ECDSA signature of a hashed message
*/
int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
{
ECDSA_VALIDATE_RET( grp != NULL );
ECDSA_VALIDATE_RET( r != NULL );
ECDSA_VALIDATE_RET( s != NULL );
ECDSA_VALIDATE_RET( d != NULL );
ECDSA_VALIDATE_RET( f_rng != NULL );
ECDSA_VALIDATE_RET( buf != NULL || blen == 0 );
/* Use the same RNG for both blinding and ephemeral key generation */
return( ecdsa_sign_restartable( grp, r, s, d, buf, blen,
f_rng, p_rng, f_rng, p_rng, NULL ) );
}
#endif /* !MBEDTLS_ECDSA_SIGN_ALT */
#if defined(MBEDTLS_ECDSA_DETERMINISTIC) #if defined(MBEDTLS_ECDSA_DETERMINISTIC)
/* /*
* Deterministic signature wrapper * Deterministic signature wrapper
*/ */
int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, static int ecdsa_sign_det_restartable( mbedtls_ecp_group *grp,
mbedtls_mpi *r, mbedtls_mpi *s,
const mbedtls_mpi *d, const unsigned char *buf, size_t blen, const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
mbedtls_md_type_t md_alg ) mbedtls_md_type_t md_alg,
int (*f_rng_blind)(void *, unsigned char *, size_t),
void *p_rng_blind,
mbedtls_ecdsa_restart_ctx *rs_ctx )
{ {
int ret; int ret;
mbedtls_hmac_drbg_context rng_ctx; mbedtls_hmac_drbg_context rng_ctx;
mbedtls_hmac_drbg_context *p_rng = &rng_ctx;
unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES];
size_t grp_len = ( grp->nbits + 7 ) / 8; size_t grp_len = ( grp->nbits + 7 ) / 8;
const mbedtls_md_info_t *md_info; const mbedtls_md_info_t *md_info;
...@@ -181,21 +429,147 @@ int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi ...@@ -181,21 +429,147 @@ int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi
mbedtls_mpi_init( &h ); mbedtls_mpi_init( &h );
mbedtls_hmac_drbg_init( &rng_ctx ); mbedtls_hmac_drbg_init( &rng_ctx );
ECDSA_RS_ENTER( det );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->det != NULL )
{
/* redirect to our context */
p_rng = &rs_ctx->det->rng_ctx;
/* jump to current step */
if( rs_ctx->det->state == ecdsa_det_sign )
goto sign;
}
#endif /* MBEDTLS_ECP_RESTARTABLE */
/* Use private key and message hash (reduced) to initialize HMAC_DRBG */ /* Use private key and message hash (reduced) to initialize HMAC_DRBG */
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) );
MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) ); MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) );
mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len ); mbedtls_hmac_drbg_seed_buf( p_rng, md_info, data, 2 * grp_len );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->det != NULL )
rs_ctx->det->state = ecdsa_det_sign;
sign:
#endif
#if defined(MBEDTLS_ECDSA_SIGN_ALT)
ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen,
mbedtls_hmac_drbg_random, &rng_ctx ); mbedtls_hmac_drbg_random, p_rng );
#else
if( f_rng_blind != NULL )
ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen,
mbedtls_hmac_drbg_random, p_rng,
f_rng_blind, p_rng_blind, rs_ctx );
else
{
mbedtls_hmac_drbg_context *p_rng_blind_det;
#if !defined(MBEDTLS_ECP_RESTARTABLE)
/*
* To avoid reusing rng_ctx and risking incorrect behavior we seed a
* second HMAC-DRBG with the same seed. We also apply a label to avoid
* reusing the bits of the ephemeral key for blinding and eliminate the
* risk that they leak this way.
*/
const char* blind_label = "BLINDING CONTEXT";
mbedtls_hmac_drbg_context rng_ctx_blind;
mbedtls_hmac_drbg_init( &rng_ctx_blind );
p_rng_blind_det = &rng_ctx_blind;
mbedtls_hmac_drbg_seed_buf( p_rng_blind_det, md_info,
data, 2 * grp_len );
ret = mbedtls_hmac_drbg_update_ret( p_rng_blind_det,
(const unsigned char*) blind_label,
strlen( blind_label ) );
if( ret != 0 )
{
mbedtls_hmac_drbg_free( &rng_ctx_blind );
goto cleanup;
}
#else
/*
* In the case of restartable computations we would either need to store
* the second RNG in the restart context too or set it up at every
* restart. The first option would penalize the correct application of
* the function and the second would defeat the purpose of the
* restartable feature.
*
* Therefore in this case we reuse the original RNG. This comes with the
* price that the resulting signature might not be a valid deterministic
* ECDSA signature with a very low probability (same magnitude as
* successfully guessing the private key). However even then it is still
* a valid ECDSA signature.
*/
p_rng_blind_det = p_rng;
#endif /* MBEDTLS_ECP_RESTARTABLE */
/*
* Since the output of the RNGs is always the same for the same key and
* message, this limits the efficiency of blinding and leaks information
* through side channels. After mbedtls_ecdsa_sign_det() is removed NULL
* won't be a valid value for f_rng_blind anymore. Therefore it should
* be checked by the caller and this branch and check can be removed.
*/
ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen,
mbedtls_hmac_drbg_random, p_rng,
mbedtls_hmac_drbg_random, p_rng_blind_det,
rs_ctx );
#if !defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_hmac_drbg_free( &rng_ctx_blind );
#endif
}
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
cleanup: cleanup:
mbedtls_hmac_drbg_free( &rng_ctx ); mbedtls_hmac_drbg_free( &rng_ctx );
mbedtls_mpi_free( &h ); mbedtls_mpi_free( &h );
ECDSA_RS_LEAVE( det );
return( ret ); return( ret );
} }
/*
* Deterministic signature wrappers
*/
int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r,
mbedtls_mpi *s, const mbedtls_mpi *d,
const unsigned char *buf, size_t blen,
mbedtls_md_type_t md_alg )
{
ECDSA_VALIDATE_RET( grp != NULL );
ECDSA_VALIDATE_RET( r != NULL );
ECDSA_VALIDATE_RET( s != NULL );
ECDSA_VALIDATE_RET( d != NULL );
ECDSA_VALIDATE_RET( buf != NULL || blen == 0 );
return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg,
NULL, NULL, NULL ) );
}
int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r,
mbedtls_mpi *s, const mbedtls_mpi *d,
const unsigned char *buf, size_t blen,
mbedtls_md_type_t md_alg,
int (*f_rng_blind)(void *, unsigned char *,
size_t),
void *p_rng_blind )
{
ECDSA_VALIDATE_RET( grp != NULL );
ECDSA_VALIDATE_RET( r != NULL );
ECDSA_VALIDATE_RET( s != NULL );
ECDSA_VALIDATE_RET( d != NULL );
ECDSA_VALIDATE_RET( buf != NULL || blen == 0 );
ECDSA_VALIDATE_RET( f_rng_blind != NULL );
return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg,
f_rng_blind, p_rng_blind, NULL ) );
}
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ #endif /* MBEDTLS_ECDSA_DETERMINISTIC */
#if !defined(MBEDTLS_ECDSA_VERIFY_ALT) #if !defined(MBEDTLS_ECDSA_VERIFY_ALT)
...@@ -203,21 +577,40 @@ cleanup: ...@@ -203,21 +577,40 @@ cleanup:
* Verify ECDSA signature of hashed message (SEC1 4.1.4) * Verify ECDSA signature of hashed message (SEC1 4.1.4)
* Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message)
*/ */
int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, static int ecdsa_verify_restartable( mbedtls_ecp_group *grp,
const unsigned char *buf, size_t blen, const unsigned char *buf, size_t blen,
const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s) const mbedtls_ecp_point *Q,
const mbedtls_mpi *r, const mbedtls_mpi *s,
mbedtls_ecdsa_restart_ctx *rs_ctx )
{ {
int ret; int ret;
mbedtls_mpi e, s_inv, u1, u2; mbedtls_mpi e, s_inv, u1, u2;
mbedtls_ecp_point R; mbedtls_ecp_point R;
mbedtls_mpi *pu1 = &u1, *pu2 = &u2;
mbedtls_ecp_point_init( &R ); mbedtls_ecp_point_init( &R );
mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv );
mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 );
/* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */
if( grp->N.p == NULL ) if( grp->N.p == NULL )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
ECDSA_RS_ENTER( ver );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->ver != NULL )
{
/* redirect to our context */
pu1 = &rs_ctx->ver->u1;
pu2 = &rs_ctx->ver->u2;
/* jump to current step */
if( rs_ctx->ver->state == ecdsa_ver_muladd )
goto muladd;
}
#endif /* MBEDTLS_ECP_RESTARTABLE */
/* /*
* Step 1: make sure r and s are in range 1..n-1 * Step 1: make sure r and s are in range 1..n-1
*/ */
...@@ -228,11 +621,6 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, ...@@ -228,11 +621,6 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
goto cleanup; goto cleanup;
} }
/*
* Additional precaution: make sure Q is valid
*/
MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) );
/* /*
* Step 3: derive MPI from hashed message * Step 3: derive MPI from hashed message
*/ */
...@@ -241,21 +629,27 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, ...@@ -241,21 +629,27 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
/* /*
* Step 4: u1 = e / s mod n, u2 = r / s mod n * Step 4: u1 = e / s mod n, u2 = r / s mod n
*/ */
ECDSA_BUDGET( MBEDTLS_ECP_OPS_CHK + MBEDTLS_ECP_OPS_INV + 2 );
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u1, &e, &s_inv ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu1, &e, &s_inv ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u1, &u1, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu1, pu1, &grp->N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu2, r, &s_inv ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu2, pu2, &grp->N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u2, r, &s_inv ) ); #if defined(MBEDTLS_ECP_RESTARTABLE)
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u2, &u2, &grp->N ) ); if( rs_ctx != NULL && rs_ctx->ver != NULL )
rs_ctx->ver->state = ecdsa_ver_muladd;
muladd:
#endif
/* /*
* Step 5: R = u1 G + u2 Q * Step 5: R = u1 G + u2 Q
*
* Since we're not using any secret data, no need to pass a RNG to
* mbedtls_ecp_mul() for countermesures.
*/ */
MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_muladd_restartable( grp,
&R, pu1, &grp->G, pu2, Q, ECDSA_RS_ECP ) );
if( mbedtls_ecp_is_zero( &R ) ) if( mbedtls_ecp_is_zero( &R ) )
{ {
...@@ -280,11 +674,32 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, ...@@ -280,11 +674,32 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
cleanup: cleanup:
mbedtls_ecp_point_free( &R ); mbedtls_ecp_point_free( &R );
mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv );
mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 );
ECDSA_RS_LEAVE( ver );
return( ret ); return( ret );
} }
#endif /* MBEDTLS_ECDSA_VERIFY_ALT */
/*
* Verify ECDSA signature of hashed message
*/
int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
const unsigned char *buf, size_t blen,
const mbedtls_ecp_point *Q,
const mbedtls_mpi *r,
const mbedtls_mpi *s)
{
ECDSA_VALIDATE_RET( grp != NULL );
ECDSA_VALIDATE_RET( Q != NULL );
ECDSA_VALIDATE_RET( r != NULL );
ECDSA_VALIDATE_RET( s != NULL );
ECDSA_VALIDATE_RET( buf != NULL || blen == 0 );
return( ecdsa_verify_restartable( grp, buf, blen, Q, r, s, NULL ) );
}
#endif /* !MBEDTLS_ECDSA_VERIFY_ALT */
/* /*
* Convert a signature (given by context) to ASN.1 * Convert a signature (given by context) to ASN.1
...@@ -313,30 +728,41 @@ static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, ...@@ -313,30 +728,41 @@ static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s,
/* /*
* Compute and write signature * Compute and write signature
*/ */
int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx,
mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hlen, const unsigned char *hash, size_t hlen,
unsigned char *sig, size_t *slen, unsigned char *sig, size_t *slen,
int (*f_rng)(void *, unsigned char *, size_t), int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng ) void *p_rng,
mbedtls_ecdsa_restart_ctx *rs_ctx )
{ {
int ret; int ret;
mbedtls_mpi r, s; mbedtls_mpi r, s;
ECDSA_VALIDATE_RET( ctx != NULL );
ECDSA_VALIDATE_RET( hash != NULL );
ECDSA_VALIDATE_RET( sig != NULL );
ECDSA_VALIDATE_RET( slen != NULL );
mbedtls_mpi_init( &r ); mbedtls_mpi_init( &r );
mbedtls_mpi_init( &s ); mbedtls_mpi_init( &s );
#if defined(MBEDTLS_ECDSA_DETERMINISTIC) #if defined(MBEDTLS_ECDSA_DETERMINISTIC)
(void) f_rng; MBEDTLS_MPI_CHK( ecdsa_sign_det_restartable( &ctx->grp, &r, &s, &ctx->d,
(void) p_rng; hash, hlen, md_alg, f_rng,
p_rng, rs_ctx ) );
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d,
hash, hlen, md_alg ) );
#else #else
(void) md_alg; (void) md_alg;
#if defined(MBEDTLS_ECDSA_SIGN_ALT)
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d, MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
hash, hlen, f_rng, p_rng ) ); hash, hlen, f_rng, p_rng ) );
#endif #else
/* Use the same RNG for both blinding and ephemeral key generation */
MBEDTLS_MPI_CHK( ecdsa_sign_restartable( &ctx->grp, &r, &s, &ctx->d,
hash, hlen, f_rng, p_rng, f_rng,
p_rng, rs_ctx ) );
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) );
...@@ -347,13 +773,35 @@ cleanup: ...@@ -347,13 +773,35 @@ cleanup:
return( ret ); return( ret );
} }
#if ! defined(MBEDTLS_DEPRECATED_REMOVED) && \ /*
* Compute and write signature
*/
int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx,
mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hlen,
unsigned char *sig, size_t *slen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
ECDSA_VALIDATE_RET( ctx != NULL );
ECDSA_VALIDATE_RET( hash != NULL );
ECDSA_VALIDATE_RET( sig != NULL );
ECDSA_VALIDATE_RET( slen != NULL );
return( mbedtls_ecdsa_write_signature_restartable(
ctx, md_alg, hash, hlen, sig, slen, f_rng, p_rng, NULL ) );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED) && \
defined(MBEDTLS_ECDSA_DETERMINISTIC) defined(MBEDTLS_ECDSA_DETERMINISTIC)
int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx,
const unsigned char *hash, size_t hlen, const unsigned char *hash, size_t hlen,
unsigned char *sig, size_t *slen, unsigned char *sig, size_t *slen,
mbedtls_md_type_t md_alg ) mbedtls_md_type_t md_alg )
{ {
ECDSA_VALIDATE_RET( ctx != NULL );
ECDSA_VALIDATE_RET( hash != NULL );
ECDSA_VALIDATE_RET( sig != NULL );
ECDSA_VALIDATE_RET( slen != NULL );
return( mbedtls_ecdsa_write_signature( ctx, md_alg, hash, hlen, sig, slen, return( mbedtls_ecdsa_write_signature( ctx, md_alg, hash, hlen, sig, slen,
NULL, NULL ) ); NULL, NULL ) );
} }
...@@ -365,12 +813,30 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, ...@@ -365,12 +813,30 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx,
int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx,
const unsigned char *hash, size_t hlen, const unsigned char *hash, size_t hlen,
const unsigned char *sig, size_t slen ) const unsigned char *sig, size_t slen )
{
ECDSA_VALIDATE_RET( ctx != NULL );
ECDSA_VALIDATE_RET( hash != NULL );
ECDSA_VALIDATE_RET( sig != NULL );
return( mbedtls_ecdsa_read_signature_restartable(
ctx, hash, hlen, sig, slen, NULL ) );
}
/*
* Restartable read and check signature
*/
int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx,
const unsigned char *hash, size_t hlen,
const unsigned char *sig, size_t slen,
mbedtls_ecdsa_restart_ctx *rs_ctx )
{ {
int ret; int ret;
unsigned char *p = (unsigned char *) sig; unsigned char *p = (unsigned char *) sig;
const unsigned char *end = sig + slen; const unsigned char *end = sig + slen;
size_t len; size_t len;
mbedtls_mpi r, s; mbedtls_mpi r, s;
ECDSA_VALIDATE_RET( ctx != NULL );
ECDSA_VALIDATE_RET( hash != NULL );
ECDSA_VALIDATE_RET( sig != NULL );
mbedtls_mpi_init( &r ); mbedtls_mpi_init( &r );
mbedtls_mpi_init( &s ); mbedtls_mpi_init( &s );
...@@ -395,10 +861,15 @@ int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, ...@@ -395,10 +861,15 @@ int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx,
ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
goto cleanup; goto cleanup;
} }
#if defined(MBEDTLS_ECDSA_VERIFY_ALT)
if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen, if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen,
&ctx->Q, &r, &s ) ) != 0 ) &ctx->Q, &r, &s ) ) != 0 )
goto cleanup; goto cleanup;
#else
if( ( ret = ecdsa_verify_restartable( &ctx->grp, hash, hlen,
&ctx->Q, &r, &s, rs_ctx ) ) != 0 )
goto cleanup;
#endif /* MBEDTLS_ECDSA_VERIFY_ALT */
/* At this point we know that the buffer starts with a valid signature. /* At this point we know that the buffer starts with a valid signature.
* Return 0 if the buffer just contains the signature, and a specific * Return 0 if the buffer just contains the signature, and a specific
...@@ -420,10 +891,18 @@ cleanup: ...@@ -420,10 +891,18 @@ cleanup:
int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
{ {
return( mbedtls_ecp_group_load( &ctx->grp, gid ) || int ret = 0;
mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ); ECDSA_VALIDATE_RET( ctx != NULL );
ECDSA_VALIDATE_RET( f_rng != NULL );
ret = mbedtls_ecp_group_load( &ctx->grp, gid );
if( ret != 0 )
return( ret );
return( mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d,
&ctx->Q, f_rng, p_rng ) );
} }
#endif /* MBEDTLS_ECDSA_GENKEY_ALT */ #endif /* !MBEDTLS_ECDSA_GENKEY_ALT */
/* /*
* Set context from an mbedtls_ecp_keypair * Set context from an mbedtls_ecp_keypair
...@@ -431,6 +910,8 @@ int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, ...@@ -431,6 +910,8 @@ int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid,
int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ) int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key )
{ {
int ret; int ret;
ECDSA_VALIDATE_RET( ctx != NULL );
ECDSA_VALIDATE_RET( key != NULL );
if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 || if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 ||
( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 || ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 ||
...@@ -447,6 +928,8 @@ int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_ke ...@@ -447,6 +928,8 @@ int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_ke
*/ */
void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ) void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx )
{ {
ECDSA_VALIDATE( ctx != NULL );
mbedtls_ecp_keypair_init( ctx ); mbedtls_ecp_keypair_init( ctx );
} }
...@@ -455,7 +938,53 @@ void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ) ...@@ -455,7 +938,53 @@ void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx )
*/ */
void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ) void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx )
{ {
if( ctx == NULL )
return;
mbedtls_ecp_keypair_free( ctx ); mbedtls_ecp_keypair_free( ctx );
} }
#if defined(MBEDTLS_ECP_RESTARTABLE)
/*
* Initialize a restart context
*/
void mbedtls_ecdsa_restart_init( mbedtls_ecdsa_restart_ctx *ctx )
{
ECDSA_VALIDATE( ctx != NULL );
mbedtls_ecp_restart_init( &ctx->ecp );
ctx->ver = NULL;
ctx->sig = NULL;
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
ctx->det = NULL;
#endif
}
/*
* Free the components of a restart context
*/
void mbedtls_ecdsa_restart_free( mbedtls_ecdsa_restart_ctx *ctx )
{
if( ctx == NULL )
return;
mbedtls_ecp_restart_free( &ctx->ecp );
ecdsa_restart_ver_free( ctx->ver );
mbedtls_free( ctx->ver );
ctx->ver = NULL;
ecdsa_restart_sig_free( ctx->sig );
mbedtls_free( ctx->sig );
ctx->sig = NULL;
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
ecdsa_restart_det_free( ctx->det );
mbedtls_free( ctx->det );
ctx->det = NULL;
#endif
}
#endif /* MBEDTLS_ECP_RESTARTABLE */
#endif /* MBEDTLS_ECDSA_C */ #endif /* MBEDTLS_ECDSA_C */
...@@ -33,11 +33,18 @@ ...@@ -33,11 +33,18 @@
#if defined(MBEDTLS_ECJPAKE_C) #if defined(MBEDTLS_ECJPAKE_C)
#include "mbedtls/ecjpake.h" #include "mbedtls/ecjpake.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
#if !defined(MBEDTLS_ECJPAKE_ALT) #if !defined(MBEDTLS_ECJPAKE_ALT)
/* Parameter validation macros based on platform_util.h */
#define ECJPAKE_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA )
#define ECJPAKE_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
/* /*
* Convert a mbedtls_ecjpake_role to identifier string * Convert a mbedtls_ecjpake_role to identifier string
*/ */
...@@ -54,8 +61,7 @@ static const char * const ecjpake_id[] = { ...@@ -54,8 +61,7 @@ static const char * const ecjpake_id[] = {
*/ */
void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx ) void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx )
{ {
if( ctx == NULL ) ECJPAKE_VALIDATE( ctx != NULL );
return;
ctx->md_info = NULL; ctx->md_info = NULL;
mbedtls_ecp_group_init( &ctx->grp ); mbedtls_ecp_group_init( &ctx->grp );
...@@ -106,6 +112,11 @@ int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, ...@@ -106,6 +112,11 @@ int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx,
{ {
int ret; int ret;
ECJPAKE_VALIDATE_RET( ctx != NULL );
ECJPAKE_VALIDATE_RET( role == MBEDTLS_ECJPAKE_CLIENT ||
role == MBEDTLS_ECJPAKE_SERVER );
ECJPAKE_VALIDATE_RET( secret != NULL || len == 0 );
ctx->role = role; ctx->role = role;
if( ( ctx->md_info = mbedtls_md_info_from_type( hash ) ) == NULL ) if( ( ctx->md_info = mbedtls_md_info_from_type( hash ) ) == NULL )
...@@ -127,6 +138,8 @@ cleanup: ...@@ -127,6 +138,8 @@ cleanup:
*/ */
int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx ) int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx )
{ {
ECJPAKE_VALIDATE_RET( ctx != NULL );
if( ctx->md_info == NULL || if( ctx->md_info == NULL ||
ctx->grp.id == MBEDTLS_ECP_DP_NONE || ctx->grp.id == MBEDTLS_ECP_DP_NONE ||
ctx->s.p == NULL ) ctx->s.p == NULL )
...@@ -213,7 +226,7 @@ static int ecjpake_hash( const mbedtls_md_info_t *md_info, ...@@ -213,7 +226,7 @@ static int ecjpake_hash( const mbedtls_md_info_t *md_info,
p += id_len; p += id_len;
/* Compute hash */ /* Compute hash */
mbedtls_md( md_info, buf, p - buf, hash ); MBEDTLS_MPI_CHK( mbedtls_md( md_info, buf, p - buf, hash ) );
/* Turn it into an integer mod n */ /* Turn it into an integer mod n */
MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash, MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash,
...@@ -504,6 +517,9 @@ int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx, ...@@ -504,6 +517,9 @@ int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx,
const unsigned char *buf, const unsigned char *buf,
size_t len ) size_t len )
{ {
ECJPAKE_VALIDATE_RET( ctx != NULL );
ECJPAKE_VALIDATE_RET( buf != NULL );
return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, ctx->point_format, return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, ctx->point_format,
&ctx->grp.G, &ctx->grp.G,
&ctx->Xp1, &ctx->Xp2, ID_PEER, &ctx->Xp1, &ctx->Xp2, ID_PEER,
...@@ -518,6 +534,11 @@ int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx, ...@@ -518,6 +534,11 @@ int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t), int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng ) void *p_rng )
{ {
ECJPAKE_VALIDATE_RET( ctx != NULL );
ECJPAKE_VALIDATE_RET( buf != NULL );
ECJPAKE_VALIDATE_RET( olen != NULL );
ECJPAKE_VALIDATE_RET( f_rng != NULL );
return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, ctx->point_format, return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, ctx->point_format,
&ctx->grp.G, &ctx->grp.G,
&ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2, &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
...@@ -560,6 +581,9 @@ int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx, ...@@ -560,6 +581,9 @@ int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx,
mbedtls_ecp_group grp; mbedtls_ecp_group grp;
mbedtls_ecp_point G; /* C: GB, S: GA */ mbedtls_ecp_point G; /* C: GB, S: GA */
ECJPAKE_VALIDATE_RET( ctx != NULL );
ECJPAKE_VALIDATE_RET( buf != NULL );
mbedtls_ecp_group_init( &grp ); mbedtls_ecp_group_init( &grp );
mbedtls_ecp_point_init( &G ); mbedtls_ecp_point_init( &G );
...@@ -652,6 +676,11 @@ int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx, ...@@ -652,6 +676,11 @@ int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx,
const unsigned char *end = buf + len; const unsigned char *end = buf + len;
size_t ec_len; size_t ec_len;
ECJPAKE_VALIDATE_RET( ctx != NULL );
ECJPAKE_VALIDATE_RET( buf != NULL );
ECJPAKE_VALIDATE_RET( olen != NULL );
ECJPAKE_VALIDATE_RET( f_rng != NULL );
mbedtls_ecp_point_init( &G ); mbedtls_ecp_point_init( &G );
mbedtls_ecp_point_init( &Xm ); mbedtls_ecp_point_init( &Xm );
mbedtls_mpi_init( &xm ); mbedtls_mpi_init( &xm );
...@@ -727,6 +756,11 @@ int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx, ...@@ -727,6 +756,11 @@ int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx,
unsigned char kx[MBEDTLS_ECP_MAX_BYTES]; unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
size_t x_bytes; size_t x_bytes;
ECJPAKE_VALIDATE_RET( ctx != NULL );
ECJPAKE_VALIDATE_RET( buf != NULL );
ECJPAKE_VALIDATE_RET( olen != NULL );
ECJPAKE_VALIDATE_RET( f_rng != NULL );
*olen = mbedtls_md_get_size( ctx->md_info ); *olen = mbedtls_md_get_size( ctx->md_info );
if( len < *olen ) if( len < *olen )
return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
...@@ -917,7 +951,7 @@ static const unsigned char ecjpake_test_pms[] = { ...@@ -917,7 +951,7 @@ static const unsigned char ecjpake_test_pms[] = {
0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
}; };
/* Load my private keys and generate the correponding public keys */ /* Load my private keys and generate the corresponding public keys */
static int ecjpake_test_load( mbedtls_ecjpake_context *ctx, static int ecjpake_test_load( mbedtls_ecjpake_context *ctx,
const unsigned char *xm1, size_t len1, const unsigned char *xm1, size_t len1,
const unsigned char *xm2, size_t len2 ) const unsigned char *xm2, size_t len2 )
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
* GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone
* FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf
* RFC 4492 for the related TLS structures and constants * RFC 4492 for the related TLS structures and constants
* RFC 7748 for the Curve448 and Curve25519 curve definitions
* *
* [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf
* *
...@@ -46,15 +47,51 @@ ...@@ -46,15 +47,51 @@
#include MBEDTLS_CONFIG_FILE #include MBEDTLS_CONFIG_FILE
#endif #endif
/**
* \brief Function level alternative implementation.
*
* The MBEDTLS_ECP_INTERNAL_ALT macro enables alternative implementations to
* replace certain functions in this module. The alternative implementations are
* typically hardware accelerators and need to activate the hardware before the
* computation starts and deactivate it after it finishes. The
* mbedtls_internal_ecp_init() and mbedtls_internal_ecp_free() functions serve
* this purpose.
*
* To preserve the correct functionality the following conditions must hold:
*
* - The alternative implementation must be activated by
* mbedtls_internal_ecp_init() before any of the replaceable functions is
* called.
* - mbedtls_internal_ecp_free() must \b only be called when the alternative
* implementation is activated.
* - mbedtls_internal_ecp_init() must \b not be called when the alternative
* implementation is activated.
* - Public functions must not return while the alternative implementation is
* activated.
* - Replaceable functions are guarded by \c MBEDTLS_ECP_XXX_ALT macros and
* before calling them an \code if( mbedtls_internal_ecp_grp_capable( grp ) )
* \endcode ensures that the alternative implementation supports the current
* group.
*/
#if defined(MBEDTLS_ECP_INTERNAL_ALT)
#endif
#if defined(MBEDTLS_ECP_C) #if defined(MBEDTLS_ECP_C)
#include "mbedtls/ecp.h" #include "mbedtls/ecp.h"
#include "mbedtls/threading.h" #include "mbedtls/threading.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
#if !defined(MBEDTLS_ECP_ALT) #if !defined(MBEDTLS_ECP_ALT)
/* Parameter validation macros based on platform_util.h */
#define ECP_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA )
#define ECP_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#if defined(MBEDTLS_PLATFORM_C) #if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h" #include "mbedtls/platform.h"
#else #else
...@@ -72,11 +109,6 @@ ...@@ -72,11 +109,6 @@
#define inline __inline #define inline __inline
#endif #endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
#if defined(MBEDTLS_SELF_TEST) #if defined(MBEDTLS_SELF_TEST)
/* /*
* Counts of point addition and doubling, and field multiplications. * Counts of point addition and doubling, and field multiplications.
...@@ -85,6 +117,233 @@ static void mbedtls_zeroize( void *v, size_t n ) { ...@@ -85,6 +117,233 @@ static void mbedtls_zeroize( void *v, size_t n ) {
static unsigned long add_count, dbl_count, mul_count; static unsigned long add_count, dbl_count, mul_count;
#endif #endif
#if defined(MBEDTLS_ECP_RESTARTABLE)
/*
* Maximum number of "basic operations" to be done in a row.
*
* Default value 0 means that ECC operations will not yield.
* Note that regardless of the value of ecp_max_ops, always at
* least one step is performed before yielding.
*
* Setting ecp_max_ops=1 can be suitable for testing purposes
* as it will interrupt computation at all possible points.
*/
static unsigned ecp_max_ops = 0;
/*
* Set ecp_max_ops
*/
void mbedtls_ecp_set_max_ops( unsigned max_ops )
{
ecp_max_ops = max_ops;
}
/*
* Check if restart is enabled
*/
int mbedtls_ecp_restart_is_enabled( void )
{
return( ecp_max_ops != 0 );
}
/*
* Restart sub-context for ecp_mul_comb()
*/
struct mbedtls_ecp_restart_mul
{
mbedtls_ecp_point R; /* current intermediate result */
size_t i; /* current index in various loops, 0 outside */
mbedtls_ecp_point *T; /* table for precomputed points */
unsigned char T_size; /* number of points in table T */
enum { /* what were we doing last time we returned? */
ecp_rsm_init = 0, /* nothing so far, dummy initial state */
ecp_rsm_pre_dbl, /* precompute 2^n multiples */
ecp_rsm_pre_norm_dbl, /* normalize precomputed 2^n multiples */
ecp_rsm_pre_add, /* precompute remaining points by adding */
ecp_rsm_pre_norm_add, /* normalize all precomputed points */
ecp_rsm_comb_core, /* ecp_mul_comb_core() */
ecp_rsm_final_norm, /* do the final normalization */
} state;
};
/*
* Init restart_mul sub-context
*/
static void ecp_restart_rsm_init( mbedtls_ecp_restart_mul_ctx *ctx )
{
mbedtls_ecp_point_init( &ctx->R );
ctx->i = 0;
ctx->T = NULL;
ctx->T_size = 0;
ctx->state = ecp_rsm_init;
}
/*
* Free the components of a restart_mul sub-context
*/
static void ecp_restart_rsm_free( mbedtls_ecp_restart_mul_ctx *ctx )
{
unsigned char i;
if( ctx == NULL )
return;
mbedtls_ecp_point_free( &ctx->R );
if( ctx->T != NULL )
{
for( i = 0; i < ctx->T_size; i++ )
mbedtls_ecp_point_free( ctx->T + i );
mbedtls_free( ctx->T );
}
ecp_restart_rsm_init( ctx );
}
/*
* Restart context for ecp_muladd()
*/
struct mbedtls_ecp_restart_muladd
{
mbedtls_ecp_point mP; /* mP value */
mbedtls_ecp_point R; /* R intermediate result */
enum { /* what should we do next? */
ecp_rsma_mul1 = 0, /* first multiplication */
ecp_rsma_mul2, /* second multiplication */
ecp_rsma_add, /* addition */
ecp_rsma_norm, /* normalization */
} state;
};
/*
* Init restart_muladd sub-context
*/
static void ecp_restart_ma_init( mbedtls_ecp_restart_muladd_ctx *ctx )
{
mbedtls_ecp_point_init( &ctx->mP );
mbedtls_ecp_point_init( &ctx->R );
ctx->state = ecp_rsma_mul1;
}
/*
* Free the components of a restart_muladd sub-context
*/
static void ecp_restart_ma_free( mbedtls_ecp_restart_muladd_ctx *ctx )
{
if( ctx == NULL )
return;
mbedtls_ecp_point_free( &ctx->mP );
mbedtls_ecp_point_free( &ctx->R );
ecp_restart_ma_init( ctx );
}
/*
* Initialize a restart context
*/
void mbedtls_ecp_restart_init( mbedtls_ecp_restart_ctx *ctx )
{
ECP_VALIDATE( ctx != NULL );
ctx->ops_done = 0;
ctx->depth = 0;
ctx->rsm = NULL;
ctx->ma = NULL;
}
/*
* Free the components of a restart context
*/
void mbedtls_ecp_restart_free( mbedtls_ecp_restart_ctx *ctx )
{
if( ctx == NULL )
return;
ecp_restart_rsm_free( ctx->rsm );
mbedtls_free( ctx->rsm );
ecp_restart_ma_free( ctx->ma );
mbedtls_free( ctx->ma );
mbedtls_ecp_restart_init( ctx );
}
/*
* Check if we can do the next step
*/
int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp,
mbedtls_ecp_restart_ctx *rs_ctx,
unsigned ops )
{
ECP_VALIDATE_RET( grp != NULL );
if( rs_ctx != NULL && ecp_max_ops != 0 )
{
/* scale depending on curve size: the chosen reference is 256-bit,
* and multiplication is quadratic. Round to the closest integer. */
if( grp->pbits >= 512 )
ops *= 4;
else if( grp->pbits >= 384 )
ops *= 2;
/* Avoid infinite loops: always allow first step.
* Because of that, however, it's not generally true
* that ops_done <= ecp_max_ops, so the check
* ops_done > ecp_max_ops below is mandatory. */
if( ( rs_ctx->ops_done != 0 ) &&
( rs_ctx->ops_done > ecp_max_ops ||
ops > ecp_max_ops - rs_ctx->ops_done ) )
{
return( MBEDTLS_ERR_ECP_IN_PROGRESS );
}
/* update running count */
rs_ctx->ops_done += ops;
}
return( 0 );
}
/* Call this when entering a function that needs its own sub-context */
#define ECP_RS_ENTER( SUB ) do { \
/* reset ops count for this call if top-level */ \
if( rs_ctx != NULL && rs_ctx->depth++ == 0 ) \
rs_ctx->ops_done = 0; \
\
/* set up our own sub-context if needed */ \
if( mbedtls_ecp_restart_is_enabled() && \
rs_ctx != NULL && rs_ctx->SUB == NULL ) \
{ \
rs_ctx->SUB = mbedtls_calloc( 1, sizeof( *rs_ctx->SUB ) ); \
if( rs_ctx->SUB == NULL ) \
return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); \
\
ecp_restart_## SUB ##_init( rs_ctx->SUB ); \
} \
} while( 0 )
/* Call this when leaving a function that needs its own sub-context */
#define ECP_RS_LEAVE( SUB ) do { \
/* clear our sub-context when not in progress (done or error) */ \
if( rs_ctx != NULL && rs_ctx->SUB != NULL && \
ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) \
{ \
ecp_restart_## SUB ##_free( rs_ctx->SUB ); \
mbedtls_free( rs_ctx->SUB ); \
rs_ctx->SUB = NULL; \
} \
\
if( rs_ctx != NULL ) \
rs_ctx->depth--; \
} while( 0 )
#else /* MBEDTLS_ECP_RESTARTABLE */
#define ECP_RS_ENTER( sub ) (void) rs_ctx;
#define ECP_RS_LEAVE( sub ) (void) rs_ctx;
#endif /* MBEDTLS_ECP_RESTARTABLE */
#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) || \ #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) || \
defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \
defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
...@@ -99,7 +358,8 @@ static unsigned long add_count, dbl_count, mul_count; ...@@ -99,7 +358,8 @@ static unsigned long add_count, dbl_count, mul_count;
#define ECP_SHORTWEIERSTRASS #define ECP_SHORTWEIERSTRASS
#endif #endif
#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) || \
defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
#define ECP_MONTGOMERY #define ECP_MONTGOMERY
#endif #endif
...@@ -245,6 +505,9 @@ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ...@@ -245,6 +505,9 @@ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name
{ {
const mbedtls_ecp_curve_info *curve_info; const mbedtls_ecp_curve_info *curve_info;
if( name == NULL )
return( NULL );
for( curve_info = mbedtls_ecp_curve_list(); for( curve_info = mbedtls_ecp_curve_list();
curve_info->grp_id != MBEDTLS_ECP_DP_NONE; curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
curve_info++ ) curve_info++ )
...@@ -275,8 +538,7 @@ static inline ecp_curve_type ecp_get_type( const mbedtls_ecp_group *grp ) ...@@ -275,8 +538,7 @@ static inline ecp_curve_type ecp_get_type( const mbedtls_ecp_group *grp )
*/ */
void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ) void mbedtls_ecp_point_init( mbedtls_ecp_point *pt )
{ {
if( pt == NULL ) ECP_VALIDATE( pt != NULL );
return;
mbedtls_mpi_init( &pt->X ); mbedtls_mpi_init( &pt->X );
mbedtls_mpi_init( &pt->Y ); mbedtls_mpi_init( &pt->Y );
...@@ -288,10 +550,23 @@ void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ) ...@@ -288,10 +550,23 @@ void mbedtls_ecp_point_init( mbedtls_ecp_point *pt )
*/ */
void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ) void mbedtls_ecp_group_init( mbedtls_ecp_group *grp )
{ {
if( grp == NULL ) ECP_VALIDATE( grp != NULL );
return;
grp->id = MBEDTLS_ECP_DP_NONE;
memset( grp, 0, sizeof( mbedtls_ecp_group ) ); mbedtls_mpi_init( &grp->P );
mbedtls_mpi_init( &grp->A );
mbedtls_mpi_init( &grp->B );
mbedtls_ecp_point_init( &grp->G );
mbedtls_mpi_init( &grp->N );
grp->pbits = 0;
grp->nbits = 0;
grp->h = 0;
grp->modp = NULL;
grp->t_pre = NULL;
grp->t_post = NULL;
grp->t_data = NULL;
grp->T = NULL;
grp->T_size = 0;
} }
/* /*
...@@ -299,8 +574,7 @@ void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ) ...@@ -299,8 +574,7 @@ void mbedtls_ecp_group_init( mbedtls_ecp_group *grp )
*/ */
void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ) void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key )
{ {
if( key == NULL ) ECP_VALIDATE( key != NULL );
return;
mbedtls_ecp_group_init( &key->grp ); mbedtls_ecp_group_init( &key->grp );
mbedtls_mpi_init( &key->d ); mbedtls_mpi_init( &key->d );
...@@ -346,7 +620,7 @@ void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ) ...@@ -346,7 +620,7 @@ void mbedtls_ecp_group_free( mbedtls_ecp_group *grp )
mbedtls_free( grp->T ); mbedtls_free( grp->T );
} }
mbedtls_zeroize( grp, sizeof( mbedtls_ecp_group ) ); mbedtls_platform_zeroize( grp, sizeof( mbedtls_ecp_group ) );
} }
/* /*
...@@ -368,6 +642,8 @@ void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ) ...@@ -368,6 +642,8 @@ void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key )
int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q )
{ {
int ret; int ret;
ECP_VALIDATE_RET( P != NULL );
ECP_VALIDATE_RET( Q != NULL );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->X, &Q->X ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->X, &Q->X ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Y, &Q->Y ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Y, &Q->Y ) );
...@@ -382,7 +658,10 @@ cleanup: ...@@ -382,7 +658,10 @@ cleanup:
*/ */
int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ) int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src )
{ {
return mbedtls_ecp_group_load( dst, src->id ); ECP_VALIDATE_RET( dst != NULL );
ECP_VALIDATE_RET( src != NULL );
return( mbedtls_ecp_group_load( dst, src->id ) );
} }
/* /*
...@@ -391,6 +670,7 @@ int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ...@@ -391,6 +670,7 @@ int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src
int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ) int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt )
{ {
int ret; int ret;
ECP_VALIDATE_RET( pt != NULL );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->X , 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->X , 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Y , 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Y , 1 ) );
...@@ -405,6 +685,8 @@ cleanup: ...@@ -405,6 +685,8 @@ cleanup:
*/ */
int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ) int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt )
{ {
ECP_VALIDATE_RET( pt != NULL );
return( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ); return( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 );
} }
...@@ -414,6 +696,9 @@ int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ) ...@@ -414,6 +696,9 @@ int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt )
int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P,
const mbedtls_ecp_point *Q ) const mbedtls_ecp_point *Q )
{ {
ECP_VALIDATE_RET( P != NULL );
ECP_VALIDATE_RET( Q != NULL );
if( mbedtls_mpi_cmp_mpi( &P->X, &Q->X ) == 0 && if( mbedtls_mpi_cmp_mpi( &P->X, &Q->X ) == 0 &&
mbedtls_mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 && mbedtls_mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 &&
mbedtls_mpi_cmp_mpi( &P->Z, &Q->Z ) == 0 ) mbedtls_mpi_cmp_mpi( &P->Z, &Q->Z ) == 0 )
...@@ -431,6 +716,9 @@ int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, ...@@ -431,6 +716,9 @@ int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix,
const char *x, const char *y ) const char *x, const char *y )
{ {
int ret; int ret;
ECP_VALIDATE_RET( P != NULL );
ECP_VALIDATE_RET( x != NULL );
ECP_VALIDATE_RET( y != NULL );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->X, radix, x ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->X, radix, x ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->Y, radix, y ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->Y, radix, y ) );
...@@ -443,16 +731,19 @@ cleanup: ...@@ -443,16 +731,19 @@ cleanup:
/* /*
* Export a point into unsigned binary data (SEC1 2.3.3) * Export a point into unsigned binary data (SEC1 2.3.3)
*/ */
int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp,
int format, size_t *olen, const mbedtls_ecp_point *P,
unsigned char *buf, size_t buflen ) int format, size_t *olen,
unsigned char *buf, size_t buflen )
{ {
int ret = 0; int ret = 0;
size_t plen; size_t plen;
ECP_VALIDATE_RET( grp != NULL );
if( format != MBEDTLS_ECP_PF_UNCOMPRESSED && ECP_VALIDATE_RET( P != NULL );
format != MBEDTLS_ECP_PF_COMPRESSED ) ECP_VALIDATE_RET( olen != NULL );
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); ECP_VALIDATE_RET( buf != NULL );
ECP_VALIDATE_RET( format == MBEDTLS_ECP_PF_UNCOMPRESSED ||
format == MBEDTLS_ECP_PF_COMPRESSED );
/* /*
* Common case: P == 0 * Common case: P == 0
...@@ -499,11 +790,15 @@ cleanup: ...@@ -499,11 +790,15 @@ cleanup:
/* /*
* Import a point from unsigned binary data (SEC1 2.3.4) * Import a point from unsigned binary data (SEC1 2.3.4)
*/ */
int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp,
const unsigned char *buf, size_t ilen ) mbedtls_ecp_point *pt,
const unsigned char *buf, size_t ilen )
{ {
int ret; int ret;
size_t plen; size_t plen;
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( pt != NULL );
ECP_VALIDATE_RET( buf != NULL );
if( ilen < 1 ) if( ilen < 1 )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
...@@ -538,11 +833,16 @@ cleanup: ...@@ -538,11 +833,16 @@ cleanup:
* opaque point <1..2^8-1>; * opaque point <1..2^8-1>;
* } ECPoint; * } ECPoint;
*/ */
int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp,
const unsigned char **buf, size_t buf_len ) mbedtls_ecp_point *pt,
const unsigned char **buf, size_t buf_len )
{ {
unsigned char data_len; unsigned char data_len;
const unsigned char *buf_start; const unsigned char *buf_start;
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( pt != NULL );
ECP_VALIDATE_RET( buf != NULL );
ECP_VALIDATE_RET( *buf != NULL );
/* /*
* We must have at least two bytes (1 for length, at least one for data) * We must have at least two bytes (1 for length, at least one for data)
...@@ -560,7 +860,7 @@ int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point ...@@ -560,7 +860,7 @@ int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point
buf_start = *buf; buf_start = *buf;
*buf += data_len; *buf += data_len;
return mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len ); return( mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len ) );
} }
/* /*
...@@ -574,6 +874,12 @@ int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp ...@@ -574,6 +874,12 @@ int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp
unsigned char *buf, size_t blen ) unsigned char *buf, size_t blen )
{ {
int ret; int ret;
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( pt != NULL );
ECP_VALIDATE_RET( olen != NULL );
ECP_VALIDATE_RET( buf != NULL );
ECP_VALIDATE_RET( format == MBEDTLS_ECP_PF_UNCOMPRESSED ||
format == MBEDTLS_ECP_PF_COMPRESSED );
/* /*
* buffer length must be at least one, for our length byte * buffer length must be at least one, for our length byte
...@@ -597,10 +903,33 @@ int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp ...@@ -597,10 +903,33 @@ int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp
/* /*
* Set a group from an ECParameters record (RFC 4492) * Set a group from an ECParameters record (RFC 4492)
*/ */
int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ) int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp,
const unsigned char **buf, size_t len )
{
int ret;
mbedtls_ecp_group_id grp_id;
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( buf != NULL );
ECP_VALIDATE_RET( *buf != NULL );
if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, len ) ) != 0 )
return( ret );
return( mbedtls_ecp_group_load( grp, grp_id ) );
}
/*
* Read a group id from an ECParameters record (RFC 4492) and convert it to
* mbedtls_ecp_group_id.
*/
int mbedtls_ecp_tls_read_group_id( mbedtls_ecp_group_id *grp,
const unsigned char **buf, size_t len )
{ {
uint16_t tls_id; uint16_t tls_id;
const mbedtls_ecp_curve_info *curve_info; const mbedtls_ecp_curve_info *curve_info;
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( buf != NULL );
ECP_VALIDATE_RET( *buf != NULL );
/* /*
* We expect at least three bytes (see below) * We expect at least three bytes (see below)
...@@ -624,7 +953,9 @@ int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **bu ...@@ -624,7 +953,9 @@ int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **bu
if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL ) if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL )
return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
return mbedtls_ecp_group_load( grp, curve_info->grp_id ); *grp = curve_info->grp_id;
return( 0 );
} }
/* /*
...@@ -634,6 +965,9 @@ int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, ...@@ -634,6 +965,9 @@ int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen,
unsigned char *buf, size_t blen ) unsigned char *buf, size_t blen )
{ {
const mbedtls_ecp_curve_info *curve_info; const mbedtls_ecp_curve_info *curve_info;
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( buf != NULL );
ECP_VALIDATE_RET( olen != NULL );
if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id( grp->id ) ) == NULL ) if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id( grp->id ) ) == NULL )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
...@@ -712,25 +1046,29 @@ cleanup: ...@@ -712,25 +1046,29 @@ cleanup:
#define INC_MUL_COUNT #define INC_MUL_COUNT
#endif #endif
#define MOD_MUL( N ) do { MBEDTLS_MPI_CHK( ecp_modp( &N, grp ) ); INC_MUL_COUNT } \ #define MOD_MUL( N ) \
while( 0 ) do \
{ \
MBEDTLS_MPI_CHK( ecp_modp( &(N), grp ) ); \
INC_MUL_COUNT \
} while( 0 )
/* /*
* Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi
* N->s < 0 is a very fast test, which fails only if N is 0 * N->s < 0 is a very fast test, which fails only if N is 0
*/ */
#define MOD_SUB( N ) \ #define MOD_SUB( N ) \
while( N.s < 0 && mbedtls_mpi_cmp_int( &N, 0 ) != 0 ) \ while( (N).s < 0 && mbedtls_mpi_cmp_int( &(N), 0 ) != 0 ) \
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &N, &N, &grp->P ) ) MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &(N), &(N), &grp->P ) )
/* /*
* Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int. * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int.
* We known P, N and the result are positive, so sub_abs is correct, and * We known P, N and the result are positive, so sub_abs is correct, and
* a bit faster. * a bit faster.
*/ */
#define MOD_ADD( N ) \ #define MOD_ADD( N ) \
while( mbedtls_mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \ while( mbedtls_mpi_cmp_mpi( &(N), &grp->P ) >= 0 ) \
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &N, &N, &grp->P ) ) MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &(N), &(N), &grp->P ) )
#if defined(ECP_SHORTWEIERSTRASS) #if defined(ECP_SHORTWEIERSTRASS)
/* /*
...@@ -754,11 +1092,10 @@ static int ecp_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p ...@@ -754,11 +1092,10 @@ static int ecp_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p
return( 0 ); return( 0 );
#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) #if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT)
if ( mbedtls_internal_ecp_grp_capable( grp ) ) if( mbedtls_internal_ecp_grp_capable( grp ) )
{ return( mbedtls_internal_ecp_normalize_jac( grp, pt ) );
return mbedtls_internal_ecp_normalize_jac( grp, pt );
}
#endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */ #endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */
mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi );
/* /*
...@@ -798,32 +1135,33 @@ cleanup: ...@@ -798,32 +1135,33 @@ cleanup:
* Cost: 1N(t) := 1I + (6t - 3)M + 1S * Cost: 1N(t) := 1I + (6t - 3)M + 1S
*/ */
static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp, static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp,
mbedtls_ecp_point *T[], size_t t_len ) mbedtls_ecp_point *T[], size_t T_size )
{ {
int ret; int ret;
size_t i; size_t i;
mbedtls_mpi *c, u, Zi, ZZi; mbedtls_mpi *c, u, Zi, ZZi;
if( t_len < 2 ) if( T_size < 2 )
return( ecp_normalize_jac( grp, *T ) ); return( ecp_normalize_jac( grp, *T ) );
#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) #if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT)
if ( mbedtls_internal_ecp_grp_capable( grp ) ) if( mbedtls_internal_ecp_grp_capable( grp ) )
{ return( mbedtls_internal_ecp_normalize_jac_many( grp, T, T_size ) );
return mbedtls_internal_ecp_normalize_jac_many(grp, T, t_len);
}
#endif #endif
if( ( c = mbedtls_calloc( t_len, sizeof( mbedtls_mpi ) ) ) == NULL ) if( ( c = mbedtls_calloc( T_size, sizeof( mbedtls_mpi ) ) ) == NULL )
return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); return( MBEDTLS_ERR_ECP_ALLOC_FAILED );
for( i = 0; i < T_size; i++ )
mbedtls_mpi_init( &c[i] );
mbedtls_mpi_init( &u ); mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); mbedtls_mpi_init( &u ); mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi );
/* /*
* c[i] = Z_0 * ... * Z_i * c[i] = Z_0 * ... * Z_i
*/ */
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &c[0], &T[0]->Z ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &c[0], &T[0]->Z ) );
for( i = 1; i < t_len; i++ ) for( i = 1; i < T_size; i++ )
{ {
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &c[i], &c[i-1], &T[i]->Z ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &c[i], &c[i-1], &T[i]->Z ) );
MOD_MUL( c[i] ); MOD_MUL( c[i] );
...@@ -832,9 +1170,9 @@ static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp, ...@@ -832,9 +1170,9 @@ static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp,
/* /*
* u = 1 / (Z_0 * ... * Z_n) mod P * u = 1 / (Z_0 * ... * Z_n) mod P
*/ */
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[t_len-1], &grp->P ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[T_size-1], &grp->P ) );
for( i = t_len - 1; ; i-- ) for( i = T_size - 1; ; i-- )
{ {
/* /*
* Zi = 1 / Z_i mod p * Zi = 1 / Z_i mod p
...@@ -874,7 +1212,7 @@ static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp, ...@@ -874,7 +1212,7 @@ static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp,
cleanup: cleanup:
mbedtls_mpi_free( &u ); mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi ); mbedtls_mpi_free( &u ); mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi );
for( i = 0; i < t_len; i++ ) for( i = 0; i < T_size; i++ )
mbedtls_mpi_free( &c[i] ); mbedtls_mpi_free( &c[i] );
mbedtls_free( c ); mbedtls_free( c );
...@@ -931,10 +1269,8 @@ static int ecp_double_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, ...@@ -931,10 +1269,8 @@ static int ecp_double_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
#endif #endif
#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) #if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT)
if ( mbedtls_internal_ecp_grp_capable( grp ) ) if( mbedtls_internal_ecp_grp_capable( grp ) )
{ return( mbedtls_internal_ecp_double_jac( grp, R, P ) );
return mbedtls_internal_ecp_double_jac( grp, R, P );
}
#endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */ #endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */
mbedtls_mpi_init( &M ); mbedtls_mpi_init( &S ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &U ); mbedtls_mpi_init( &M ); mbedtls_mpi_init( &S ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &U );
...@@ -1029,10 +1365,8 @@ static int ecp_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, ...@@ -1029,10 +1365,8 @@ static int ecp_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
#endif #endif
#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) #if defined(MBEDTLS_ECP_ADD_MIXED_ALT)
if ( mbedtls_internal_ecp_grp_capable( grp ) ) if( mbedtls_internal_ecp_grp_capable( grp ) )
{ return( mbedtls_internal_ecp_add_mixed( grp, R, P, Q ) );
return mbedtls_internal_ecp_add_mixed( grp, R, P, Q );
}
#endif /* MBEDTLS_ECP_ADD_MIXED_ALT */ #endif /* MBEDTLS_ECP_ADD_MIXED_ALT */
/* /*
...@@ -1116,10 +1450,8 @@ static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p ...@@ -1116,10 +1450,8 @@ static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p
int count = 0; int count = 0;
#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) #if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT)
if ( mbedtls_internal_ecp_grp_capable( grp ) ) if( mbedtls_internal_ecp_grp_capable( grp ) )
{ return( mbedtls_internal_ecp_randomize_jac( grp, pt, f_rng, p_rng ) );
return mbedtls_internal_ecp_randomize_jac( grp, pt, f_rng, p_rng );
}
#endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */ #endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */
p_size = ( grp->pbits + 7 ) / 8; p_size = ( grp->pbits + 7 ) / 8;
...@@ -1175,11 +1507,38 @@ cleanup: ...@@ -1175,11 +1507,38 @@ cleanup:
* modified version that provides resistance to SPA by avoiding zero * modified version that provides resistance to SPA by avoiding zero
* digits in the representation as in [3]. We modify the method further by * digits in the representation as in [3]. We modify the method further by
* requiring that all K_i be odd, which has the small cost that our * requiring that all K_i be odd, which has the small cost that our
* representation uses one more K_i, due to carries. * representation uses one more K_i, due to carries, but saves on the size of
* the precomputed table.
*
* Summary of the comb method and its modifications:
* *
* Also, for the sake of compactness, only the seven low-order bits of x[i] * - The goal is to compute m*P for some w*d-bit integer m.
* are used to represent K_i, and the msb of x[i] encodes the the sign (s_i in *
* the paper): it is set if and only if if s_i == -1; * - The basic comb method splits m into the w-bit integers
* x[0] .. x[d-1] where x[i] consists of the bits in m whose
* index has residue i modulo d, and computes m * P as
* S[x[0]] + 2 * S[x[1]] + .. + 2^(d-1) S[x[d-1]], where
* S[i_{w-1} .. i_0] := i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + i_0 P.
*
* - If it happens that, say, x[i+1]=0 (=> S[x[i+1]]=0), one can replace the sum by
* .. + 2^{i-1} S[x[i-1]] - 2^i S[x[i]] + 2^{i+1} S[x[i]] + 2^{i+2} S[x[i+2]] ..,
* thereby successively converting it into a form where all summands
* are nonzero, at the cost of negative summands. This is the basic idea of [3].
*
* - More generally, even if x[i+1] != 0, we can first transform the sum as
* .. - 2^i S[x[i]] + 2^{i+1} ( S[x[i]] + S[x[i+1]] ) + 2^{i+2} S[x[i+2]] ..,
* and then replace S[x[i]] + S[x[i+1]] = S[x[i] ^ x[i+1]] + 2 S[x[i] & x[i+1]].
* Performing and iterating this procedure for those x[i] that are even
* (keeping track of carry), we can transform the original sum into one of the form
* S[x'[0]] +- 2 S[x'[1]] +- .. +- 2^{d-1} S[x'[d-1]] + 2^d S[x'[d]]
* with all x'[i] odd. It is therefore only necessary to know S at odd indices,
* which is why we are only computing half of it in the first place in
* ecp_precompute_comb and accessing it with index abs(i) / 2 in ecp_select_comb.
*
* - For the sake of compactness, only the seven low-order bits of x[i]
* are used to represent its absolute value (K_i in the paper), and the msb
* of x[i] encodes the sign (s_i in the paper): it is set if and only if
* if s_i == -1;
* *
* Calling conventions: * Calling conventions:
* - x is an array of size d + 1 * - x is an array of size d + 1
...@@ -1188,8 +1547,8 @@ cleanup: ...@@ -1188,8 +1547,8 @@ cleanup:
* - m is the MPI, expected to be odd and such that bitlength(m) <= w * d * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d
* (the result will be incorrect if these assumptions are not satisfied) * (the result will be incorrect if these assumptions are not satisfied)
*/ */
static void ecp_comb_fixed( unsigned char x[], size_t d, static void ecp_comb_recode_core( unsigned char x[], size_t d,
unsigned char w, const mbedtls_mpi *m ) unsigned char w, const mbedtls_mpi *m )
{ {
size_t i, j; size_t i, j;
unsigned char c, cc, adjust; unsigned char c, cc, adjust;
...@@ -1219,70 +1578,178 @@ static void ecp_comb_fixed( unsigned char x[], size_t d, ...@@ -1219,70 +1578,178 @@ static void ecp_comb_fixed( unsigned char x[], size_t d,
} }
/* /*
* Precompute points for the comb method * Precompute points for the adapted comb method
* *
* If i = i_{w-1} ... i_1 is the binary representation of i, then * Assumption: T must be able to hold 2^{w - 1} elements.
* T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P
* *
* T must be able to hold 2^{w - 1} elements * Operation: If i = i_{w-1} ... i_1 is the binary representation of i,
* sets T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P.
* *
* Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1)
*
* Note: Even comb values (those where P would be omitted from the
* sum defining T[i] above) are not needed in our adaption
* the comb method. See ecp_comb_recode_core().
*
* This function currently works in four steps:
* (1) [dbl] Computation of intermediate T[i] for 2-power values of i
* (2) [norm_dbl] Normalization of coordinates of these T[i]
* (3) [add] Computation of all T[i]
* (4) [norm_add] Normalization of all T[i]
*
* Step 1 can be interrupted but not the others; together with the final
* coordinate normalization they are the largest steps done at once, depending
* on the window size. Here are operation counts for P-256:
*
* step (2) (3) (4)
* w = 5 142 165 208
* w = 4 136 77 160
* w = 3 130 33 136
* w = 2 124 11 124
*
* So if ECC operations are blocking for too long even with a low max_ops
* value, it's useful to set MBEDTLS_ECP_WINDOW_SIZE to a lower value in order
* to minimize maximum blocking time.
*/ */
static int ecp_precompute_comb( const mbedtls_ecp_group *grp, static int ecp_precompute_comb( const mbedtls_ecp_group *grp,
mbedtls_ecp_point T[], const mbedtls_ecp_point *P, mbedtls_ecp_point T[], const mbedtls_ecp_point *P,
unsigned char w, size_t d ) unsigned char w, size_t d,
mbedtls_ecp_restart_ctx *rs_ctx )
{ {
int ret; int ret;
unsigned char i, k; unsigned char i;
size_t j; size_t j = 0;
const unsigned char T_size = 1U << ( w - 1 );
mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1]; mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1];
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL )
{
if( rs_ctx->rsm->state == ecp_rsm_pre_dbl )
goto dbl;
if( rs_ctx->rsm->state == ecp_rsm_pre_norm_dbl )
goto norm_dbl;
if( rs_ctx->rsm->state == ecp_rsm_pre_add )
goto add;
if( rs_ctx->rsm->state == ecp_rsm_pre_norm_add )
goto norm_add;
}
#else
(void) rs_ctx;
#endif
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL )
{
rs_ctx->rsm->state = ecp_rsm_pre_dbl;
/* initial state for the loop */
rs_ctx->rsm->i = 0;
}
dbl:
#endif
/* /*
* Set T[0] = P and * Set T[0] = P and
* T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value) * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value)
*/ */
MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &T[0], P ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &T[0], P ) );
k = 0; #if defined(MBEDTLS_ECP_RESTARTABLE)
for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0 )
j = rs_ctx->rsm->i;
else
#endif
j = 0;
for( ; j < d * ( w - 1 ); j++ )
{ {
MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_DBL );
i = 1U << ( j / d );
cur = T + i; cur = T + i;
MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) );
for( j = 0; j < d; j++ )
MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) );
TT[k++] = cur; if( j % d == 0 )
MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) );
MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) );
} }
MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); #if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL )
rs_ctx->rsm->state = ecp_rsm_pre_norm_dbl;
norm_dbl:
#endif
/*
* Normalize current elements in T. As T has holes,
* use an auxiliary array of pointers to elements in T.
*/
j = 0;
for( i = 1; i < T_size; i <<= 1 )
TT[j++] = T + i;
MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV + 6 * j - 2 );
MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, j ) );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL )
rs_ctx->rsm->state = ecp_rsm_pre_add;
add:
#endif
/* /*
* Compute the remaining ones using the minimal number of additions * Compute the remaining ones using the minimal number of additions
* Be careful to update T[2^l] only after using it! * Be careful to update T[2^l] only after using it!
*/ */
k = 0; MBEDTLS_ECP_BUDGET( ( T_size - 1 ) * MBEDTLS_ECP_OPS_ADD );
for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 )
for( i = 1; i < T_size; i <<= 1 )
{ {
j = i; j = i;
while( j-- ) while( j-- )
{
MBEDTLS_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) ); MBEDTLS_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) );
TT[k++] = &T[i + j];
}
} }
MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); #if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL )
rs_ctx->rsm->state = ecp_rsm_pre_norm_add;
norm_add:
#endif
/*
* Normalize final elements in T. Even though there are no holes now, we
* still need the auxiliary array for homogeneity with the previous
* call. Also, skip T[0] which is already normalised, being a copy of P.
*/
for( j = 0; j + 1 < T_size; j++ )
TT[j] = T + j + 1;
MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV + 6 * j - 2 );
MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, j ) );
cleanup: cleanup:
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL &&
ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
{
if( rs_ctx->rsm->state == ecp_rsm_pre_dbl )
rs_ctx->rsm->i = j;
}
#endif
return( ret ); return( ret );
} }
/* /*
* Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ]
*
* See ecp_comb_recode_core() for background
*/ */
static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_ecp_point T[], unsigned char t_len, const mbedtls_ecp_point T[], unsigned char T_size,
unsigned char i ) unsigned char i )
{ {
int ret; int ret;
...@@ -1292,7 +1759,7 @@ static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, ...@@ -1292,7 +1759,7 @@ static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
ii = ( i & 0x7Fu ) >> 1; ii = ( i & 0x7Fu ) >> 1;
/* Read the whole table to thwart cache-based timing attacks */ /* Read the whole table to thwart cache-based timing attacks */
for( j = 0; j < t_len; j++ ) for( j = 0; j < T_size; j++ )
{ {
MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) );
...@@ -1312,10 +1779,11 @@ cleanup: ...@@ -1312,10 +1779,11 @@ cleanup:
* Cost: d A + d D + 1 R * Cost: d A + d D + 1 R
*/ */
static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_ecp_point T[], unsigned char t_len, const mbedtls_ecp_point T[], unsigned char T_size,
const unsigned char x[], size_t d, const unsigned char x[], size_t d,
int (*f_rng)(void *, unsigned char *, size_t), int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng ) void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx )
{ {
int ret; int ret;
mbedtls_ecp_point Txi; mbedtls_ecp_point Txi;
...@@ -1323,17 +1791,42 @@ static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R ...@@ -1323,17 +1791,42 @@ static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R
mbedtls_ecp_point_init( &Txi ); mbedtls_ecp_point_init( &Txi );
/* Start with a non-zero point and randomize its coordinates */ #if !defined(MBEDTLS_ECP_RESTARTABLE)
i = d; (void) rs_ctx;
MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, t_len, x[i] ) ); #endif
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) );
if( f_rng != 0 ) #if defined(MBEDTLS_ECP_RESTARTABLE)
MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) ); if( rs_ctx != NULL && rs_ctx->rsm != NULL &&
rs_ctx->rsm->state != ecp_rsm_comb_core )
{
rs_ctx->rsm->i = 0;
rs_ctx->rsm->state = ecp_rsm_comb_core;
}
/* new 'if' instead of nested for the sake of the 'else' branch */
if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0 )
{
/* restore current index (R already pointing to rs_ctx->rsm->R) */
i = rs_ctx->rsm->i;
}
else
#endif
{
/* Start with a non-zero point and randomize its coordinates */
i = d;
MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, T_size, x[i] ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) );
if( f_rng != 0 )
MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) );
}
while( i-- != 0 ) while( i != 0 )
{ {
MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_DBL + MBEDTLS_ECP_OPS_ADD );
--i;
MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) ); MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) );
MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, t_len, x[i] ) ); MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, T_size, x[i] ) );
MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) ); MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) );
} }
...@@ -1341,32 +1834,130 @@ cleanup: ...@@ -1341,32 +1834,130 @@ cleanup:
mbedtls_ecp_point_free( &Txi ); mbedtls_ecp_point_free( &Txi );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL &&
ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
{
rs_ctx->rsm->i = i;
/* no need to save R, already pointing to rs_ctx->rsm->R */
}
#endif
return( ret ); return( ret );
} }
/* /*
* Multiplication using the comb method, * Recode the scalar to get constant-time comb multiplication
* for curves in short Weierstrass form *
*/ * As the actual scalar recoding needs an odd scalar as a starting point,
static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, * this wrapper ensures that by replacing m by N - m if necessary, and
const mbedtls_mpi *m, const mbedtls_ecp_point *P, * informs the caller that the result of multiplication will be negated.
int (*f_rng)(void *, unsigned char *, size_t), *
void *p_rng ) * This works because we only support large prime order for Short Weierstrass
* curves, so N is always odd hence either m or N - m is.
*
* See ecp_comb_recode_core() for background.
*/
static int ecp_comb_recode_scalar( const mbedtls_ecp_group *grp,
const mbedtls_mpi *m,
unsigned char k[COMB_MAX_D + 1],
size_t d,
unsigned char w,
unsigned char *parity_trick )
{ {
int ret; int ret;
unsigned char w, m_is_odd, p_eq_g, pre_len, i;
size_t d;
unsigned char k[COMB_MAX_D + 1];
mbedtls_ecp_point *T;
mbedtls_mpi M, mm; mbedtls_mpi M, mm;
mbedtls_mpi_init( &M ); mbedtls_mpi_init( &M );
mbedtls_mpi_init( &mm ); mbedtls_mpi_init( &mm );
/* we need N to be odd to trnaform m in an odd number, check now */ /* N is always odd (see above), just make extra sure */
if( mbedtls_mpi_get_bit( &grp->N, 0 ) != 1 ) if( mbedtls_mpi_get_bit( &grp->N, 0 ) != 1 )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
/* do we need the parity trick? */
*parity_trick = ( mbedtls_mpi_get_bit( m, 0 ) == 0 );
/* execute parity fix in constant time */
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, *parity_trick ) );
/* actual scalar recoding */
ecp_comb_recode_core( k, d, w, &M );
cleanup:
mbedtls_mpi_free( &mm );
mbedtls_mpi_free( &M );
return( ret );
}
/*
* Perform comb multiplication (for short Weierstrass curves)
* once the auxiliary table has been pre-computed.
*
* Scalar recoding may use a parity trick that makes us compute -m * P,
* if that is the case we'll need to recover m * P at the end.
*/
static int ecp_mul_comb_after_precomp( const mbedtls_ecp_group *grp,
mbedtls_ecp_point *R,
const mbedtls_mpi *m,
const mbedtls_ecp_point *T,
unsigned char T_size,
unsigned char w,
size_t d,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx )
{
int ret;
unsigned char parity_trick;
unsigned char k[COMB_MAX_D + 1];
mbedtls_ecp_point *RR = R;
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL )
{
RR = &rs_ctx->rsm->R;
if( rs_ctx->rsm->state == ecp_rsm_final_norm )
goto final_norm;
}
#endif
MBEDTLS_MPI_CHK( ecp_comb_recode_scalar( grp, m, k, d, w,
&parity_trick ) );
MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, RR, T, T_size, k, d,
f_rng, p_rng, rs_ctx ) );
MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, RR, parity_trick ) );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL )
rs_ctx->rsm->state = ecp_rsm_final_norm;
final_norm:
#endif
MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV );
MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, RR ) );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL )
MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, RR ) );
#endif
cleanup:
return( ret );
}
/*
* Pick window size based on curve size and whether we optimize for base point
*/
static unsigned char ecp_pick_window_size( const mbedtls_ecp_group *grp,
unsigned char p_eq_g )
{
unsigned char w;
/* /*
* Minimize the number of multiplications, that is minimize * Minimize the number of multiplications, that is minimize
* 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w ) * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w )
...@@ -1379,14 +1970,8 @@ static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, ...@@ -1379,14 +1970,8 @@ static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
* Just adding one avoids upping the cost of the first mul too much, * Just adding one avoids upping the cost of the first mul too much,
* and the memory cost too. * and the memory cost too.
*/ */
#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1
p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 &&
mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 );
if( p_eq_g ) if( p_eq_g )
w++; w++;
#else
p_eq_g = 0;
#endif
/* /*
* Make sure w is within bounds. * Make sure w is within bounds.
...@@ -1397,75 +1982,140 @@ static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, ...@@ -1397,75 +1982,140 @@ static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
if( w >= grp->nbits ) if( w >= grp->nbits )
w = 2; w = 2;
/* Other sizes that depend on w */ return( w );
pre_len = 1U << ( w - 1 ); }
/*
* Multiplication using the comb method - for curves in short Weierstrass form
*
* This function is mainly responsible for administrative work:
* - managing the restart context if enabled
* - managing the table of precomputed points (passed between the below two
* functions): allocation, computation, ownership tranfer, freeing.
*
* It delegates the actual arithmetic work to:
* ecp_precompute_comb() and ecp_mul_comb_with_precomp()
*
* See comments on ecp_comb_recode_core() regarding the computation strategy.
*/
static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx )
{
int ret;
unsigned char w, p_eq_g, i;
size_t d;
unsigned char T_size, T_ok;
mbedtls_ecp_point *T;
ECP_RS_ENTER( rsm );
/* Is P the base point ? */
#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1
p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 &&
mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 );
#else
p_eq_g = 0;
#endif
/* Pick window size and deduce related sizes */
w = ecp_pick_window_size( grp, p_eq_g );
T_size = 1U << ( w - 1 );
d = ( grp->nbits + w - 1 ) / w; d = ( grp->nbits + w - 1 ) / w;
/* /* Pre-computed table: do we have it already for the base point? */
* Prepare precomputed points: if P == G we want to if( p_eq_g && grp->T != NULL )
* use grp->T if already initialized, or initialize it. {
*/ /* second pointer to the same table, will be deleted on exit */
T = p_eq_g ? grp->T : NULL; T = grp->T;
T_ok = 1;
}
else
#if defined(MBEDTLS_ECP_RESTARTABLE)
/* Pre-computed table: do we have one in progress? complete? */
if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->T != NULL )
{
/* transfer ownership of T from rsm to local function */
T = rs_ctx->rsm->T;
rs_ctx->rsm->T = NULL;
rs_ctx->rsm->T_size = 0;
if( T == NULL ) /* This effectively jumps to the call to mul_comb_after_precomp() */
T_ok = rs_ctx->rsm->state >= ecp_rsm_comb_core;
}
else
#endif
/* Allocate table if we didn't have any */
{ {
T = mbedtls_calloc( pre_len, sizeof( mbedtls_ecp_point ) ); T = mbedtls_calloc( T_size, sizeof( mbedtls_ecp_point ) );
if( T == NULL ) if( T == NULL )
{ {
ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; ret = MBEDTLS_ERR_ECP_ALLOC_FAILED;
goto cleanup; goto cleanup;
} }
MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d ) ); for( i = 0; i < T_size; i++ )
mbedtls_ecp_point_init( &T[i] );
T_ok = 0;
}
/* Compute table (or finish computing it) if not done already */
if( !T_ok )
{
MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d, rs_ctx ) );
if( p_eq_g ) if( p_eq_g )
{ {
/* almost transfer ownership of T to the group, but keep a copy of
* the pointer to use for calling the next function more easily */
grp->T = T; grp->T = T;
grp->T_size = pre_len; grp->T_size = T_size;
} }
} }
/* /* Actual comb multiplication using precomputed points */
* Make sure M is odd (M = m or M = N - m, since N is odd) MBEDTLS_MPI_CHK( ecp_mul_comb_after_precomp( grp, R, m,
* using the fact that m * P = - (N - m) * P T, T_size, w, d,
*/ f_rng, p_rng, rs_ctx ) );
m_is_odd = ( mbedtls_mpi_get_bit( m, 0 ) == 1 );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, ! m_is_odd ) );
/* cleanup:
* Go for comb multiplication, R = M * P
*/
ecp_comb_fixed( k, d, w, &M );
MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, R, T, pre_len, k, d, f_rng, p_rng ) );
/* /* does T belong to the group? */
* Now get m * P from M * P and normalize it if( T == grp->T )
*/ T = NULL;
MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, ! m_is_odd ) );
MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) );
cleanup: /* does T belong to the restart context? */
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->rsm != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS && T != NULL )
{
/* transfer ownership of T from local function to rsm */
rs_ctx->rsm->T_size = T_size;
rs_ctx->rsm->T = T;
T = NULL;
}
#endif
/* There are two cases where T is not stored in grp: /* did T belong to us? then let's destroy it! */
* - P != G if( T != NULL )
* - An intermediate operation failed before setting grp->T
* In either case, T must be freed.
*/
if( T != NULL && T != grp->T )
{ {
for( i = 0; i < pre_len; i++ ) for( i = 0; i < T_size; i++ )
mbedtls_ecp_point_free( &T[i] ); mbedtls_ecp_point_free( &T[i] );
mbedtls_free( T ); mbedtls_free( T );
} }
mbedtls_mpi_free( &M ); /* don't free R while in progress in case R == P */
mbedtls_mpi_free( &mm ); #if defined(MBEDTLS_ECP_RESTARTABLE)
if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
#endif
/* prevent caller from using invalid value */
if( ret != 0 ) if( ret != 0 )
mbedtls_ecp_point_free( R ); mbedtls_ecp_point_free( R );
ECP_RS_LEAVE( rsm );
return( ret ); return( ret );
} }
...@@ -1489,10 +2139,8 @@ static int ecp_normalize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P ...@@ -1489,10 +2139,8 @@ static int ecp_normalize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P
int ret; int ret;
#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) #if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT)
if ( mbedtls_internal_ecp_grp_capable( grp ) ) if( mbedtls_internal_ecp_grp_capable( grp ) )
{ return( mbedtls_internal_ecp_normalize_mxz( grp, P ) );
return mbedtls_internal_ecp_normalize_mxz( grp, P );
}
#endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */ #endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &P->Z, &P->Z, &grp->P ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &P->Z, &P->Z, &grp->P ) );
...@@ -1520,10 +2168,8 @@ static int ecp_randomize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P ...@@ -1520,10 +2168,8 @@ static int ecp_randomize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P
int count = 0; int count = 0;
#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) #if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT)
if ( mbedtls_internal_ecp_grp_capable( grp ) ) if( mbedtls_internal_ecp_grp_capable( grp ) )
{ return( mbedtls_internal_ecp_randomize_mxz( grp, P, f_rng, p_rng );
return mbedtls_internal_ecp_randomize_mxz( grp, P, f_rng, p_rng );
}
#endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */ #endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */
p_size = ( grp->pbits + 7 ) / 8; p_size = ( grp->pbits + 7 ) / 8;
...@@ -1575,10 +2221,8 @@ static int ecp_double_add_mxz( const mbedtls_ecp_group *grp, ...@@ -1575,10 +2221,8 @@ static int ecp_double_add_mxz( const mbedtls_ecp_group *grp,
mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB; mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB;
#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) #if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT)
if ( mbedtls_internal_ecp_grp_capable( grp ) ) if( mbedtls_internal_ecp_grp_capable( grp ) )
{ return( mbedtls_internal_ecp_double_add_mxz( grp, R, S, P, Q, d ) );
return mbedtls_internal_ecp_double_add_mxz( grp, R, S, P, Q, d );
}
#endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */ #endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */
mbedtls_mpi_init( &A ); mbedtls_mpi_init( &AA ); mbedtls_mpi_init( &B ); mbedtls_mpi_init( &A ); mbedtls_mpi_init( &AA ); mbedtls_mpi_init( &B );
...@@ -1675,54 +2319,85 @@ cleanup: ...@@ -1675,54 +2319,85 @@ cleanup:
#endif /* ECP_MONTGOMERY */ #endif /* ECP_MONTGOMERY */
/* /*
* Multiplication R = m * P * Restartable multiplication R = m * P
*/ */
int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P, const mbedtls_mpi *m, const mbedtls_ecp_point *P,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx )
{ {
int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
#if defined(MBEDTLS_ECP_INTERNAL_ALT) #if defined(MBEDTLS_ECP_INTERNAL_ALT)
char is_grp_capable = 0; char is_grp_capable = 0;
#endif #endif
ECP_VALIDATE_RET( grp != NULL );
/* Common sanity checks */ ECP_VALIDATE_RET( R != NULL );
if( mbedtls_mpi_cmp_int( &P->Z, 1 ) != 0 ) ECP_VALIDATE_RET( m != NULL );
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); ECP_VALIDATE_RET( P != NULL );
if( ( ret = mbedtls_ecp_check_privkey( grp, m ) ) != 0 || #if defined(MBEDTLS_ECP_RESTARTABLE)
( ret = mbedtls_ecp_check_pubkey( grp, P ) ) != 0 ) /* reset ops count for this call if top-level */
return( ret ); if( rs_ctx != NULL && rs_ctx->depth++ == 0 )
rs_ctx->ops_done = 0;
#endif
#if defined(MBEDTLS_ECP_INTERNAL_ALT) #if defined(MBEDTLS_ECP_INTERNAL_ALT)
if ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) if( ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) )
{
MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) );
#endif /* MBEDTLS_ECP_INTERNAL_ALT */
#if defined(MBEDTLS_ECP_RESTARTABLE)
/* skip argument check when restarting */
if( rs_ctx == NULL || rs_ctx->rsm == NULL )
#endif
{
/* check_privkey is free */
MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_CHK );
/* Common sanity checks */
MBEDTLS_MPI_CHK( mbedtls_ecp_check_privkey( grp, m ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) );
} }
#endif /* MBEDTLS_ECP_INTERNAL_ALT */ ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
#if defined(ECP_MONTGOMERY) #if defined(ECP_MONTGOMERY)
if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
ret = ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ); MBEDTLS_MPI_CHK( ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ) );
#endif #endif
#if defined(ECP_SHORTWEIERSTRASS) #if defined(ECP_SHORTWEIERSTRASS)
if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
ret = ecp_mul_comb( grp, R, m, P, f_rng, p_rng ); MBEDTLS_MPI_CHK( ecp_mul_comb( grp, R, m, P, f_rng, p_rng, rs_ctx ) );
#endif #endif
#if defined(MBEDTLS_ECP_INTERNAL_ALT)
cleanup: cleanup:
if ( is_grp_capable ) #if defined(MBEDTLS_ECP_INTERNAL_ALT)
{ if( is_grp_capable )
mbedtls_internal_ecp_free( grp ); mbedtls_internal_ecp_free( grp );
}
#endif /* MBEDTLS_ECP_INTERNAL_ALT */ #endif /* MBEDTLS_ECP_INTERNAL_ALT */
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL )
rs_ctx->depth--;
#endif
return( ret ); return( ret );
} }
/*
* Multiplication R = m * P
*/
int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
{
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( R != NULL );
ECP_VALIDATE_RET( m != NULL );
ECP_VALIDATE_RET( P != NULL );
return( mbedtls_ecp_mul_restartable( grp, R, m, P, f_rng, p_rng, NULL ) );
}
#if defined(ECP_SHORTWEIERSTRASS) #if defined(ECP_SHORTWEIERSTRASS)
/* /*
* Check that an affine point is valid as a public key, * Check that an affine point is valid as a public key,
...@@ -1780,7 +2455,8 @@ cleanup: ...@@ -1780,7 +2455,8 @@ cleanup:
static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp,
mbedtls_ecp_point *R, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_mpi *m,
const mbedtls_ecp_point *P ) const mbedtls_ecp_point *P,
mbedtls_ecp_restart_ctx *rs_ctx )
{ {
int ret; int ret;
...@@ -1796,7 +2472,8 @@ static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, ...@@ -1796,7 +2472,8 @@ static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp,
} }
else else
{ {
MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, R, m, P, NULL, NULL ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, R, m, P,
NULL, NULL, rs_ctx ) );
} }
cleanup: cleanup:
...@@ -1804,51 +2481,118 @@ cleanup: ...@@ -1804,51 +2481,118 @@ cleanup:
} }
/* /*
* Linear combination * Restartable linear combination
* NOT constant-time * NOT constant-time
*/ */
int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, int mbedtls_ecp_muladd_restartable(
mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P, const mbedtls_mpi *m, const mbedtls_ecp_point *P,
const mbedtls_mpi *n, const mbedtls_ecp_point *Q ) const mbedtls_mpi *n, const mbedtls_ecp_point *Q,
mbedtls_ecp_restart_ctx *rs_ctx )
{ {
int ret; int ret;
mbedtls_ecp_point mP; mbedtls_ecp_point mP;
mbedtls_ecp_point *pmP = &mP;
mbedtls_ecp_point *pR = R;
#if defined(MBEDTLS_ECP_INTERNAL_ALT) #if defined(MBEDTLS_ECP_INTERNAL_ALT)
char is_grp_capable = 0; char is_grp_capable = 0;
#endif #endif
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( R != NULL );
ECP_VALIDATE_RET( m != NULL );
ECP_VALIDATE_RET( P != NULL );
ECP_VALIDATE_RET( n != NULL );
ECP_VALIDATE_RET( Q != NULL );
if( ecp_get_type( grp ) != ECP_TYPE_SHORT_WEIERSTRASS ) if( ecp_get_type( grp ) != ECP_TYPE_SHORT_WEIERSTRASS )
return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
mbedtls_ecp_point_init( &mP ); mbedtls_ecp_point_init( &mP );
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, &mP, m, P ) ); ECP_RS_ENTER( ma );
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, R, n, Q ) );
#if defined(MBEDTLS_ECP_INTERNAL_ALT) #if defined(MBEDTLS_ECP_RESTARTABLE)
if ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) if( rs_ctx != NULL && rs_ctx->ma != NULL )
{ {
MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); /* redirect intermediate results to restart context */
pmP = &rs_ctx->ma->mP;
pR = &rs_ctx->ma->R;
/* jump to next operation */
if( rs_ctx->ma->state == ecp_rsma_mul2 )
goto mul2;
if( rs_ctx->ma->state == ecp_rsma_add )
goto add;
if( rs_ctx->ma->state == ecp_rsma_norm )
goto norm;
} }
#endif /* MBEDTLS_ECP_RESTARTABLE */
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, pmP, m, P, rs_ctx ) );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->ma != NULL )
rs_ctx->ma->state = ecp_rsma_mul2;
mul2:
#endif
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, pR, n, Q, rs_ctx ) );
#if defined(MBEDTLS_ECP_INTERNAL_ALT)
if( ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) )
MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) );
#endif /* MBEDTLS_ECP_INTERNAL_ALT */ #endif /* MBEDTLS_ECP_INTERNAL_ALT */
MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, &mP, R ) );
MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) );
cleanup: #if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->ma != NULL )
rs_ctx->ma->state = ecp_rsma_add;
add:
#endif
MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_ADD );
MBEDTLS_MPI_CHK( ecp_add_mixed( grp, pR, pmP, pR ) );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->ma != NULL )
rs_ctx->ma->state = ecp_rsma_norm;
norm:
#endif
MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV );
MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, pR ) );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && rs_ctx->ma != NULL )
MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, pR ) );
#endif
cleanup:
#if defined(MBEDTLS_ECP_INTERNAL_ALT) #if defined(MBEDTLS_ECP_INTERNAL_ALT)
if ( is_grp_capable ) if( is_grp_capable )
{
mbedtls_internal_ecp_free( grp ); mbedtls_internal_ecp_free( grp );
}
#endif /* MBEDTLS_ECP_INTERNAL_ALT */ #endif /* MBEDTLS_ECP_INTERNAL_ALT */
mbedtls_ecp_point_free( &mP ); mbedtls_ecp_point_free( &mP );
ECP_RS_LEAVE( ma );
return( ret ); return( ret );
} }
/*
* Linear combination
* NOT constant-time
*/
int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
const mbedtls_mpi *n, const mbedtls_ecp_point *Q )
{
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( R != NULL );
ECP_VALIDATE_RET( m != NULL );
ECP_VALIDATE_RET( P != NULL );
ECP_VALIDATE_RET( n != NULL );
ECP_VALIDATE_RET( Q != NULL );
return( mbedtls_ecp_muladd_restartable( grp, R, m, P, n, Q, NULL ) );
}
#if defined(ECP_MONTGOMERY) #if defined(ECP_MONTGOMERY)
/* /*
...@@ -1857,6 +2601,8 @@ cleanup: ...@@ -1857,6 +2601,8 @@ cleanup:
static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt )
{ {
/* [Curve25519 p. 5] Just check X is the correct number of bytes */ /* [Curve25519 p. 5] Just check X is the correct number of bytes */
/* Allow any public value, if it's too big then we'll just reduce it mod p
* (RFC 7748 sec. 5 para. 3). */
if( mbedtls_mpi_size( &pt->X ) > ( grp->nbits + 7 ) / 8 ) if( mbedtls_mpi_size( &pt->X ) > ( grp->nbits + 7 ) / 8 )
return( MBEDTLS_ERR_ECP_INVALID_KEY ); return( MBEDTLS_ERR_ECP_INVALID_KEY );
...@@ -1867,8 +2613,12 @@ static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_ ...@@ -1867,8 +2613,12 @@ static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_
/* /*
* Check that a point is valid as a public key * Check that a point is valid as a public key
*/ */
int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp,
const mbedtls_ecp_point *pt )
{ {
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( pt != NULL );
/* Must use affine coordinates */ /* Must use affine coordinates */
if( mbedtls_mpi_cmp_int( &pt->Z, 1 ) != 0 ) if( mbedtls_mpi_cmp_int( &pt->Z, 1 ) != 0 )
return( MBEDTLS_ERR_ECP_INVALID_KEY ); return( MBEDTLS_ERR_ECP_INVALID_KEY );
...@@ -1887,19 +2637,26 @@ int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_po ...@@ -1887,19 +2637,26 @@ int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_po
/* /*
* Check that an mbedtls_mpi is valid as a private key * Check that an mbedtls_mpi is valid as a private key
*/ */
int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ) int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp,
const mbedtls_mpi *d )
{ {
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( d != NULL );
#if defined(ECP_MONTGOMERY) #if defined(ECP_MONTGOMERY)
if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
{ {
/* see [Curve25519] page 5 */ /* see RFC 7748 sec. 5 para. 5 */
if( mbedtls_mpi_get_bit( d, 0 ) != 0 || if( mbedtls_mpi_get_bit( d, 0 ) != 0 ||
mbedtls_mpi_get_bit( d, 1 ) != 0 || mbedtls_mpi_get_bit( d, 1 ) != 0 ||
mbedtls_mpi_get_bit( d, 2 ) != 0 ||
mbedtls_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedtls_mpi_bitlen is one-based! */ mbedtls_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedtls_mpi_bitlen is one-based! */
return( MBEDTLS_ERR_ECP_INVALID_KEY ); return( MBEDTLS_ERR_ECP_INVALID_KEY );
else
return( 0 ); /* see [Curve25519] page 5 */
if( grp->nbits == 254 && mbedtls_mpi_get_bit( d, 2 ) != 0 )
return( MBEDTLS_ERR_ECP_INVALID_KEY );
return( 0 );
} }
#endif /* ECP_MONTGOMERY */ #endif /* ECP_MONTGOMERY */
#if defined(ECP_SHORTWEIERSTRASS) #if defined(ECP_SHORTWEIERSTRASS)
...@@ -1918,16 +2675,21 @@ int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi * ...@@ -1918,16 +2675,21 @@ int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *
} }
/* /*
* Generate a keypair with configurable base point * Generate a private key
*/ */
int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp,
const mbedtls_ecp_point *G, mbedtls_mpi *d,
mbedtls_mpi *d, mbedtls_ecp_point *Q,
int (*f_rng)(void *, unsigned char *, size_t), int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng ) void *p_rng )
{ {
int ret; int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
size_t n_size = ( grp->nbits + 7 ) / 8; size_t n_size;
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( d != NULL );
ECP_VALIDATE_RET( f_rng != NULL );
n_size = ( grp->nbits + 7 ) / 8;
#if defined(ECP_MONTGOMERY) #if defined(ECP_MONTGOMERY)
if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
...@@ -1946,13 +2708,17 @@ int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, ...@@ -1946,13 +2708,17 @@ int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp,
else else
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, grp->nbits, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, grp->nbits, 1 ) );
/* Make sure the last three bits are unset */ /* Make sure the last two bits are unset for Curve448, three bits for
Curve25519 */
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 0, 0 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 0, 0 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 1, 0 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 1, 0 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) ); if( grp->nbits == 254 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) );
}
} }
else
#endif /* ECP_MONTGOMERY */ #endif /* ECP_MONTGOMERY */
#if defined(ECP_SHORTWEIERSTRASS) #if defined(ECP_SHORTWEIERSTRASS)
if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
{ {
...@@ -1986,15 +2752,33 @@ int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, ...@@ -1986,15 +2752,33 @@ int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp,
while( mbedtls_mpi_cmp_int( d, 1 ) < 0 || while( mbedtls_mpi_cmp_int( d, 1 ) < 0 ||
mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ); mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 );
} }
else
#endif /* ECP_SHORTWEIERSTRASS */ #endif /* ECP_SHORTWEIERSTRASS */
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
cleanup: cleanup:
if( ret != 0 ) return( ret );
return( ret ); }
/*
* Generate a keypair with configurable base point
*/
int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp,
const mbedtls_ecp_point *G,
mbedtls_mpi *d, mbedtls_ecp_point *Q,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret;
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( d != NULL );
ECP_VALIDATE_RET( G != NULL );
ECP_VALIDATE_RET( Q != NULL );
ECP_VALIDATE_RET( f_rng != NULL );
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) );
return( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) ); cleanup:
return( ret );
} }
/* /*
...@@ -2005,6 +2789,11 @@ int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, ...@@ -2005,6 +2789,11 @@ int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp,
int (*f_rng)(void *, unsigned char *, size_t), int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng ) void *p_rng )
{ {
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( d != NULL );
ECP_VALIDATE_RET( Q != NULL );
ECP_VALIDATE_RET( f_rng != NULL );
return( mbedtls_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) ); return( mbedtls_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) );
} }
...@@ -2015,6 +2804,8 @@ int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, ...@@ -2015,6 +2804,8 @@ int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
{ {
int ret; int ret;
ECP_VALIDATE_RET( key != NULL );
ECP_VALIDATE_RET( f_rng != NULL );
if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 ) if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 )
return( ret ); return( ret );
...@@ -2030,6 +2821,8 @@ int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ec ...@@ -2030,6 +2821,8 @@ int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ec
int ret; int ret;
mbedtls_ecp_point Q; mbedtls_ecp_point Q;
mbedtls_ecp_group grp; mbedtls_ecp_group grp;
ECP_VALIDATE_RET( pub != NULL );
ECP_VALIDATE_RET( prv != NULL );
if( pub->grp.id == MBEDTLS_ECP_DP_NONE || if( pub->grp.id == MBEDTLS_ECP_DP_NONE ||
pub->grp.id != prv->grp.id || pub->grp.id != prv->grp.id ||
......
...@@ -28,11 +28,18 @@ ...@@ -28,11 +28,18 @@
#if defined(MBEDTLS_ECP_C) #if defined(MBEDTLS_ECP_C)
#include "mbedtls/ecp.h" #include "mbedtls/ecp.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
#if !defined(MBEDTLS_ECP_ALT) #if !defined(MBEDTLS_ECP_ALT)
/* Parameter validation macros based on platform_util.h */
#define ECP_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA )
#define ECP_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ #if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
!defined(inline) && !defined(__cplusplus) !defined(inline) && !defined(__cplusplus)
#define inline __inline #define inline __inline
...@@ -44,11 +51,11 @@ ...@@ -44,11 +51,11 @@
*/ */
#if defined(MBEDTLS_HAVE_INT32) #if defined(MBEDTLS_HAVE_INT32)
#define BYTES_TO_T_UINT_4( a, b, c, d ) \ #define BYTES_TO_T_UINT_4( a, b, c, d ) \
( (mbedtls_mpi_uint) a << 0 ) | \ ( (mbedtls_mpi_uint) (a) << 0 ) | \
( (mbedtls_mpi_uint) b << 8 ) | \ ( (mbedtls_mpi_uint) (b) << 8 ) | \
( (mbedtls_mpi_uint) c << 16 ) | \ ( (mbedtls_mpi_uint) (c) << 16 ) | \
( (mbedtls_mpi_uint) d << 24 ) ( (mbedtls_mpi_uint) (d) << 24 )
#define BYTES_TO_T_UINT_2( a, b ) \ #define BYTES_TO_T_UINT_2( a, b ) \
BYTES_TO_T_UINT_4( a, b, 0, 0 ) BYTES_TO_T_UINT_4( a, b, 0, 0 )
...@@ -60,14 +67,14 @@ ...@@ -60,14 +67,14 @@
#else /* 64-bits */ #else /* 64-bits */
#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ #define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \
( (mbedtls_mpi_uint) a << 0 ) | \ ( (mbedtls_mpi_uint) (a) << 0 ) | \
( (mbedtls_mpi_uint) b << 8 ) | \ ( (mbedtls_mpi_uint) (b) << 8 ) | \
( (mbedtls_mpi_uint) c << 16 ) | \ ( (mbedtls_mpi_uint) (c) << 16 ) | \
( (mbedtls_mpi_uint) d << 24 ) | \ ( (mbedtls_mpi_uint) (d) << 24 ) | \
( (mbedtls_mpi_uint) e << 32 ) | \ ( (mbedtls_mpi_uint) (e) << 32 ) | \
( (mbedtls_mpi_uint) f << 40 ) | \ ( (mbedtls_mpi_uint) (f) << 40 ) | \
( (mbedtls_mpi_uint) g << 48 ) | \ ( (mbedtls_mpi_uint) (g) << 48 ) | \
( (mbedtls_mpi_uint) h << 56 ) ( (mbedtls_mpi_uint) (h) << 56 )
#define BYTES_TO_T_UINT_4( a, b, c, d ) \ #define BYTES_TO_T_UINT_4( a, b, c, d ) \
BYTES_TO_T_UINT_8( a, b, c, d, 0, 0, 0, 0 ) BYTES_TO_T_UINT_8( a, b, c, d, 0, 0, 0, 0 )
...@@ -627,6 +634,9 @@ static int ecp_mod_p521( mbedtls_mpi * ); ...@@ -627,6 +634,9 @@ static int ecp_mod_p521( mbedtls_mpi * );
#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
static int ecp_mod_p255( mbedtls_mpi * ); static int ecp_mod_p255( mbedtls_mpi * );
#endif #endif
#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
static int ecp_mod_p448( mbedtls_mpi * );
#endif
#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) #if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED)
static int ecp_mod_p192k1( mbedtls_mpi * ); static int ecp_mod_p192k1( mbedtls_mpi * );
#endif #endif
...@@ -670,7 +680,12 @@ static int ecp_use_curve25519( mbedtls_ecp_group *grp ) ...@@ -670,7 +680,12 @@ static int ecp_use_curve25519( mbedtls_ecp_group *grp )
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 19 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 19 ) );
grp->pbits = mbedtls_mpi_bitlen( &grp->P ); grp->pbits = mbedtls_mpi_bitlen( &grp->P );
/* Y intentionaly not set, since we use x/z coordinates. /* N = 2^252 + 27742317777372353535851937790883648493 */
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->N, 16,
"14DEF9DEA2F79CD65812631A5CF5D3ED" ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &grp->N, 252, 1 ) );
/* Y intentionally not set, since we use x/z coordinates.
* This is used as a marker to identify Montgomery curves! */ * This is used as a marker to identify Montgomery curves! */
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 9 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 9 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) );
...@@ -687,11 +702,58 @@ cleanup: ...@@ -687,11 +702,58 @@ cleanup:
} }
#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ #endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */
#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
/*
* Specialized function for creating the Curve448 group
*/
static int ecp_use_curve448( mbedtls_ecp_group *grp )
{
mbedtls_mpi Ns;
int ret;
mbedtls_mpi_init( &Ns );
/* Actually ( A + 2 ) / 4 */
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->A, 16, "98AA" ) );
/* P = 2^448 - 2^224 - 1 */
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->P, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 224 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 224 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 1 ) );
grp->pbits = mbedtls_mpi_bitlen( &grp->P );
/* Y intentionally not set, since we use x/z coordinates.
* This is used as a marker to identify Montgomery curves! */
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 5 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) );
mbedtls_mpi_free( &grp->G.Y );
/* N = 2^446 - 13818066809895115352007386748515426880336692474882178609894547503885 */
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &grp->N, 446, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &Ns, 16,
"8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D" ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &grp->N, &grp->N, &Ns ) );
/* Actually, the required msb for private keys */
grp->nbits = 447;
cleanup:
mbedtls_mpi_free( &Ns );
if( ret != 0 )
mbedtls_ecp_group_free( grp );
return( ret );
}
#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */
/* /*
* Set a group using well-known domain parameters * Set a group using well-known domain parameters
*/ */
int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id )
{ {
ECP_VALIDATE_RET( grp != NULL );
mbedtls_ecp_group_free( grp ); mbedtls_ecp_group_free( grp );
grp->id = id; grp->id = id;
...@@ -767,6 +829,12 @@ int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) ...@@ -767,6 +829,12 @@ int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id )
return( ecp_use_curve25519( grp ) ); return( ecp_use_curve25519( grp ) );
#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ #endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */
#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
case MBEDTLS_ECP_DP_CURVE448:
grp->modp = ecp_mod_p448;
return( ecp_use_curve448( grp ) );
#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */
default: default:
mbedtls_ecp_group_free( grp ); mbedtls_ecp_group_free( grp );
return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
...@@ -822,7 +890,7 @@ static inline void carry64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *carry ) ...@@ -822,7 +890,7 @@ static inline void carry64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *carry )
} }
#define WIDTH 8 / sizeof( mbedtls_mpi_uint ) #define WIDTH 8 / sizeof( mbedtls_mpi_uint )
#define A( i ) N->p + i * WIDTH #define A( i ) N->p + (i) * WIDTH
#define ADD( i ) add64( p, A( i ), &c ) #define ADD( i ) add64( p, A( i ), &c )
#define NEXT p += WIDTH; carry64( p, &c ) #define NEXT p += WIDTH; carry64( p, &c )
#define LAST p += WIDTH; *p = c; while( ++p < end ) *p = 0 #define LAST p += WIDTH; *p = c; while( ++p < end ) *p = 0
...@@ -887,7 +955,8 @@ cleanup: ...@@ -887,7 +955,8 @@ cleanup:
#else /* 64-bit */ #else /* 64-bit */
#define MAX32 N->n * 2 #define MAX32 N->n * 2
#define A( j ) j % 2 ? (uint32_t)( N->p[j/2] >> 32 ) : (uint32_t)( N->p[j/2] ) #define A( j ) (j) % 2 ? (uint32_t)( N->p[(j)/2] >> 32 ) : \
(uint32_t)( N->p[(j)/2] )
#define STORE32 \ #define STORE32 \
if( i % 2 ) { \ if( i % 2 ) { \
N->p[i/2] &= 0x00000000FFFFFFFF; \ N->p[i/2] &= 0x00000000FFFFFFFF; \
...@@ -921,20 +990,21 @@ static inline void sub32( uint32_t *dst, uint32_t src, signed char *carry ) ...@@ -921,20 +990,21 @@ static inline void sub32( uint32_t *dst, uint32_t src, signed char *carry )
* Helpers for the main 'loop' * Helpers for the main 'loop'
* (see fix_negative for the motivation of C) * (see fix_negative for the motivation of C)
*/ */
#define INIT( b ) \ #define INIT( b ) \
int ret; \ int ret; \
signed char c = 0, cc; \ signed char c = 0, cc; \
uint32_t cur; \ uint32_t cur; \
size_t i = 0, bits = b; \ size_t i = 0, bits = (b); \
mbedtls_mpi C; \ mbedtls_mpi C; \
mbedtls_mpi_uint Cp[ b / 8 / sizeof( mbedtls_mpi_uint) + 1 ]; \ mbedtls_mpi_uint Cp[ (b) / 8 / sizeof( mbedtls_mpi_uint) + 1 ]; \
\ \
C.s = 1; \ C.s = 1; \
C.n = b / 8 / sizeof( mbedtls_mpi_uint) + 1; \ C.n = (b) / 8 / sizeof( mbedtls_mpi_uint) + 1; \
C.p = Cp; \ C.p = Cp; \
memset( Cp, 0, C.n * sizeof( mbedtls_mpi_uint ) ); \ memset( Cp, 0, C.n * sizeof( mbedtls_mpi_uint ) ); \
\ \
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, b * 2 / 8 / sizeof( mbedtls_mpi_uint ) ) ); \ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, (b) * 2 / 8 / \
sizeof( mbedtls_mpi_uint ) ) ); \
LOAD32; LOAD32;
#define NEXT \ #define NEXT \
...@@ -1176,7 +1246,7 @@ static int ecp_mod_p255( mbedtls_mpi *N ) ...@@ -1176,7 +1246,7 @@ static int ecp_mod_p255( mbedtls_mpi *N )
M.s = 1; M.s = 1;
M.n = N->n - ( P255_WIDTH - 1 ); M.n = N->n - ( P255_WIDTH - 1 );
if( M.n > P255_WIDTH + 1 ) if( M.n > P255_WIDTH + 1 )
M.n = P255_WIDTH + 1; return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
M.p = Mp; M.p = Mp;
memset( Mp, 0, sizeof Mp ); memset( Mp, 0, sizeof Mp );
memcpy( Mp, N->p + P255_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) ); memcpy( Mp, N->p + P255_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) );
...@@ -1197,6 +1267,77 @@ cleanup: ...@@ -1197,6 +1267,77 @@ cleanup:
} }
#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ #endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */
#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
/* Size of p448 in terms of mbedtls_mpi_uint */
#define P448_WIDTH ( 448 / 8 / sizeof( mbedtls_mpi_uint ) )
/* Number of limbs fully occupied by 2^224 (max), and limbs used by it (min) */
#define DIV_ROUND_UP( X, Y ) ( ( ( X ) + ( Y ) - 1 ) / ( Y ) )
#define P224_WIDTH_MIN ( 28 / sizeof( mbedtls_mpi_uint ) )
#define P224_WIDTH_MAX DIV_ROUND_UP( 28, sizeof( mbedtls_mpi_uint ) )
#define P224_UNUSED_BITS ( ( P224_WIDTH_MAX * sizeof( mbedtls_mpi_uint ) * 8 ) - 224 )
/*
* Fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1
* Write N as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and return
* A0 + A1 + B1 + (B0 + B1) * 2^224. This is different to the reference
* implementation of Curve448, which uses its own special 56-bit limbs rather
* than a generic bignum library. We could squeeze some extra speed out on
* 32-bit machines by splitting N up into 32-bit limbs and doing the
* arithmetic using the limbs directly as we do for the NIST primes above,
* but for 64-bit targets it should use half the number of operations if we do
* the reduction with 224-bit limbs, since mpi_add_mpi will then use 64-bit adds.
*/
static int ecp_mod_p448( mbedtls_mpi *N )
{
int ret;
size_t i;
mbedtls_mpi M, Q;
mbedtls_mpi_uint Mp[P448_WIDTH + 1], Qp[P448_WIDTH];
if( N->n <= P448_WIDTH )
return( 0 );
/* M = A1 */
M.s = 1;
M.n = N->n - ( P448_WIDTH );
if( M.n > P448_WIDTH )
/* Shouldn't be called with N larger than 2^896! */
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
M.p = Mp;
memset( Mp, 0, sizeof( Mp ) );
memcpy( Mp, N->p + P448_WIDTH, M.n * sizeof( mbedtls_mpi_uint ) );
/* N = A0 */
for( i = P448_WIDTH; i < N->n; i++ )
N->p[i] = 0;
/* N += A1 */
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &M ) );
/* Q = B1, N += B1 */
Q = M;
Q.p = Qp;
memcpy( Qp, Mp, sizeof( Qp ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Q, 224 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &Q ) );
/* M = (B0 + B1) * 2^224, N += M */
if( sizeof( mbedtls_mpi_uint ) > 4 )
Mp[P224_WIDTH_MIN] &= ( (mbedtls_mpi_uint)-1 ) >> ( P224_UNUSED_BITS );
for( i = P224_WIDTH_MAX; i < M.n; ++i )
Mp[i] = 0;
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &M, &M, &Q ) );
M.n = P448_WIDTH + 1; /* Make room for shifted carry bit from the addition */
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &M, 224 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &M ) );
cleanup:
return( ret );
}
#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */
#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \ #if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \
defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \
defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "mbedtls/entropy.h" #include "mbedtls/entropy.h"
#include "mbedtls/entropy_poll.h" #include "mbedtls/entropy_poll.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
...@@ -59,11 +60,6 @@ ...@@ -59,11 +60,6 @@
#include "mbedtls/havege.h" #include "mbedtls/havege.h"
#endif #endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ #define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */
void mbedtls_entropy_init( mbedtls_entropy_context *ctx ) void mbedtls_entropy_init( mbedtls_entropy_context *ctx )
...@@ -140,7 +136,7 @@ void mbedtls_entropy_free( mbedtls_entropy_context *ctx ) ...@@ -140,7 +136,7 @@ void mbedtls_entropy_free( mbedtls_entropy_context *ctx )
ctx->initial_entropy_run = 0; ctx->initial_entropy_run = 0;
#endif #endif
ctx->source_count = 0; ctx->source_count = 0;
mbedtls_zeroize( ctx->source, sizeof( ctx->source ) ); mbedtls_platform_zeroize( ctx->source, sizeof( ctx->source ) );
ctx->accumulator_started = 0; ctx->accumulator_started = 0;
} }
...@@ -232,7 +228,7 @@ static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id ...@@ -232,7 +228,7 @@ static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id
#endif #endif
cleanup: cleanup:
mbedtls_zeroize( tmp, sizeof( tmp ) ); mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
return( ret ); return( ret );
} }
...@@ -300,7 +296,7 @@ static int entropy_gather_internal( mbedtls_entropy_context *ctx ) ...@@ -300,7 +296,7 @@ static int entropy_gather_internal( mbedtls_entropy_context *ctx )
ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE; ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE;
cleanup: cleanup:
mbedtls_zeroize( buf, sizeof( buf ) ); mbedtls_platform_zeroize( buf, sizeof( buf ) );
return( ret ); return( ret );
} }
...@@ -433,7 +429,7 @@ int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ) ...@@ -433,7 +429,7 @@ int mbedtls_entropy_func( void *data, unsigned char *output, size_t len )
ret = 0; ret = 0;
exit: exit:
mbedtls_zeroize( buf, sizeof( buf ) ); mbedtls_platform_zeroize( buf, sizeof( buf ) );
#if defined(MBEDTLS_THREADING_C) #if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
...@@ -486,7 +482,7 @@ int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *p ...@@ -486,7 +482,7 @@ int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *p
ret = 0; ret = 0;
exit: exit:
mbedtls_zeroize( buf, sizeof( buf ) ); mbedtls_platform_zeroize( buf, sizeof( buf ) );
fclose( f ); fclose( f );
return( ret ); return( ret );
...@@ -516,7 +512,7 @@ int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char * ...@@ -516,7 +512,7 @@ int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *
fclose( f ); fclose( f );
mbedtls_zeroize( buf, sizeof( buf ) ); mbedtls_platform_zeroize( buf, sizeof( buf ) );
if( ret != 0 ) if( ret != 0 )
return( ret ); return( ret );
......
...@@ -19,19 +19,25 @@ ...@@ -19,19 +19,25 @@
* This file is part of mbed TLS (https://tls.mbed.org) * This file is part of mbed TLS (https://tls.mbed.org)
*/ */
#if defined(__linux__)
/* Ensure that syscall() is available even when compiling with -std=c99 */
#define _GNU_SOURCE
#endif
#if !defined(MBEDTLS_CONFIG_FILE) #if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h" #include "mbedtls/config.h"
#else #else
#include MBEDTLS_CONFIG_FILE #include MBEDTLS_CONFIG_FILE
#endif #endif
#include <string.h>
#if defined(MBEDTLS_ENTROPY_C) #if defined(MBEDTLS_ENTROPY_C)
#include "mbedtls/entropy.h" #include "mbedtls/entropy.h"
#include "mbedtls/entropy_poll.h" #include "mbedtls/entropy_poll.h"
#if defined(MBEDTLS_TIMING_C) #if defined(MBEDTLS_TIMING_C)
#include <string.h>
#include "mbedtls/timing.h" #include "mbedtls/timing.h"
#endif #endif
#if defined(MBEDTLS_HAVEGE_C) #if defined(MBEDTLS_HAVEGE_C)
...@@ -44,7 +50,8 @@ ...@@ -44,7 +50,8 @@
#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
!defined(__APPLE__) && !defined(_WIN32) !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
!defined(__HAIKU__)
#error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h" #error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h"
#endif #endif
......
...@@ -49,6 +49,10 @@ ...@@ -49,6 +49,10 @@
#include "mbedtls/arc4.h" #include "mbedtls/arc4.h"
#endif #endif
#if defined(MBEDTLS_ARIA_C)
#include "mbedtls/aria.h"
#endif
#if defined(MBEDTLS_BASE64_C) #if defined(MBEDTLS_BASE64_C)
#include "mbedtls/base64.h" #include "mbedtls/base64.h"
#endif #endif
...@@ -69,6 +73,14 @@ ...@@ -69,6 +73,14 @@
#include "mbedtls/ccm.h" #include "mbedtls/ccm.h"
#endif #endif
#if defined(MBEDTLS_CHACHA20_C)
#include "mbedtls/chacha20.h"
#endif
#if defined(MBEDTLS_CHACHAPOLY_C)
#include "mbedtls/chachapoly.h"
#endif
#if defined(MBEDTLS_CIPHER_C) #if defined(MBEDTLS_CIPHER_C)
#include "mbedtls/cipher.h" #include "mbedtls/cipher.h"
#endif #endif
...@@ -101,6 +113,10 @@ ...@@ -101,6 +113,10 @@
#include "mbedtls/gcm.h" #include "mbedtls/gcm.h"
#endif #endif
#if defined(MBEDTLS_HKDF_C)
#include "mbedtls/hkdf.h"
#endif
#if defined(MBEDTLS_HMAC_DRBG_C) #if defined(MBEDTLS_HMAC_DRBG_C)
#include "mbedtls/hmac_drbg.h" #include "mbedtls/hmac_drbg.h"
#endif #endif
...@@ -149,6 +165,14 @@ ...@@ -149,6 +165,14 @@
#include "mbedtls/pkcs5.h" #include "mbedtls/pkcs5.h"
#endif #endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#endif
#if defined(MBEDTLS_POLY1305_C)
#include "mbedtls/poly1305.h"
#endif
#if defined(MBEDTLS_RIPEMD160_C) #if defined(MBEDTLS_RIPEMD160_C)
#include "mbedtls/ripemd160.h" #include "mbedtls/ripemd160.h"
#endif #endif
...@@ -256,19 +280,21 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -256,19 +280,21 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
if( use_ret == -(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) ) if( use_ret == -(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) )
mbedtls_snprintf( buf, buflen, "ECP - The buffer is too small to write to" ); mbedtls_snprintf( buf, buflen, "ECP - The buffer is too small to write to" );
if( use_ret == -(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) ) if( use_ret == -(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) )
mbedtls_snprintf( buf, buflen, "ECP - Requested curve not available" ); mbedtls_snprintf( buf, buflen, "ECP - The requested feature is not available, for example, the requested curve is not supported" );
if( use_ret == -(MBEDTLS_ERR_ECP_VERIFY_FAILED) ) if( use_ret == -(MBEDTLS_ERR_ECP_VERIFY_FAILED) )
mbedtls_snprintf( buf, buflen, "ECP - The signature is not valid" ); mbedtls_snprintf( buf, buflen, "ECP - The signature is not valid" );
if( use_ret == -(MBEDTLS_ERR_ECP_ALLOC_FAILED) ) if( use_ret == -(MBEDTLS_ERR_ECP_ALLOC_FAILED) )
mbedtls_snprintf( buf, buflen, "ECP - Memory allocation failed" ); mbedtls_snprintf( buf, buflen, "ECP - Memory allocation failed" );
if( use_ret == -(MBEDTLS_ERR_ECP_RANDOM_FAILED) ) if( use_ret == -(MBEDTLS_ERR_ECP_RANDOM_FAILED) )
mbedtls_snprintf( buf, buflen, "ECP - Generation of random value, such as (ephemeral) key, failed" ); mbedtls_snprintf( buf, buflen, "ECP - Generation of random value, such as ephemeral key, failed" );
if( use_ret == -(MBEDTLS_ERR_ECP_INVALID_KEY) ) if( use_ret == -(MBEDTLS_ERR_ECP_INVALID_KEY) )
mbedtls_snprintf( buf, buflen, "ECP - Invalid private or public key" ); mbedtls_snprintf( buf, buflen, "ECP - Invalid private or public key" );
if( use_ret == -(MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH) ) if( use_ret == -(MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH) )
mbedtls_snprintf( buf, buflen, "ECP - The buffer contains a valid signature followed by more data" ); mbedtls_snprintf( buf, buflen, "ECP - The buffer contains a valid signature followed by more data" );
if( use_ret == -(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED) ) if( use_ret == -(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "ECP - ECP hardware accelerator failed" ); mbedtls_snprintf( buf, buflen, "ECP - The ECP hardware accelerator failed" );
if( use_ret == -(MBEDTLS_ERR_ECP_IN_PROGRESS) )
mbedtls_snprintf( buf, buflen, "ECP - Operation in progress, call again with the same parameters to continue" );
#endif /* MBEDTLS_ECP_C */ #endif /* MBEDTLS_ECP_C */
#if defined(MBEDTLS_MD_C) #if defined(MBEDTLS_MD_C)
...@@ -478,7 +504,7 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -478,7 +504,7 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
if( use_ret == -(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) ) if( use_ret == -(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) )
mbedtls_snprintf( buf, buflen, "SSL - None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages)" ); mbedtls_snprintf( buf, buflen, "SSL - None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages)" );
if( use_ret == -(MBEDTLS_ERR_SSL_WANT_READ) ) if( use_ret == -(MBEDTLS_ERR_SSL_WANT_READ) )
mbedtls_snprintf( buf, buflen, "SSL - Connection requires a read call" ); mbedtls_snprintf( buf, buflen, "SSL - No data of requested type currently available on underlying transport" );
if( use_ret == -(MBEDTLS_ERR_SSL_WANT_WRITE) ) if( use_ret == -(MBEDTLS_ERR_SSL_WANT_WRITE) )
mbedtls_snprintf( buf, buflen, "SSL - Connection requires a write call" ); mbedtls_snprintf( buf, buflen, "SSL - Connection requires a write call" );
if( use_ret == -(MBEDTLS_ERR_SSL_TIMEOUT) ) if( use_ret == -(MBEDTLS_ERR_SSL_TIMEOUT) )
...@@ -491,6 +517,14 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -491,6 +517,14 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
mbedtls_snprintf( buf, buflen, "SSL - The alert message received indicates a non-fatal error" ); mbedtls_snprintf( buf, buflen, "SSL - The alert message received indicates a non-fatal error" );
if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH) ) if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH) )
mbedtls_snprintf( buf, buflen, "SSL - Couldn't set the hash for verifying CertificateVerify" ); mbedtls_snprintf( buf, buflen, "SSL - Couldn't set the hash for verifying CertificateVerify" );
if( use_ret == -(MBEDTLS_ERR_SSL_CONTINUE_PROCESSING) )
mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that further message-processing should be done" );
if( use_ret == -(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) )
mbedtls_snprintf( buf, buflen, "SSL - The asynchronous operation is not completed yet" );
if( use_ret == -(MBEDTLS_ERR_SSL_EARLY_MESSAGE) )
mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that a message arrived early" );
if( use_ret == -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) )
mbedtls_snprintf( buf, buflen, "SSL - A cryptographic operation is in progress. Try again later" );
#endif /* MBEDTLS_SSL_TLS_C */ #endif /* MBEDTLS_SSL_TLS_C */
#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) #if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
...@@ -533,7 +567,7 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -533,7 +567,7 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
if( use_ret == -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) ) if( use_ret == -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) )
mbedtls_snprintf( buf, buflen, "X509 - Destination buffer is too small" ); mbedtls_snprintf( buf, buflen, "X509 - Destination buffer is too small" );
if( use_ret == -(MBEDTLS_ERR_X509_FATAL_ERROR) ) if( use_ret == -(MBEDTLS_ERR_X509_FATAL_ERROR) )
mbedtls_snprintf( buf, buflen, "X509 - A fatal error occured, eg the chain is too long or the vrfy callback failed" ); mbedtls_snprintf( buf, buflen, "X509 - A fatal error occurred, eg the chain is too long or the vrfy callback failed" );
#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ #endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */
// END generated code // END generated code
...@@ -570,6 +604,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -570,6 +604,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
mbedtls_snprintf( buf, buflen, "AES - Invalid key length" ); mbedtls_snprintf( buf, buflen, "AES - Invalid key length" );
if( use_ret == -(MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH) ) if( use_ret == -(MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH) )
mbedtls_snprintf( buf, buflen, "AES - Invalid data input length" ); mbedtls_snprintf( buf, buflen, "AES - Invalid data input length" );
if( use_ret == -(MBEDTLS_ERR_AES_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "AES - Invalid input data" );
if( use_ret == -(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE) ) if( use_ret == -(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE) )
mbedtls_snprintf( buf, buflen, "AES - Feature not available. For example, an unsupported AES key size" ); mbedtls_snprintf( buf, buflen, "AES - Feature not available. For example, an unsupported AES key size" );
if( use_ret == -(MBEDTLS_ERR_AES_HW_ACCEL_FAILED) ) if( use_ret == -(MBEDTLS_ERR_AES_HW_ACCEL_FAILED) )
...@@ -581,6 +617,17 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -581,6 +617,17 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
mbedtls_snprintf( buf, buflen, "ARC4 - ARC4 hardware accelerator failed" ); mbedtls_snprintf( buf, buflen, "ARC4 - ARC4 hardware accelerator failed" );
#endif /* MBEDTLS_ARC4_C */ #endif /* MBEDTLS_ARC4_C */
#if defined(MBEDTLS_ARIA_C)
if( use_ret == -(MBEDTLS_ERR_ARIA_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "ARIA - Bad input data" );
if( use_ret == -(MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH) )
mbedtls_snprintf( buf, buflen, "ARIA - Invalid data input length" );
if( use_ret == -(MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE) )
mbedtls_snprintf( buf, buflen, "ARIA - Feature not available. For example, an unsupported ARIA key size" );
if( use_ret == -(MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "ARIA - ARIA hardware accelerator failed" );
#endif /* MBEDTLS_ARIA_C */
#if defined(MBEDTLS_ASN1_PARSE_C) #if defined(MBEDTLS_ASN1_PARSE_C)
if( use_ret == -(MBEDTLS_ERR_ASN1_OUT_OF_DATA) ) if( use_ret == -(MBEDTLS_ERR_ASN1_OUT_OF_DATA) )
mbedtls_snprintf( buf, buflen, "ASN1 - Out of data when parsing an ASN1 data structure" ); mbedtls_snprintf( buf, buflen, "ASN1 - Out of data when parsing an ASN1 data structure" );
...@@ -625,17 +672,17 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -625,17 +672,17 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
#endif /* MBEDTLS_BIGNUM_C */ #endif /* MBEDTLS_BIGNUM_C */
#if defined(MBEDTLS_BLOWFISH_C) #if defined(MBEDTLS_BLOWFISH_C)
if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH) ) if( use_ret == -(MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid key length" ); mbedtls_snprintf( buf, buflen, "BLOWFISH - Bad input data" );
if( use_ret == -(MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "BLOWFISH - Blowfish hardware accelerator failed" );
if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH) ) if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH) )
mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid data input length" ); mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid data input length" );
if( use_ret == -(MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "BLOWFISH - Blowfish hardware accelerator failed" );
#endif /* MBEDTLS_BLOWFISH_C */ #endif /* MBEDTLS_BLOWFISH_C */
#if defined(MBEDTLS_CAMELLIA_C) #if defined(MBEDTLS_CAMELLIA_C)
if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH) ) if( use_ret == -(MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid key length" ); mbedtls_snprintf( buf, buflen, "CAMELLIA - Bad input data" );
if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH) ) if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH) )
mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid data input length" ); mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid data input length" );
if( use_ret == -(MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED) ) if( use_ret == -(MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED) )
...@@ -651,6 +698,22 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -651,6 +698,22 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
mbedtls_snprintf( buf, buflen, "CCM - CCM hardware accelerator failed" ); mbedtls_snprintf( buf, buflen, "CCM - CCM hardware accelerator failed" );
#endif /* MBEDTLS_CCM_C */ #endif /* MBEDTLS_CCM_C */
#if defined(MBEDTLS_CHACHA20_C)
if( use_ret == -(MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "CHACHA20 - Invalid input parameter(s)" );
if( use_ret == -(MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE) )
mbedtls_snprintf( buf, buflen, "CHACHA20 - Feature not available. For example, s part of the API is not implemented" );
if( use_ret == -(MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "CHACHA20 - Chacha20 hardware accelerator failed" );
#endif /* MBEDTLS_CHACHA20_C */
#if defined(MBEDTLS_CHACHAPOLY_C)
if( use_ret == -(MBEDTLS_ERR_CHACHAPOLY_BAD_STATE) )
mbedtls_snprintf( buf, buflen, "CHACHAPOLY - The requested operation is not permitted in the current state" );
if( use_ret == -(MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED) )
mbedtls_snprintf( buf, buflen, "CHACHAPOLY - Authenticated decryption failed: data was not authentic" );
#endif /* MBEDTLS_CHACHAPOLY_C */
#if defined(MBEDTLS_CMAC_C) #if defined(MBEDTLS_CMAC_C)
if( use_ret == -(MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED) ) if( use_ret == -(MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "CMAC - CMAC hardware accelerator failed" ); mbedtls_snprintf( buf, buflen, "CMAC - CMAC hardware accelerator failed" );
...@@ -696,6 +759,11 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -696,6 +759,11 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
mbedtls_snprintf( buf, buflen, "GCM - Bad input parameters to function" ); mbedtls_snprintf( buf, buflen, "GCM - Bad input parameters to function" );
#endif /* MBEDTLS_GCM_C */ #endif /* MBEDTLS_GCM_C */
#if defined(MBEDTLS_HKDF_C)
if( use_ret == -(MBEDTLS_ERR_HKDF_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "HKDF - Bad input parameters to function" );
#endif /* MBEDTLS_HKDF_C */
#if defined(MBEDTLS_HMAC_DRBG_C) #if defined(MBEDTLS_HMAC_DRBG_C)
if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG) ) if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG) )
mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Too many random requested in single call" ); mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Too many random requested in single call" );
...@@ -745,6 +813,10 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -745,6 +813,10 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
mbedtls_snprintf( buf, buflen, "NET - Buffer is too small to hold the data" ); mbedtls_snprintf( buf, buflen, "NET - Buffer is too small to hold the data" );
if( use_ret == -(MBEDTLS_ERR_NET_INVALID_CONTEXT) ) if( use_ret == -(MBEDTLS_ERR_NET_INVALID_CONTEXT) )
mbedtls_snprintf( buf, buflen, "NET - The context is invalid, eg because it was free()ed" ); mbedtls_snprintf( buf, buflen, "NET - The context is invalid, eg because it was free()ed" );
if( use_ret == -(MBEDTLS_ERR_NET_POLL_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Polling the net context failed" );
if( use_ret == -(MBEDTLS_ERR_NET_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "NET - Input invalid" );
#endif /* MBEDTLS_NET_C */ #endif /* MBEDTLS_NET_C */
#if defined(MBEDTLS_OID_C) #if defined(MBEDTLS_OID_C)
...@@ -759,6 +831,22 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -759,6 +831,22 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
mbedtls_snprintf( buf, buflen, "PADLOCK - Input data should be aligned" ); mbedtls_snprintf( buf, buflen, "PADLOCK - Input data should be aligned" );
#endif /* MBEDTLS_PADLOCK_C */ #endif /* MBEDTLS_PADLOCK_C */
#if defined(MBEDTLS_PLATFORM_C)
if( use_ret == -(MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "PLATFORM - Hardware accelerator failed" );
if( use_ret == -(MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED) )
mbedtls_snprintf( buf, buflen, "PLATFORM - The requested feature is not supported by the platform" );
#endif /* MBEDTLS_PLATFORM_C */
#if defined(MBEDTLS_POLY1305_C)
if( use_ret == -(MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "POLY1305 - Invalid input parameter(s)" );
if( use_ret == -(MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE) )
mbedtls_snprintf( buf, buflen, "POLY1305 - Feature not available. For example, s part of the API is not implemented" );
if( use_ret == -(MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "POLY1305 - Poly1305 hardware accelerator failed" );
#endif /* MBEDTLS_POLY1305_C */
#if defined(MBEDTLS_RIPEMD160_C) #if defined(MBEDTLS_RIPEMD160_C)
if( use_ret == -(MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED) ) if( use_ret == -(MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "RIPEMD160 - RIPEMD160 hardware accelerator failed" ); mbedtls_snprintf( buf, buflen, "RIPEMD160 - RIPEMD160 hardware accelerator failed" );
...@@ -767,16 +855,22 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) ...@@ -767,16 +855,22 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
#if defined(MBEDTLS_SHA1_C) #if defined(MBEDTLS_SHA1_C)
if( use_ret == -(MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED) ) if( use_ret == -(MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "SHA1 - SHA-1 hardware accelerator failed" ); mbedtls_snprintf( buf, buflen, "SHA1 - SHA-1 hardware accelerator failed" );
if( use_ret == -(MBEDTLS_ERR_SHA1_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "SHA1 - SHA-1 input data was malformed" );
#endif /* MBEDTLS_SHA1_C */ #endif /* MBEDTLS_SHA1_C */
#if defined(MBEDTLS_SHA256_C) #if defined(MBEDTLS_SHA256_C)
if( use_ret == -(MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED) ) if( use_ret == -(MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "SHA256 - SHA-256 hardware accelerator failed" ); mbedtls_snprintf( buf, buflen, "SHA256 - SHA-256 hardware accelerator failed" );
if( use_ret == -(MBEDTLS_ERR_SHA256_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "SHA256 - SHA-256 input data was malformed" );
#endif /* MBEDTLS_SHA256_C */ #endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C) #if defined(MBEDTLS_SHA512_C)
if( use_ret == -(MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED) ) if( use_ret == -(MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "SHA512 - SHA-512 hardware accelerator failed" ); mbedtls_snprintf( buf, buflen, "SHA512 - SHA-512 hardware accelerator failed" );
if( use_ret == -(MBEDTLS_ERR_SHA512_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "SHA512 - SHA-512 input data was malformed" );
#endif /* MBEDTLS_SHA512_C */ #endif /* MBEDTLS_SHA512_C */
#if defined(MBEDTLS_THREADING_C) #if defined(MBEDTLS_THREADING_C)
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#if defined(MBEDTLS_GCM_C) #if defined(MBEDTLS_GCM_C)
#include "mbedtls/gcm.h" #include "mbedtls/gcm.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
...@@ -47,9 +48,8 @@ ...@@ -47,9 +48,8 @@
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
#include "mbedtls/aes.h" #include "mbedtls/aes.h"
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h" #include "mbedtls/platform.h"
#else #if !defined(MBEDTLS_PLATFORM_C)
#include <stdio.h> #include <stdio.h>
#define mbedtls_printf printf #define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */ #endif /* MBEDTLS_PLATFORM_C */
...@@ -57,6 +57,12 @@ ...@@ -57,6 +57,12 @@
#if !defined(MBEDTLS_GCM_ALT) #if !defined(MBEDTLS_GCM_ALT)
/* Parameter validation macros */
#define GCM_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_GCM_BAD_INPUT )
#define GCM_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
/* /*
* 32-bit integer manipulation macros (big endian) * 32-bit integer manipulation macros (big endian)
*/ */
...@@ -80,16 +86,12 @@ ...@@ -80,16 +86,12 @@
} }
#endif #endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/* /*
* Initialize a context * Initialize a context
*/ */
void mbedtls_gcm_init( mbedtls_gcm_context *ctx ) void mbedtls_gcm_init( mbedtls_gcm_context *ctx )
{ {
GCM_VALIDATE( ctx != NULL );
memset( ctx, 0, sizeof( mbedtls_gcm_context ) ); memset( ctx, 0, sizeof( mbedtls_gcm_context ) );
} }
...@@ -169,6 +171,10 @@ int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, ...@@ -169,6 +171,10 @@ int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx,
int ret; int ret;
const mbedtls_cipher_info_t *cipher_info; const mbedtls_cipher_info_t *cipher_info;
GCM_VALIDATE_RET( ctx != NULL );
GCM_VALIDATE_RET( key != NULL );
GCM_VALIDATE_RET( keybits == 128 || keybits == 192 || keybits == 256 );
cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB ); cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB );
if( cipher_info == NULL ) if( cipher_info == NULL )
return( MBEDTLS_ERR_GCM_BAD_INPUT ); return( MBEDTLS_ERR_GCM_BAD_INPUT );
...@@ -279,6 +285,10 @@ int mbedtls_gcm_starts( mbedtls_gcm_context *ctx, ...@@ -279,6 +285,10 @@ int mbedtls_gcm_starts( mbedtls_gcm_context *ctx,
const unsigned char *p; const unsigned char *p;
size_t use_len, olen = 0; size_t use_len, olen = 0;
GCM_VALIDATE_RET( ctx != NULL );
GCM_VALIDATE_RET( iv != NULL );
GCM_VALIDATE_RET( add_len == 0 || add != NULL );
/* IV and AD are limited to 2^64 bits, so 2^61 bytes */ /* IV and AD are limited to 2^64 bits, so 2^61 bytes */
/* IV is not allowed to be zero length */ /* IV is not allowed to be zero length */
if( iv_len == 0 || if( iv_len == 0 ||
...@@ -361,6 +371,10 @@ int mbedtls_gcm_update( mbedtls_gcm_context *ctx, ...@@ -361,6 +371,10 @@ int mbedtls_gcm_update( mbedtls_gcm_context *ctx,
unsigned char *out_p = output; unsigned char *out_p = output;
size_t use_len, olen = 0; size_t use_len, olen = 0;
GCM_VALIDATE_RET( ctx != NULL );
GCM_VALIDATE_RET( length == 0 || input != NULL );
GCM_VALIDATE_RET( length == 0 || output != NULL );
if( output > input && (size_t) ( output - input ) < length ) if( output > input && (size_t) ( output - input ) < length )
return( MBEDTLS_ERR_GCM_BAD_INPUT ); return( MBEDTLS_ERR_GCM_BAD_INPUT );
...@@ -414,8 +428,14 @@ int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, ...@@ -414,8 +428,14 @@ int mbedtls_gcm_finish( mbedtls_gcm_context *ctx,
{ {
unsigned char work_buf[16]; unsigned char work_buf[16];
size_t i; size_t i;
uint64_t orig_len = ctx->len * 8; uint64_t orig_len;
uint64_t orig_add_len = ctx->add_len * 8; uint64_t orig_add_len;
GCM_VALIDATE_RET( ctx != NULL );
GCM_VALIDATE_RET( tag != NULL );
orig_len = ctx->len * 8;
orig_add_len = ctx->add_len * 8;
if( tag_len > 16 || tag_len < 4 ) if( tag_len > 16 || tag_len < 4 )
return( MBEDTLS_ERR_GCM_BAD_INPUT ); return( MBEDTLS_ERR_GCM_BAD_INPUT );
...@@ -457,6 +477,13 @@ int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, ...@@ -457,6 +477,13 @@ int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx,
{ {
int ret; int ret;
GCM_VALIDATE_RET( ctx != NULL );
GCM_VALIDATE_RET( iv != NULL );
GCM_VALIDATE_RET( add_len == 0 || add != NULL );
GCM_VALIDATE_RET( length == 0 || input != NULL );
GCM_VALIDATE_RET( length == 0 || output != NULL );
GCM_VALIDATE_RET( tag != NULL );
if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 ) if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 )
return( ret ); return( ret );
...@@ -485,6 +512,13 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, ...@@ -485,6 +512,13 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx,
size_t i; size_t i;
int diff; int diff;
GCM_VALIDATE_RET( ctx != NULL );
GCM_VALIDATE_RET( iv != NULL );
GCM_VALIDATE_RET( add_len == 0 || add != NULL );
GCM_VALIDATE_RET( tag != NULL );
GCM_VALIDATE_RET( length == 0 || input != NULL );
GCM_VALIDATE_RET( length == 0 || output != NULL );
if( ( ret = mbedtls_gcm_crypt_and_tag( ctx, MBEDTLS_GCM_DECRYPT, length, if( ( ret = mbedtls_gcm_crypt_and_tag( ctx, MBEDTLS_GCM_DECRYPT, length,
iv, iv_len, add, add_len, iv, iv_len, add, add_len,
input, output, tag_len, check_tag ) ) != 0 ) input, output, tag_len, check_tag ) ) != 0 )
...@@ -498,7 +532,7 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, ...@@ -498,7 +532,7 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx,
if( diff != 0 ) if( diff != 0 )
{ {
mbedtls_zeroize( output, length ); mbedtls_platform_zeroize( output, length );
return( MBEDTLS_ERR_GCM_AUTH_FAILED ); return( MBEDTLS_ERR_GCM_AUTH_FAILED );
} }
...@@ -507,8 +541,10 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, ...@@ -507,8 +541,10 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx,
void mbedtls_gcm_free( mbedtls_gcm_context *ctx ) void mbedtls_gcm_free( mbedtls_gcm_context *ctx )
{ {
if( ctx == NULL )
return;
mbedtls_cipher_free( &ctx->cipher_ctx ); mbedtls_cipher_free( &ctx->cipher_ctx );
mbedtls_zeroize( ctx, sizeof( mbedtls_gcm_context ) ); mbedtls_platform_zeroize( ctx, sizeof( mbedtls_gcm_context ) );
} }
#endif /* !MBEDTLS_GCM_ALT */ #endif /* !MBEDTLS_GCM_ALT */
...@@ -768,7 +804,7 @@ int mbedtls_gcm_self_test( int verbose ) ...@@ -768,7 +804,7 @@ int mbedtls_gcm_self_test( int verbose )
* there is an alternative underlying implementation i.e. when * there is an alternative underlying implementation i.e. when
* MBEDTLS_AES_ALT is defined. * MBEDTLS_AES_ALT is defined.
*/ */
if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && key_len == 192 ) if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && key_len == 192 )
{ {
mbedtls_printf( "skipped\n" ); mbedtls_printf( "skipped\n" );
break; break;
......
...@@ -36,13 +36,20 @@ ...@@ -36,13 +36,20 @@
#include "mbedtls/havege.h" #include "mbedtls/havege.h"
#include "mbedtls/timing.h" #include "mbedtls/timing.h"
#include "mbedtls/platform_util.h"
#include <limits.h>
#include <string.h> #include <string.h>
/* Implementation that should never be optimized out by the compiler */ /* If int isn't capable of storing 2^32 distinct values, the code of this
static void mbedtls_zeroize( void *v, size_t n ) { * module may cause a processor trap or a miscalculation. If int is more
volatile unsigned char *p = v; while( n-- ) *p++ = 0; * than 32 bits, the code may not calculate the intended values. */
} #if INT_MIN + 1 != -0x7fffffff
#error "The HAVEGE module requires int to be exactly 32 bits, with INT_MIN = -2^31."
#endif
#if UINT_MAX != 0xffffffff
#error "The HAVEGE module requires unsigned to be exactly 32 bits."
#endif
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* On average, one iteration accesses two 8-word blocks in the havege WALK * On average, one iteration accesses two 8-word blocks in the havege WALK
...@@ -58,7 +65,7 @@ static void mbedtls_zeroize( void *v, size_t n ) { ...@@ -58,7 +65,7 @@ static void mbedtls_zeroize( void *v, size_t n ) {
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
*/ */
#define SWAP(X,Y) { int *T = X; X = Y; Y = T; } #define SWAP(X,Y) { unsigned *T = (X); (X) = (Y); (Y) = T; }
#define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; #define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1;
#define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; #define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1;
...@@ -81,7 +88,7 @@ static void mbedtls_zeroize( void *v, size_t n ) { ...@@ -81,7 +88,7 @@ static void mbedtls_zeroize( void *v, size_t n ) {
PTX = (PT1 >> 18) & 7; \ PTX = (PT1 >> 18) & 7; \
PT1 &= 0x1FFF; \ PT1 &= 0x1FFF; \
PT2 &= 0x1FFF; \ PT2 &= 0x1FFF; \
CLK = (int) mbedtls_timing_hardclock(); \ CLK = (unsigned) mbedtls_timing_hardclock(); \
\ \
i = 0; \ i = 0; \
A = &WALK[PT1 ]; RES[i++] ^= *A; \ A = &WALK[PT1 ]; RES[i++] ^= *A; \
...@@ -104,7 +111,7 @@ static void mbedtls_zeroize( void *v, size_t n ) { ...@@ -104,7 +111,7 @@ static void mbedtls_zeroize( void *v, size_t n ) {
\ \
IN = (*A >> (5)) ^ (*A << (27)) ^ CLK; \ IN = (*A >> (5)) ^ (*A << (27)) ^ CLK; \
*A = (*B >> (6)) ^ (*B << (26)) ^ CLK; \ *A = (*B >> (6)) ^ (*B << (26)) ^ CLK; \
*B = IN; CLK = (int) mbedtls_timing_hardclock(); \ *B = IN; CLK = (unsigned) mbedtls_timing_hardclock(); \
*C = (*C >> (7)) ^ (*C << (25)) ^ CLK; \ *C = (*C >> (7)) ^ (*C << (25)) ^ CLK; \
*D = (*D >> (8)) ^ (*D << (24)) ^ CLK; \ *D = (*D >> (8)) ^ (*D << (24)) ^ CLK; \
\ \
...@@ -155,19 +162,20 @@ static void mbedtls_zeroize( void *v, size_t n ) { ...@@ -155,19 +162,20 @@ static void mbedtls_zeroize( void *v, size_t n ) {
PT1 ^= (PT2 ^ 0x10) & 0x10; \ PT1 ^= (PT2 ^ 0x10) & 0x10; \
\ \
for( n++, i = 0; i < 16; i++ ) \ for( n++, i = 0; i < 16; i++ ) \
hs->pool[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i]; POOL[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i];
/* /*
* Entropy gathering function * Entropy gathering function
*/ */
static void havege_fill( mbedtls_havege_state *hs ) static void havege_fill( mbedtls_havege_state *hs )
{ {
int i, n = 0; unsigned i, n = 0;
int U1, U2, *A, *B, *C, *D; unsigned U1, U2, *A, *B, *C, *D;
int PT1, PT2, *WALK, RES[16]; unsigned PT1, PT2, *WALK, *POOL, RES[16];
int PTX, PTY, CLK, PTEST, IN; unsigned PTX, PTY, CLK, PTEST, IN;
WALK = hs->WALK; WALK = (unsigned *) hs->WALK;
POOL = (unsigned *) hs->pool;
PT1 = hs->PT1; PT1 = hs->PT1;
PT2 = hs->PT2; PT2 = hs->PT2;
...@@ -208,7 +216,7 @@ void mbedtls_havege_free( mbedtls_havege_state *hs ) ...@@ -208,7 +216,7 @@ void mbedtls_havege_free( mbedtls_havege_state *hs )
if( hs == NULL ) if( hs == NULL )
return; return;
mbedtls_zeroize( hs, sizeof( mbedtls_havege_state ) ); mbedtls_platform_zeroize( hs, sizeof( mbedtls_havege_state ) );
} }
/* /*
......
/*
* HKDF implementation -- RFC 5869
*
* Copyright (C) 2016-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_HKDF_C)
#include <string.h>
#include "mbedtls/hkdf.h"
#include "mbedtls/platform_util.h"
int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt,
size_t salt_len, const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
unsigned char *okm, size_t okm_len )
{
int ret;
unsigned char prk[MBEDTLS_MD_MAX_SIZE];
ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, prk );
if( ret == 0 )
{
ret = mbedtls_hkdf_expand( md, prk, mbedtls_md_get_size( md ),
info, info_len, okm, okm_len );
}
mbedtls_platform_zeroize( prk, sizeof( prk ) );
return( ret );
}
int mbedtls_hkdf_extract( const mbedtls_md_info_t *md,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
unsigned char *prk )
{
unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' };
if( salt == NULL )
{
size_t hash_len;
if( salt_len != 0 )
{
return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
}
hash_len = mbedtls_md_get_size( md );
if( hash_len == 0 )
{
return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
}
salt = null_salt;
salt_len = hash_len;
}
return( mbedtls_md_hmac( md, salt, salt_len, ikm, ikm_len, prk ) );
}
int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk,
size_t prk_len, const unsigned char *info,
size_t info_len, unsigned char *okm, size_t okm_len )
{
size_t hash_len;
size_t where = 0;
size_t n;
size_t t_len = 0;
size_t i;
int ret = 0;
mbedtls_md_context_t ctx;
unsigned char t[MBEDTLS_MD_MAX_SIZE];
if( okm == NULL )
{
return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
}
hash_len = mbedtls_md_get_size( md );
if( prk_len < hash_len || hash_len == 0 )
{
return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
}
if( info == NULL )
{
info = (const unsigned char *) "";
info_len = 0;
}
n = okm_len / hash_len;
if( (okm_len % hash_len) != 0 )
{
n++;
}
/*
* Per RFC 5869 Section 2.3, okm_len must not exceed
* 255 times the hash length
*/
if( n > 255 )
{
return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
}
mbedtls_md_init( &ctx );
if( (ret = mbedtls_md_setup( &ctx, md, 1) ) != 0 )
{
goto exit;
}
/*
* Compute T = T(1) | T(2) | T(3) | ... | T(N)
* Where T(N) is defined in RFC 5869 Section 2.3
*/
for( i = 1; i <= n; i++ )
{
size_t num_to_copy;
unsigned char c = i & 0xff;
ret = mbedtls_md_hmac_starts( &ctx, prk, prk_len );
if( ret != 0 )
{
goto exit;
}
ret = mbedtls_md_hmac_update( &ctx, t, t_len );
if( ret != 0 )
{
goto exit;
}
ret = mbedtls_md_hmac_update( &ctx, info, info_len );
if( ret != 0 )
{
goto exit;
}
/* The constant concatenated to the end of each T(n) is a single octet.
* */
ret = mbedtls_md_hmac_update( &ctx, &c, 1 );
if( ret != 0 )
{
goto exit;
}
ret = mbedtls_md_hmac_finish( &ctx, t );
if( ret != 0 )
{
goto exit;
}
num_to_copy = i != n ? hash_len : okm_len - where;
memcpy( okm + where, t, num_to_copy );
where += hash_len;
t_len = hash_len;
}
exit:
mbedtls_md_free( &ctx );
mbedtls_platform_zeroize( t, sizeof( t ) );
return( ret );
}
#endif /* MBEDTLS_HKDF_C */
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#if defined(MBEDTLS_HMAC_DRBG_C) #if defined(MBEDTLS_HMAC_DRBG_C)
#include "mbedtls/hmac_drbg.h" #include "mbedtls/hmac_drbg.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
...@@ -50,11 +51,6 @@ ...@@ -50,11 +51,6 @@
#endif /* MBEDTLS_SELF_TEST */ #endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_PLATFORM_C */ #endif /* MBEDTLS_PLATFORM_C */
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/* /*
* HMAC_DRBG context initialization * HMAC_DRBG context initialization
*/ */
...@@ -111,16 +107,18 @@ int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx, ...@@ -111,16 +107,18 @@ int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx,
} }
exit: exit:
mbedtls_zeroize( K, sizeof( K ) ); mbedtls_platform_zeroize( K, sizeof( K ) );
return( ret ); return( ret );
} }
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx,
const unsigned char *additional, const unsigned char *additional,
size_t add_len ) size_t add_len )
{ {
(void) mbedtls_hmac_drbg_update_ret( ctx, additional, add_len ); (void) mbedtls_hmac_drbg_update_ret( ctx, additional, add_len );
} }
#endif /* MBEDTLS_DEPRECATED_REMOVED */
/* /*
* Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA) * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA)
...@@ -151,20 +149,32 @@ int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, ...@@ -151,20 +149,32 @@ int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx,
} }
/* /*
* HMAC_DRBG reseeding: 10.1.2.4 (arabic) + 9.2 (Roman) * Internal function used both for seeding and reseeding the DRBG.
* Comments starting with arabic numbers refer to section 10.1.2.4
* of SP800-90A, while roman numbers refer to section 9.2.
*/ */
int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, static int hmac_drbg_reseed_core( mbedtls_hmac_drbg_context *ctx,
const unsigned char *additional, size_t len ) const unsigned char *additional, size_t len,
int use_nonce )
{ {
unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT]; unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT];
size_t seedlen; size_t seedlen = 0;
int ret; int ret;
/* III. Check input length */
if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT ||
ctx->entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT )
{ {
return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); size_t total_entropy_len;
if( use_nonce == 0 )
total_entropy_len = ctx->entropy_len;
else
total_entropy_len = ctx->entropy_len * 3 / 2;
/* III. Check input length */
if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT ||
total_entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT )
{
return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG );
}
} }
memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ); memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT );
...@@ -172,9 +182,32 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, ...@@ -172,9 +182,32 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
/* IV. Gather entropy_len bytes of entropy for the seed */ /* IV. Gather entropy_len bytes of entropy for the seed */
if( ( ret = ctx->f_entropy( ctx->p_entropy, if( ( ret = ctx->f_entropy( ctx->p_entropy,
seed, ctx->entropy_len ) ) != 0 ) seed, ctx->entropy_len ) ) != 0 )
{
return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED );
}
seedlen += ctx->entropy_len;
/* For initial seeding, allow adding of nonce generated
* from the entropy source. See Sect 8.6.7 in SP800-90A. */
if( use_nonce )
{
/* Note: We don't merge the two calls to f_entropy() in order
* to avoid requesting too much entropy from f_entropy()
* at once. Specifically, if the underlying digest is not
* SHA-1, 3 / 2 * entropy_len is at least 36 Bytes, which
* is larger than the maximum of 32 Bytes that our own
* entropy source implementation can emit in a single
* call in configurations disabling SHA-512. */
if( ( ret = ctx->f_entropy( ctx->p_entropy,
seed + seedlen,
ctx->entropy_len / 2 ) ) != 0 )
{
return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED );
}
seedlen += ctx->entropy_len / 2;
}
seedlen = ctx->entropy_len;
/* 1. Concatenate entropy and additional data if any */ /* 1. Concatenate entropy and additional data if any */
if( additional != NULL && len != 0 ) if( additional != NULL && len != 0 )
...@@ -192,12 +225,24 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, ...@@ -192,12 +225,24 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
exit: exit:
/* 4. Done */ /* 4. Done */
mbedtls_zeroize( seed, seedlen ); mbedtls_platform_zeroize( seed, seedlen );
return( ret ); return( ret );
} }
/*
* HMAC_DRBG reseeding: 10.1.2.4 + 9.2
*/
int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
const unsigned char *additional, size_t len )
{
return( hmac_drbg_reseed_core( ctx, additional, len, 0 ) );
}
/* /*
* HMAC_DRBG initialisation (10.1.2.3 + 9.1) * HMAC_DRBG initialisation (10.1.2.3 + 9.1)
*
* The nonce is not passed as a separate parameter but extracted
* from the entropy source as suggested in 8.6.7.
*/ */
int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
const mbedtls_md_info_t * md_info, const mbedtls_md_info_t * md_info,
...@@ -207,7 +252,7 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, ...@@ -207,7 +252,7 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
size_t len ) size_t len )
{ {
int ret; int ret;
size_t entropy_len, md_size; size_t md_size;
if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 ) if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
return( ret ); return( ret );
...@@ -228,27 +273,25 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, ...@@ -228,27 +273,25 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL; ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
/* if( ctx->entropy_len == 0 )
* See SP800-57 5.6.1 (p. 65-66) for the security strength provided by {
* each hash function, then according to SP800-90A rev1 10.1 table 2, /*
* min_entropy_len (in bits) is security_strength. * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by
* * each hash function, then according to SP800-90A rev1 10.1 table 2,
* (This also matches the sizes used in the NIST test vectors.) * min_entropy_len (in bits) is security_strength.
*/ *
entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */ * (This also matches the sizes used in the NIST test vectors.)
md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */ */
32; /* better (256+) -> 256 bits */ ctx->entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */
md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */
/* 32; /* better (256+) -> 256 bits */
* For initialisation, use more entropy to emulate a nonce }
* (Again, matches test vectors.)
*/
ctx->entropy_len = entropy_len * 3 / 2;
if( ( ret = mbedtls_hmac_drbg_reseed( ctx, custom, len ) ) != 0 ) if( ( ret = hmac_drbg_reseed_core( ctx, custom, len,
1 /* add nonce */ ) ) != 0 )
{
return( ret ); return( ret );
}
ctx->entropy_len = entropy_len;
return( 0 ); return( 0 );
} }
...@@ -263,7 +306,7 @@ void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx ...@@ -263,7 +306,7 @@ void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx
} }
/* /*
* Set entropy length grabbed for reseeds * Set entropy length grabbed for seeding
*/ */
void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len ) void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len )
{ {
...@@ -385,7 +428,7 @@ void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ) ...@@ -385,7 +428,7 @@ void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx )
mbedtls_mutex_free( &ctx->mutex ); mbedtls_mutex_free( &ctx->mutex );
#endif #endif
mbedtls_md_free( &ctx->md_ctx ); mbedtls_md_free( &ctx->md_ctx );
mbedtls_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) ); mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) );
} }
#if defined(MBEDTLS_FS_IO) #if defined(MBEDTLS_FS_IO)
...@@ -411,7 +454,7 @@ int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const cha ...@@ -411,7 +454,7 @@ int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const cha
exit: exit:
fclose( f ); fclose( f );
mbedtls_zeroize( buf, sizeof( buf ) ); mbedtls_platform_zeroize( buf, sizeof( buf ) );
return( ret ); return( ret );
} }
...@@ -419,35 +462,36 @@ exit: ...@@ -419,35 +462,36 @@ exit:
int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path )
{ {
int ret = 0; int ret = 0;
FILE *f; FILE *f = NULL;
size_t n; size_t n;
unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ];
unsigned char c;
if( ( f = fopen( path, "rb" ) ) == NULL ) if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR );
fseek( f, 0, SEEK_END ); n = fread( buf, 1, sizeof( buf ), f );
n = (size_t) ftell( f ); if( fread( &c, 1, 1, f ) != 0 )
fseek( f, 0, SEEK_SET );
if( n > MBEDTLS_HMAC_DRBG_MAX_INPUT )
{ {
fclose( f ); ret = MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG;
return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); goto exit;
} }
if( n == 0 || ferror( f ) )
if( fread( buf, 1, n, f ) != n ) {
ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR;
else goto exit;
ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n ); }
fclose( f ); fclose( f );
f = NULL;
mbedtls_zeroize( buf, sizeof( buf ) ); ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n );
exit:
mbedtls_platform_zeroize( buf, sizeof( buf ) );
if( f != NULL )
fclose( f );
if( ret != 0 ) if( ret != 0 )
return( ret ); return( ret );
return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) ); return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) );
} }
#endif /* MBEDTLS_FS_IO */ #endif /* MBEDTLS_FS_IO */
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "mbedtls/md.h" #include "mbedtls/md.h"
#include "mbedtls/md_internal.h" #include "mbedtls/md_internal.h"
#include "mbedtls/platform_util.h"
#if defined(MBEDTLS_PLATFORM_C) #if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h" #include "mbedtls/platform.h"
...@@ -48,11 +49,6 @@ ...@@ -48,11 +49,6 @@
#include <stdio.h> #include <stdio.h>
#endif #endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/* /*
* Reminder: update profiles in x509_crt.c when adding a new hash! * Reminder: update profiles in x509_crt.c when adding a new hash!
*/ */
...@@ -193,11 +189,12 @@ void mbedtls_md_free( mbedtls_md_context_t *ctx ) ...@@ -193,11 +189,12 @@ void mbedtls_md_free( mbedtls_md_context_t *ctx )
if( ctx->hmac_ctx != NULL ) if( ctx->hmac_ctx != NULL )
{ {
mbedtls_zeroize( ctx->hmac_ctx, 2 * ctx->md_info->block_size ); mbedtls_platform_zeroize( ctx->hmac_ctx,
2 * ctx->md_info->block_size );
mbedtls_free( ctx->hmac_ctx ); mbedtls_free( ctx->hmac_ctx );
} }
mbedtls_zeroize( ctx, sizeof( mbedtls_md_context_t ) ); mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md_context_t ) );
} }
int mbedtls_md_clone( mbedtls_md_context_t *dst, int mbedtls_md_clone( mbedtls_md_context_t *dst,
...@@ -311,7 +308,7 @@ int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigne ...@@ -311,7 +308,7 @@ int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigne
ret = md_info->finish_func( ctx.md_ctx, output ); ret = md_info->finish_func( ctx.md_ctx, output );
cleanup: cleanup:
mbedtls_zeroize( buf, sizeof( buf ) ); mbedtls_platform_zeroize( buf, sizeof( buf ) );
fclose( f ); fclose( f );
mbedtls_md_free( &ctx ); mbedtls_md_free( &ctx );
...@@ -361,7 +358,7 @@ int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, ...@@ -361,7 +358,7 @@ int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key,
goto cleanup; goto cleanup;
cleanup: cleanup:
mbedtls_zeroize( sum, sizeof( sum ) ); mbedtls_platform_zeroize( sum, sizeof( sum ) );
return( ret ); return( ret );
} }
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#if defined(MBEDTLS_MD2_C) #if defined(MBEDTLS_MD2_C)
#include "mbedtls/md2.h" #include "mbedtls/md2.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
...@@ -48,11 +49,6 @@ ...@@ -48,11 +49,6 @@
#if !defined(MBEDTLS_MD2_ALT) #if !defined(MBEDTLS_MD2_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
static const unsigned char PI_SUBST[256] = static const unsigned char PI_SUBST[256] =
{ {
0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36,
...@@ -93,7 +89,7 @@ void mbedtls_md2_free( mbedtls_md2_context *ctx ) ...@@ -93,7 +89,7 @@ void mbedtls_md2_free( mbedtls_md2_context *ctx )
if( ctx == NULL ) if( ctx == NULL )
return; return;
mbedtls_zeroize( ctx, sizeof( mbedtls_md2_context ) ); mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md2_context ) );
} }
void mbedtls_md2_clone( mbedtls_md2_context *dst, void mbedtls_md2_clone( mbedtls_md2_context *dst,
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#if defined(MBEDTLS_MD4_C) #if defined(MBEDTLS_MD4_C)
#include "mbedtls/md4.h" #include "mbedtls/md4.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
...@@ -48,11 +49,6 @@ ...@@ -48,11 +49,6 @@
#if !defined(MBEDTLS_MD4_ALT) #if !defined(MBEDTLS_MD4_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/* /*
* 32-bit integer manipulation macros (little endian) * 32-bit integer manipulation macros (little endian)
*/ */
...@@ -86,7 +82,7 @@ void mbedtls_md4_free( mbedtls_md4_context *ctx ) ...@@ -86,7 +82,7 @@ void mbedtls_md4_free( mbedtls_md4_context *ctx )
if( ctx == NULL ) if( ctx == NULL )
return; return;
mbedtls_zeroize( ctx, sizeof( mbedtls_md4_context ) ); mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md4_context ) );
} }
void mbedtls_md4_clone( mbedtls_md4_context *dst, void mbedtls_md4_clone( mbedtls_md4_context *dst,
...@@ -141,15 +137,21 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx, ...@@ -141,15 +137,21 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
GET_UINT32_LE( X[14], data, 56 ); GET_UINT32_LE( X[14], data, 56 );
GET_UINT32_LE( X[15], data, 60 ); GET_UINT32_LE( X[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) #define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n))))
A = ctx->state[0]; A = ctx->state[0];
B = ctx->state[1]; B = ctx->state[1];
C = ctx->state[2]; C = ctx->state[2];
D = ctx->state[3]; D = ctx->state[3];
#define F(x, y, z) ((x & y) | ((~x) & z)) #define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); } #define P(a,b,c,d,x,s) \
do \
{ \
(a) += F((b),(c),(d)) + (x); \
(a) = S((a),(s)); \
} while( 0 )
P( A, B, C, D, X[ 0], 3 ); P( A, B, C, D, X[ 0], 3 );
P( D, A, B, C, X[ 1], 7 ); P( D, A, B, C, X[ 1], 7 );
...@@ -171,8 +173,13 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx, ...@@ -171,8 +173,13 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
#undef P #undef P
#undef F #undef F
#define F(x,y,z) ((x & y) | (x & z) | (y & z)) #define F(x,y,z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } #define P(a,b,c,d,x,s) \
do \
{ \
(a) += F((b),(c),(d)) + (x) + 0x5A827999; \
(a) = S((a),(s)); \
} while( 0 )
P( A, B, C, D, X[ 0], 3 ); P( A, B, C, D, X[ 0], 3 );
P( D, A, B, C, X[ 4], 5 ); P( D, A, B, C, X[ 4], 5 );
...@@ -194,8 +201,13 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx, ...@@ -194,8 +201,13 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
#undef P #undef P
#undef F #undef F
#define F(x,y,z) (x ^ y ^ z) #define F(x,y,z) ((x) ^ (y) ^ (z))
#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } #define P(a,b,c,d,x,s) \
do \
{ \
(a) += F((b),(c),(d)) + (x) + 0x6ED9EBA1; \
(a) = S((a),(s)); \
} while( 0 )
P( A, B, C, D, X[ 0], 3 ); P( A, B, C, D, X[ 0], 3 );
P( D, A, B, C, X[ 8], 9 ); P( D, A, B, C, X[ 8], 9 );
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#if defined(MBEDTLS_MD5_C) #if defined(MBEDTLS_MD5_C)
#include "mbedtls/md5.h" #include "mbedtls/md5.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
...@@ -47,11 +48,6 @@ ...@@ -47,11 +48,6 @@
#if !defined(MBEDTLS_MD5_ALT) #if !defined(MBEDTLS_MD5_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/* /*
* 32-bit integer manipulation macros (little endian) * 32-bit integer manipulation macros (little endian)
*/ */
...@@ -85,7 +81,7 @@ void mbedtls_md5_free( mbedtls_md5_context *ctx ) ...@@ -85,7 +81,7 @@ void mbedtls_md5_free( mbedtls_md5_context *ctx )
if( ctx == NULL ) if( ctx == NULL )
return; return;
mbedtls_zeroize( ctx, sizeof( mbedtls_md5_context ) ); mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md5_context ) );
} }
void mbedtls_md5_clone( mbedtls_md5_context *dst, void mbedtls_md5_clone( mbedtls_md5_context *dst,
...@@ -140,19 +136,22 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, ...@@ -140,19 +136,22 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx,
GET_UINT32_LE( X[14], data, 56 ); GET_UINT32_LE( X[14], data, 56 );
GET_UINT32_LE( X[15], data, 60 ); GET_UINT32_LE( X[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) #define S(x,n) \
( ( (x) << (n) ) | ( ( (x) & 0xFFFFFFFF) >> ( 32 - (n) ) ) )
#define P(a,b,c,d,k,s,t) \ #define P(a,b,c,d,k,s,t) \
{ \ do \
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ { \
} (a) += F((b),(c),(d)) + X[(k)] + (t); \
(a) = S((a),(s)) + (b); \
} while( 0 )
A = ctx->state[0]; A = ctx->state[0];
B = ctx->state[1]; B = ctx->state[1];
C = ctx->state[2]; C = ctx->state[2];
D = ctx->state[3]; D = ctx->state[3];
#define F(x,y,z) (z ^ (x & (y ^ z))) #define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
P( A, B, C, D, 0, 7, 0xD76AA478 ); P( A, B, C, D, 0, 7, 0xD76AA478 );
P( D, A, B, C, 1, 12, 0xE8C7B756 ); P( D, A, B, C, 1, 12, 0xE8C7B756 );
...@@ -173,7 +172,7 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, ...@@ -173,7 +172,7 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx,
#undef F #undef F
#define F(x,y,z) (y ^ (z & (x ^ y))) #define F(x,y,z) ((y) ^ ((z) & ((x) ^ (y))))
P( A, B, C, D, 1, 5, 0xF61E2562 ); P( A, B, C, D, 1, 5, 0xF61E2562 );
P( D, A, B, C, 6, 9, 0xC040B340 ); P( D, A, B, C, 6, 9, 0xC040B340 );
...@@ -194,7 +193,7 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, ...@@ -194,7 +193,7 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx,
#undef F #undef F
#define F(x,y,z) (x ^ y ^ z) #define F(x,y,z) ((x) ^ (y) ^ (z))
P( A, B, C, D, 5, 4, 0xFFFA3942 ); P( A, B, C, D, 5, 4, 0xFFFA3942 );
P( D, A, B, C, 8, 11, 0x8771F681 ); P( D, A, B, C, 8, 11, 0x8771F681 );
...@@ -215,7 +214,7 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, ...@@ -215,7 +214,7 @@ int mbedtls_internal_md5_process( mbedtls_md5_context *ctx,
#undef F #undef F
#define F(x,y,z) (y ^ (x | ~z)) #define F(x,y,z) ((y) ^ ((x) | ~(z)))
P( A, B, C, D, 0, 6, 0xF4292244 ); P( A, B, C, D, 0, 6, 0xF4292244 );
P( D, A, B, C, 7, 10, 0x432AFF97 ); P( D, A, B, C, 7, 10, 0x432AFF97 );
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
/* No need for the header guard as MBEDTLS_MEMORY_BUFFER_ALLOC_C /* No need for the header guard as MBEDTLS_MEMORY_BUFFER_ALLOC_C
is dependent upon MBEDTLS_PLATFORM_C */ is dependent upon MBEDTLS_PLATFORM_C */
#include "mbedtls/platform.h" #include "mbedtls/platform.h"
#include "mbedtls/platform_util.h"
#include <string.h> #include <string.h>
...@@ -42,11 +43,6 @@ ...@@ -42,11 +43,6 @@
#include "mbedtls/threading.h" #include "mbedtls/threading.h"
#endif #endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
#define MAGIC1 0xFF00AA55 #define MAGIC1 0xFF00AA55
#define MAGIC2 0xEE119966 #define MAGIC2 0xEE119966
#define MAX_BT 20 #define MAX_BT 20
...@@ -113,7 +109,7 @@ static void debug_header( memory_header *hdr ) ...@@ -113,7 +109,7 @@ static void debug_header( memory_header *hdr )
#endif #endif
} }
static void debug_chain() static void debug_chain( void )
{ {
memory_header *cur = heap.first; memory_header *cur = heap.first;
...@@ -180,7 +176,7 @@ static int verify_header( memory_header *hdr ) ...@@ -180,7 +176,7 @@ static int verify_header( memory_header *hdr )
return( 0 ); return( 0 );
} }
static int verify_chain() static int verify_chain( void )
{ {
memory_header *prv = heap.first, *cur; memory_header *prv = heap.first, *cur;
...@@ -504,13 +500,13 @@ void mbedtls_memory_buffer_set_verify( int verify ) ...@@ -504,13 +500,13 @@ void mbedtls_memory_buffer_set_verify( int verify )
heap.verify = verify; heap.verify = verify;
} }
int mbedtls_memory_buffer_alloc_verify() int mbedtls_memory_buffer_alloc_verify( void )
{ {
return verify_chain(); return verify_chain();
} }
#if defined(MBEDTLS_MEMORY_DEBUG) #if defined(MBEDTLS_MEMORY_DEBUG)
void mbedtls_memory_buffer_alloc_status() void mbedtls_memory_buffer_alloc_status( void )
{ {
mbedtls_fprintf( stderr, mbedtls_fprintf( stderr,
"Current use: %zu blocks / %zu bytes, max: %zu blocks / " "Current use: %zu blocks / %zu bytes, max: %zu blocks / "
...@@ -609,12 +605,12 @@ void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len ) ...@@ -609,12 +605,12 @@ void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len )
heap.first_free = heap.first; heap.first_free = heap.first;
} }
void mbedtls_memory_buffer_alloc_free() void mbedtls_memory_buffer_alloc_free( void )
{ {
#if defined(MBEDTLS_THREADING_C) #if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_free( &heap.mutex ); mbedtls_mutex_free( &heap.mutex );
#endif #endif
mbedtls_zeroize( &heap, sizeof(buffer_alloc_ctx) ); mbedtls_platform_zeroize( &heap, sizeof(buffer_alloc_ctx) );
} }
#if defined(MBEDTLS_SELF_TEST) #if defined(MBEDTLS_SELF_TEST)
...@@ -629,7 +625,7 @@ static int check_pointer( void *p ) ...@@ -629,7 +625,7 @@ static int check_pointer( void *p )
return( 0 ); return( 0 );
} }
static int check_all_free( ) static int check_all_free( void )
{ {
if( if(
#if defined(MBEDTLS_MEMORY_DEBUG) #if defined(MBEDTLS_MEMORY_DEBUG)
......
/*
* Implementation of NIST SP 800-38F key wrapping, supporting KW and KWP modes
* only
*
* Copyright (C) 2018, Arm Limited (or its affiliates), All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
/*
* Definition of Key Wrapping:
* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf
* RFC 3394 "Advanced Encryption Standard (AES) Key Wrap Algorithm"
* RFC 5649 "Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm"
*
* Note: RFC 3394 defines different methodology for intermediate operations for
* the wrapping and unwrapping operation than the definition in NIST SP 800-38F.
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_NIST_KW_C)
#include "mbedtls/nist_kw.h"
#include "mbedtls/platform_util.h"
#include <stdint.h>
#include <string.h>
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#if !defined(MBEDTLS_NIST_KW_ALT)
#define KW_SEMIBLOCK_LENGTH 8
#define MIN_SEMIBLOCKS_COUNT 3
/* constant-time buffer comparison */
static inline unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n )
{
size_t i;
volatile const unsigned char *A = (volatile const unsigned char *) a;
volatile const unsigned char *B = (volatile const unsigned char *) b;
volatile unsigned char diff = 0;
for( i = 0; i < n; i++ )
{
/* Read volatile data in order before computing diff.
* This avoids IAR compiler warning:
* 'the order of volatile accesses is undefined ..' */
unsigned char x = A[i], y = B[i];
diff |= x ^ y;
}
return( diff );
}
/*! The 64-bit default integrity check value (ICV) for KW mode. */
static const unsigned char NIST_KW_ICV1[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
/*! The 32-bit default integrity check value (ICV) for KWP mode. */
static const unsigned char NIST_KW_ICV2[] = {0xA6, 0x59, 0x59, 0xA6};
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
do { \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
} while( 0 )
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
do { \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
} while( 0 )
#endif
/*
* Initialize context
*/
void mbedtls_nist_kw_init( mbedtls_nist_kw_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_nist_kw_context ) );
}
int mbedtls_nist_kw_setkey( mbedtls_nist_kw_context *ctx,
mbedtls_cipher_id_t cipher,
const unsigned char *key,
unsigned int keybits,
const int is_wrap )
{
int ret;
const mbedtls_cipher_info_t *cipher_info;
cipher_info = mbedtls_cipher_info_from_values( cipher,
keybits,
MBEDTLS_MODE_ECB );
if( cipher_info == NULL )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( cipher_info->block_size != 16 )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
/*
* SP 800-38F currently defines AES cipher as the only block cipher allowed:
* "For KW and KWP, the underlying block cipher shall be approved, and the
* block size shall be 128 bits. Currently, the AES block cipher, with key
* lengths of 128, 192, or 256 bits, is the only block cipher that fits
* this profile."
* Currently we don't support other 128 bit block ciphers for key wrapping,
* such as Camellia and Aria.
*/
if( cipher != MBEDTLS_CIPHER_ID_AES )
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
mbedtls_cipher_free( &ctx->cipher_ctx );
if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
is_wrap ? MBEDTLS_ENCRYPT :
MBEDTLS_DECRYPT )
) != 0 )
{
return( ret );
}
return( 0 );
}
/*
* Free context
*/
void mbedtls_nist_kw_free( mbedtls_nist_kw_context *ctx )
{
mbedtls_cipher_free( &ctx->cipher_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_nist_kw_context ) );
}
/*
* Helper function for Xoring the uint64_t "t" with the encrypted A.
* Defined in NIST SP 800-38F section 6.1
*/
static void calc_a_xor_t( unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t )
{
size_t i = 0;
for( i = 0; i < sizeof( t ); i++ )
{
A[i] ^= ( t >> ( ( sizeof( t ) - 1 - i ) * 8 ) ) & 0xff;
}
}
/*
* KW-AE as defined in SP 800-38F section 6.2
* KWP-AE as defined in SP 800-38F section 6.3
*/
int mbedtls_nist_kw_wrap( mbedtls_nist_kw_context *ctx,
mbedtls_nist_kw_mode_t mode,
const unsigned char *input, size_t in_len,
unsigned char *output, size_t *out_len, size_t out_size )
{
int ret = 0;
size_t semiblocks = 0;
size_t s;
size_t olen, padlen = 0;
uint64_t t = 0;
unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH;
unsigned char *A = output;
*out_len = 0;
/*
* Generate the String to work on
*/
if( mode == MBEDTLS_KW_MODE_KW )
{
if( out_size < in_len + KW_SEMIBLOCK_LENGTH )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
/*
* According to SP 800-38F Table 1, the plaintext length for KW
* must be between 2 to 2^54-1 semiblocks inclusive.
*/
if( in_len < 16 ||
#if SIZE_MAX > 0x1FFFFFFFFFFFFF8
in_len > 0x1FFFFFFFFFFFFF8 ||
#endif
in_len % KW_SEMIBLOCK_LENGTH != 0 )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
memcpy( output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH );
memmove( output + KW_SEMIBLOCK_LENGTH, input, in_len );
}
else
{
if( in_len % 8 != 0 )
{
padlen = ( 8 - ( in_len % 8 ) );
}
if( out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
/*
* According to SP 800-38F Table 1, the plaintext length for KWP
* must be between 1 and 2^32-1 octets inclusive.
*/
if( in_len < 1
#if SIZE_MAX > 0xFFFFFFFF
|| in_len > 0xFFFFFFFF
#endif
)
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
memcpy( output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2 );
PUT_UINT32_BE( ( in_len & 0xffffffff ), output,
KW_SEMIBLOCK_LENGTH / 2 );
memcpy( output + KW_SEMIBLOCK_LENGTH, input, in_len );
memset( output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen );
}
semiblocks = ( ( in_len + padlen ) / KW_SEMIBLOCK_LENGTH ) + 1;
s = 6 * ( semiblocks - 1 );
if( mode == MBEDTLS_KW_MODE_KWP
&& in_len <= KW_SEMIBLOCK_LENGTH )
{
memcpy( inbuff, output, 16 );
ret = mbedtls_cipher_update( &ctx->cipher_ctx,
inbuff, 16, output, &olen );
if( ret != 0 )
goto cleanup;
}
else
{
/*
* Do the wrapping function W, as defined in RFC 3394 section 2.2.1
*/
if( semiblocks < MIN_SEMIBLOCKS_COUNT )
{
ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
goto cleanup;
}
/* Calculate intermediate values */
for( t = 1; t <= s; t++ )
{
memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH );
memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH );
ret = mbedtls_cipher_update( &ctx->cipher_ctx,
inbuff, 16, outbuff, &olen );
if( ret != 0 )
goto cleanup;
memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
calc_a_xor_t( A, t );
memcpy( R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
R2 += KW_SEMIBLOCK_LENGTH;
if( R2 >= output + ( semiblocks * KW_SEMIBLOCK_LENGTH ) )
R2 = output + KW_SEMIBLOCK_LENGTH;
}
}
*out_len = semiblocks * KW_SEMIBLOCK_LENGTH;
cleanup:
if( ret != 0)
{
memset( output, 0, semiblocks * KW_SEMIBLOCK_LENGTH );
}
mbedtls_platform_zeroize( inbuff, KW_SEMIBLOCK_LENGTH * 2 );
mbedtls_platform_zeroize( outbuff, KW_SEMIBLOCK_LENGTH * 2 );
return( ret );
}
/*
* W-1 function as defined in RFC 3394 section 2.2.2
* This function assumes the following:
* 1. Output buffer is at least of size ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH.
* 2. The input buffer is of size semiblocks * KW_SEMIBLOCK_LENGTH.
* 3. Minimal number of semiblocks is 3.
* 4. A is a buffer to hold the first semiblock of the input buffer.
*/
static int unwrap( mbedtls_nist_kw_context *ctx,
const unsigned char *input, size_t semiblocks,
unsigned char A[KW_SEMIBLOCK_LENGTH],
unsigned char *output, size_t* out_len )
{
int ret = 0;
const size_t s = 6 * ( semiblocks - 1 );
size_t olen;
uint64_t t = 0;
unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
unsigned char *R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH;
*out_len = 0;
if( semiblocks < MIN_SEMIBLOCKS_COUNT )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
memcpy( A, input, KW_SEMIBLOCK_LENGTH );
memmove( output, input + KW_SEMIBLOCK_LENGTH, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH );
/* Calculate intermediate values */
for( t = s; t >= 1; t-- )
{
calc_a_xor_t( A, t );
memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH );
memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH );
ret = mbedtls_cipher_update( &ctx->cipher_ctx,
inbuff, 16, outbuff, &olen );
if( ret != 0 )
goto cleanup;
memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
/* Set R as LSB64 of outbuff */
memcpy( R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
if( R == output )
R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH;
else
R -= KW_SEMIBLOCK_LENGTH;
}
*out_len = ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH;
cleanup:
if( ret != 0)
memset( output, 0, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH );
mbedtls_platform_zeroize( inbuff, sizeof( inbuff ) );
mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) );
return( ret );
}
/*
* KW-AD as defined in SP 800-38F section 6.2
* KWP-AD as defined in SP 800-38F section 6.3
*/
int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx,
mbedtls_nist_kw_mode_t mode,
const unsigned char *input, size_t in_len,
unsigned char *output, size_t *out_len, size_t out_size )
{
int ret = 0;
size_t i, olen;
unsigned char A[KW_SEMIBLOCK_LENGTH];
unsigned char diff, bad_padding = 0;
*out_len = 0;
if( out_size < in_len - KW_SEMIBLOCK_LENGTH )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
if( mode == MBEDTLS_KW_MODE_KW )
{
/*
* According to SP 800-38F Table 1, the ciphertext length for KW
* must be between 3 to 2^54 semiblocks inclusive.
*/
if( in_len < 24 ||
#if SIZE_MAX > 0x200000000000000
in_len > 0x200000000000000 ||
#endif
in_len % KW_SEMIBLOCK_LENGTH != 0 )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
A, output, out_len );
if( ret != 0 )
goto cleanup;
/* Check ICV in "constant-time" */
diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH );
if( diff != 0 )
{
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
goto cleanup;
}
}
else if( mode == MBEDTLS_KW_MODE_KWP )
{
size_t padlen = 0;
uint32_t Plen;
/*
* According to SP 800-38F Table 1, the ciphertext length for KWP
* must be between 2 to 2^29 semiblocks inclusive.
*/
if( in_len < KW_SEMIBLOCK_LENGTH * 2 ||
#if SIZE_MAX > 0x100000000
in_len > 0x100000000 ||
#endif
in_len % KW_SEMIBLOCK_LENGTH != 0 )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
if( in_len == KW_SEMIBLOCK_LENGTH * 2 )
{
unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
ret = mbedtls_cipher_update( &ctx->cipher_ctx,
input, 16, outbuff, &olen );
if( ret != 0 )
goto cleanup;
memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
memcpy( output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) );
*out_len = KW_SEMIBLOCK_LENGTH;
}
else
{
/* in_len >= KW_SEMIBLOCK_LENGTH * 3 */
ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
A, output, out_len );
if( ret != 0 )
goto cleanup;
}
/* Check ICV in "constant-time" */
diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 );
if( diff != 0 )
{
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
}
GET_UINT32_BE( Plen, A, KW_SEMIBLOCK_LENGTH / 2 );
/*
* Plen is the length of the plaintext, when the input is valid.
* If Plen is larger than the plaintext and padding, padlen will be
* larger than 8, because of the type wrap around.
*/
padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen;
if ( padlen > 7 )
{
padlen &= 7;
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
}
/* Check padding in "constant-time" */
for( diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++ )
{
if( i >= KW_SEMIBLOCK_LENGTH - padlen )
diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
else
bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
}
if( diff != 0 )
{
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
}
if( ret != 0 )
{
goto cleanup;
}
memset( output + Plen, 0, padlen );
*out_len = Plen;
}
else
{
ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
goto cleanup;
}
cleanup:
if( ret != 0 )
{
memset( output, 0, *out_len );
*out_len = 0;
}
mbedtls_platform_zeroize( &bad_padding, sizeof( bad_padding) );
mbedtls_platform_zeroize( &diff, sizeof( diff ) );
mbedtls_platform_zeroize( A, sizeof( A ) );
return( ret );
}
#endif /* !MBEDTLS_NIST_KW_ALT */
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
#define KW_TESTS 3
/*
* Test vectors taken from NIST
* https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#KW
*/
static const unsigned int key_len[KW_TESTS] = { 16, 24, 32 };
static const unsigned char kw_key[KW_TESTS][32] = {
{ 0x75, 0x75, 0xda, 0x3a, 0x93, 0x60, 0x7c, 0xc2,
0xbf, 0xd8, 0xce, 0xc7, 0xaa, 0xdf, 0xd9, 0xa6 },
{ 0x2d, 0x85, 0x26, 0x08, 0x1d, 0x02, 0xfb, 0x5b,
0x85, 0xf6, 0x9a, 0xc2, 0x86, 0xec, 0xd5, 0x7d,
0x40, 0xdf, 0x5d, 0xf3, 0x49, 0x47, 0x44, 0xd3 },
{ 0x11, 0x2a, 0xd4, 0x1b, 0x48, 0x56, 0xc7, 0x25,
0x4a, 0x98, 0x48, 0xd3, 0x0f, 0xdd, 0x78, 0x33,
0x5b, 0x03, 0x9a, 0x48, 0xa8, 0x96, 0x2c, 0x4d,
0x1c, 0xb7, 0x8e, 0xab, 0xd5, 0xda, 0xd7, 0x88 }
};
static const unsigned char kw_msg[KW_TESTS][40] = {
{ 0x42, 0x13, 0x6d, 0x3c, 0x38, 0x4a, 0x3e, 0xea,
0xc9, 0x5a, 0x06, 0x6f, 0xd2, 0x8f, 0xed, 0x3f },
{ 0x95, 0xc1, 0x1b, 0xf5, 0x35, 0x3a, 0xfe, 0xdb,
0x98, 0xfd, 0xd6, 0xc8, 0xca, 0x6f, 0xdb, 0x6d,
0xa5, 0x4b, 0x74, 0xb4, 0x99, 0x0f, 0xdc, 0x45,
0xc0, 0x9d, 0x15, 0x8f, 0x51, 0xce, 0x62, 0x9d,
0xe2, 0xaf, 0x26, 0xe3, 0x25, 0x0e, 0x6b, 0x4c },
{ 0x1b, 0x20, 0xbf, 0x19, 0x90, 0xb0, 0x65, 0xd7,
0x98, 0xe1, 0xb3, 0x22, 0x64, 0xad, 0x50, 0xa8,
0x74, 0x74, 0x92, 0xba, 0x09, 0xa0, 0x4d, 0xd1 }
};
static const size_t kw_msg_len[KW_TESTS] = { 16, 40, 24 };
static const size_t kw_out_len[KW_TESTS] = { 24, 48, 32 };
static const unsigned char kw_res[KW_TESTS][48] = {
{ 0x03, 0x1f, 0x6b, 0xd7, 0xe6, 0x1e, 0x64, 0x3d,
0xf6, 0x85, 0x94, 0x81, 0x6f, 0x64, 0xca, 0xa3,
0xf5, 0x6f, 0xab, 0xea, 0x25, 0x48, 0xf5, 0xfb },
{ 0x44, 0x3c, 0x6f, 0x15, 0x09, 0x83, 0x71, 0x91,
0x3e, 0x5c, 0x81, 0x4c, 0xa1, 0xa0, 0x42, 0xec,
0x68, 0x2f, 0x7b, 0x13, 0x6d, 0x24, 0x3a, 0x4d,
0x6c, 0x42, 0x6f, 0xc6, 0x97, 0x15, 0x63, 0xe8,
0xa1, 0x4a, 0x55, 0x8e, 0x09, 0x64, 0x16, 0x19,
0xbf, 0x03, 0xfc, 0xaf, 0x90, 0xb1, 0xfc, 0x2d },
{ 0xba, 0x8a, 0x25, 0x9a, 0x47, 0x1b, 0x78, 0x7d,
0xd5, 0xd5, 0x40, 0xec, 0x25, 0xd4, 0x3d, 0x87,
0x20, 0x0f, 0xda, 0xdc, 0x6d, 0x1f, 0x05, 0xd9,
0x16, 0x58, 0x4f, 0xa9, 0xf6, 0xcb, 0xf5, 0x12 }
};
static const unsigned char kwp_key[KW_TESTS][32] = {
{ 0x78, 0x65, 0xe2, 0x0f, 0x3c, 0x21, 0x65, 0x9a,
0xb4, 0x69, 0x0b, 0x62, 0x9c, 0xdf, 0x3c, 0xc4 },
{ 0xf5, 0xf8, 0x96, 0xa3, 0xbd, 0x2f, 0x4a, 0x98,
0x23, 0xef, 0x16, 0x2b, 0x00, 0xb8, 0x05, 0xd7,
0xde, 0x1e, 0xa4, 0x66, 0x26, 0x96, 0xa2, 0x58 },
{ 0x95, 0xda, 0x27, 0x00, 0xca, 0x6f, 0xd9, 0xa5,
0x25, 0x54, 0xee, 0x2a, 0x8d, 0xf1, 0x38, 0x6f,
0x5b, 0x94, 0xa1, 0xa6, 0x0e, 0xd8, 0xa4, 0xae,
0xf6, 0x0a, 0x8d, 0x61, 0xab, 0x5f, 0x22, 0x5a }
};
static const unsigned char kwp_msg[KW_TESTS][31] = {
{ 0xbd, 0x68, 0x43, 0xd4, 0x20, 0x37, 0x8d, 0xc8,
0x96 },
{ 0x6c, 0xcd, 0xd5, 0x85, 0x18, 0x40, 0x97, 0xeb,
0xd5, 0xc3, 0xaf, 0x3e, 0x47, 0xd0, 0x2c, 0x19,
0x14, 0x7b, 0x4d, 0x99, 0x5f, 0x96, 0x43, 0x66,
0x91, 0x56, 0x75, 0x8c, 0x13, 0x16, 0x8f },
{ 0xd1 }
};
static const size_t kwp_msg_len[KW_TESTS] = { 9, 31, 1 };
static const unsigned char kwp_res[KW_TESTS][48] = {
{ 0x41, 0xec, 0xa9, 0x56, 0xd4, 0xaa, 0x04, 0x7e,
0xb5, 0xcf, 0x4e, 0xfe, 0x65, 0x96, 0x61, 0xe7,
0x4d, 0xb6, 0xf8, 0xc5, 0x64, 0xe2, 0x35, 0x00 },
{ 0x4e, 0x9b, 0xc2, 0xbc, 0xbc, 0x6c, 0x1e, 0x13,
0xd3, 0x35, 0xbc, 0xc0, 0xf7, 0x73, 0x6a, 0x88,
0xfa, 0x87, 0x53, 0x66, 0x15, 0xbb, 0x8e, 0x63,
0x8b, 0xcc, 0x81, 0x66, 0x84, 0x68, 0x17, 0x90,
0x67, 0xcf, 0xa9, 0x8a, 0x9d, 0x0e, 0x33, 0x26 },
{ 0x06, 0xba, 0x7a, 0xe6, 0xf3, 0x24, 0x8c, 0xfd,
0xcf, 0x26, 0x75, 0x07, 0xfa, 0x00, 0x1b, 0xc4 }
};
static const size_t kwp_out_len[KW_TESTS] = { 24, 40, 16 };
int mbedtls_nist_kw_self_test( int verbose )
{
mbedtls_nist_kw_context ctx;
unsigned char out[48];
size_t olen;
int i;
int ret = 0;
mbedtls_nist_kw_init( &ctx );
for( i = 0; i < KW_TESTS; i++ )
{
if( verbose != 0 )
mbedtls_printf( " KW-AES-%u ", (unsigned int) key_len[i] * 8 );
ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
kw_key[i], key_len[i] * 8, 1 );
if( ret != 0 )
{
if( verbose != 0 )
mbedtls_printf( " KW: setup failed " );
goto end;
}
ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KW, kw_msg[i],
kw_msg_len[i], out, &olen, sizeof( out ) );
if( ret != 0 || kw_out_len[i] != olen ||
memcmp( out, kw_res[i], kw_out_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed. ");
ret = 1;
goto end;
}
if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
kw_key[i], key_len[i] * 8, 0 ) )
!= 0 )
{
if( verbose != 0 )
mbedtls_printf( " KW: setup failed ");
goto end;
}
ret = mbedtls_nist_kw_unwrap( &ctx, MBEDTLS_KW_MODE_KW,
out, olen, out, &olen, sizeof( out ) );
if( ret != 0 || olen != kw_msg_len[i] ||
memcmp( out, kw_msg[i], kw_msg_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto end;
}
if( verbose != 0 )
mbedtls_printf( " passed\n" );
}
for( i = 0; i < KW_TESTS; i++ )
{
olen = sizeof( out );
if( verbose != 0 )
mbedtls_printf( " KWP-AES-%u ", (unsigned int) key_len[i] * 8 );
ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, kwp_key[i],
key_len[i] * 8, 1 );
if( ret != 0 )
{
if( verbose != 0 )
mbedtls_printf( " KWP: setup failed " );
goto end;
}
ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i],
kwp_msg_len[i], out, &olen, sizeof( out ) );
if( ret != 0 || kwp_out_len[i] != olen ||
memcmp( out, kwp_res[i], kwp_out_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed. ");
ret = 1;
goto end;
}
if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
kwp_key[i], key_len[i] * 8, 0 ) )
!= 0 )
{
if( verbose != 0 )
mbedtls_printf( " KWP: setup failed ");
goto end;
}
ret = mbedtls_nist_kw_unwrap( &ctx, MBEDTLS_KW_MODE_KWP, out,
olen, out, &olen, sizeof( out ) );
if( ret != 0 || olen != kwp_msg_len[i] ||
memcmp( out, kwp_msg[i], kwp_msg_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed. ");
ret = 1;
goto end;
}
if( verbose != 0 )
mbedtls_printf( " passed\n" );
}
end:
mbedtls_nist_kw_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "\n" );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#endif /* MBEDTLS_NIST_KW_C */
...@@ -54,22 +54,24 @@ ...@@ -54,22 +54,24 @@
* Macro to generate an internal function for oid_XXX_from_asn1() (used by * Macro to generate an internal function for oid_XXX_from_asn1() (used by
* the other functions) * the other functions)
*/ */
#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \ #define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \
static const TYPE_T * oid_ ## NAME ## _from_asn1( const mbedtls_asn1_buf *oid ) \ static const TYPE_T * oid_ ## NAME ## _from_asn1( \
{ \ const mbedtls_asn1_buf *oid ) \
const TYPE_T *p = LIST; \ { \
const mbedtls_oid_descriptor_t *cur = (const mbedtls_oid_descriptor_t *) p; \ const TYPE_T *p = (LIST); \
if( p == NULL || oid == NULL ) return( NULL ); \ const mbedtls_oid_descriptor_t *cur = \
while( cur->asn1 != NULL ) { \ (const mbedtls_oid_descriptor_t *) p; \
if( cur->asn1_len == oid->len && \ if( p == NULL || oid == NULL ) return( NULL ); \
memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \ while( cur->asn1 != NULL ) { \
return( p ); \ if( cur->asn1_len == oid->len && \
} \ memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \
p++; \ return( p ); \
cur = (const mbedtls_oid_descriptor_t *) p; \ } \
} \ p++; \
return( NULL ); \ cur = (const mbedtls_oid_descriptor_t *) p; \
} } \
return( NULL ); \
}
/* /*
* Macro to generate a function for retrieving a single attribute from the * Macro to generate a function for retrieving a single attribute from the
...@@ -103,12 +105,13 @@ int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) ...@@ -103,12 +105,13 @@ int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 )
*/ */
#define FN_OID_GET_ATTR2(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1, \ #define FN_OID_GET_ATTR2(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1, \
ATTR2_TYPE, ATTR2) \ ATTR2_TYPE, ATTR2) \
int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2 ) \ int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, \
ATTR2_TYPE * ATTR2 ) \
{ \ { \
const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \
if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \
*ATTR1 = data->ATTR1; \ *(ATTR1) = data->ATTR1; \
*ATTR2 = data->ATTR2; \ *(ATTR2) = data->ATTR2; \
return( 0 ); \ return( 0 ); \
} }
...@@ -119,16 +122,16 @@ int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2 ...@@ -119,16 +122,16 @@ int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2
#define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \ #define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \
int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \ int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \
{ \ { \
const TYPE_T *cur = LIST; \ const TYPE_T *cur = (LIST); \
while( cur->descriptor.asn1 != NULL ) { \ while( cur->descriptor.asn1 != NULL ) { \
if( cur->ATTR1 == ATTR1 ) { \ if( cur->ATTR1 == (ATTR1) ) { \
*oid = cur->descriptor.asn1; \ *oid = cur->descriptor.asn1; \
*olen = cur->descriptor.asn1_len; \ *olen = cur->descriptor.asn1_len; \
return( 0 ); \ return( 0 ); \
} \ } \
cur++; \ cur++; \
} \ } \
return( MBEDTLS_ERR_OID_NOT_FOUND ); \ return( MBEDTLS_ERR_OID_NOT_FOUND ); \
} }
/* /*
...@@ -140,9 +143,9 @@ int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \ ...@@ -140,9 +143,9 @@ int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \
int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \ int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \
size_t *olen ) \ size_t *olen ) \
{ \ { \
const TYPE_T *cur = LIST; \ const TYPE_T *cur = (LIST); \
while( cur->descriptor.asn1 != NULL ) { \ while( cur->descriptor.asn1 != NULL ) { \
if( cur->ATTR1 == ATTR1 && cur->ATTR2 == ATTR2 ) { \ if( cur->ATTR1 == (ATTR1) && cur->ATTR2 == (ATTR2) ) { \
*oid = cur->descriptor.asn1; \ *oid = cur->descriptor.asn1; \
*olen = cur->descriptor.asn1_len; \ *olen = cur->descriptor.asn1_len; \
return( 0 ); \ return( 0 ); \
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment