mbedtls/tests/suites/test_suite_ecp.function
Gilles Peskine 6373fab865 mbedtls_ecp_gen_privkey_sw: range and coverage tests
Add unit tests for private key generation on short Weierstrass curves.
These tests validate that the result is within the desired range.
Additionally, they validate that after performing many iterations, the
range is covered to an acceptable extent: for tiny ranges, all values
must be reached; for larger ranges, all value bits must reach both 0
and 1.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
2021-06-02 21:31:24 +02:00

1440 lines
55 KiB
Plaintext

/* BEGIN_HEADER */
#include "mbedtls/ecp.h"
#include "ecp_invasive.h"
#if defined(MBEDTLS_TEST_HOOKS) && \
( defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \
defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) )
#define HAVE_FIX_NEGATIVE
#endif
#define ECP_PF_UNKNOWN -1
#define ECP_PT_RESET( x ) \
mbedtls_ecp_point_free( x ); \
mbedtls_ecp_point_init( x );
#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
/* Test whether bytes represents (in big-endian base 256) a number B that
* is "significantly" above a power of 2, which is defined as follows.
* Let n be the integer such that 2^n <= B < 2^{n+1}. B is significantly
* above a power of 2 if (B - 2^n) / 2^n is not negligible. "Negligible"
* is defined as having a negligible chance that if you draw an integer
* in the range [1, B-1] K times, the number will always be less than 2^n,
* where K is the iteration count passed to genkey_sw_many.
*/
static int is_significantly_above_a_power_of_2( data_t *bytes )
{
const uint8_t *p = bytes->x;
size_t len = bytes->len;
unsigned x;
while( len > 0 && p[0] == 0 )
{
++p;
--len;
}
if( len == 0 )
return( 0 );
else if( len == 1 )
x = p[0];
else
x = ( p[0] << 8 ) | p[1];
if( x <= 4 )
return( 0 );
while( ( x & 0x8000 ) == 0 )
x <<= 1;
x &= 0x7fff;
return( x >= 0x1000 );
}
#endif
/* END_HEADER */
/* BEGIN_DEPENDENCIES
* depends_on:MBEDTLS_ECP_C
* END_DEPENDENCIES
*/
/* BEGIN_CASE */
void ecp_valid_param( )
{
TEST_VALID_PARAM( mbedtls_ecp_group_free( NULL ) );
TEST_VALID_PARAM( mbedtls_ecp_keypair_free( NULL ) );
TEST_VALID_PARAM( mbedtls_ecp_point_free( NULL ) );
#if defined(MBEDTLS_ECP_RESTARTABLE)
TEST_VALID_PARAM( mbedtls_ecp_restart_free( NULL ) );
#endif /* MBEDTLS_ECP_RESTARTABLE */
exit:
return;
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_CHECK_PARAMS:!MBEDTLS_PARAM_FAILED_ALT */
void ecp_invalid_param( )
{
mbedtls_ecp_group grp;
mbedtls_ecp_keypair kp;
mbedtls_ecp_point P;
mbedtls_mpi m;
const char *x = "deadbeef";
int valid_fmt = MBEDTLS_ECP_PF_UNCOMPRESSED;
int invalid_fmt = 42;
size_t olen;
unsigned char buf[42] = { 0 };
const unsigned char *null_buf = NULL;
mbedtls_ecp_group_id valid_group = MBEDTLS_ECP_DP_SECP192R1;
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_ctx restart_ctx;
#endif /* MBEDTLS_ECP_RESTARTABLE */
TEST_INVALID_PARAM( mbedtls_ecp_point_init( NULL ) );
TEST_INVALID_PARAM( mbedtls_ecp_keypair_init( NULL ) );
TEST_INVALID_PARAM( mbedtls_ecp_group_init( NULL ) );
#if defined(MBEDTLS_ECP_RESTARTABLE)
TEST_INVALID_PARAM( mbedtls_ecp_restart_init( NULL ) );
TEST_INVALID_PARAM( mbedtls_ecp_check_budget( NULL, &restart_ctx, 42 ) );
#endif /* MBEDTLS_ECP_RESTARTABLE */
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_copy( NULL, &P ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_copy( &P, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_group_copy( NULL, &grp ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_group_copy( &grp, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_privkey( NULL,
&m,
mbedtls_test_rnd_std_rand,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_privkey( &grp,
NULL,
mbedtls_test_rnd_std_rand,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_privkey( &grp,
&m,
NULL,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_set_zero( NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_is_zero( NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_cmp( NULL, &P ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_cmp( &P, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_read_string( NULL, 2,
x, x ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_read_string( &P, 2,
NULL, x ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_read_string( &P, 2,
x, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_write_binary( NULL, &P,
valid_fmt,
&olen,
buf, sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_write_binary( &grp, NULL,
valid_fmt,
&olen,
buf, sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_write_binary( &grp, &P,
invalid_fmt,
&olen,
buf, sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_write_binary( &grp, &P,
valid_fmt,
NULL,
buf, sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_write_binary( &grp, &P,
valid_fmt,
&olen,
NULL, sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_read_binary( NULL, &P, buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_read_binary( &grp, NULL, buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_point_read_binary( &grp, &P, NULL,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_read_point( NULL, &P,
(const unsigned char **) &buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_read_point( &grp, NULL,
(const unsigned char **) &buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_read_point( &grp, &P, &null_buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_read_point( &grp, &P, NULL,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_write_point( NULL, &P,
valid_fmt,
&olen,
buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_write_point( &grp, NULL,
valid_fmt,
&olen,
buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_write_point( &grp, &P,
invalid_fmt,
&olen,
buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_write_point( &grp, &P,
valid_fmt,
NULL,
buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_write_point( &grp, &P,
valid_fmt,
&olen,
NULL,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_group_load( NULL, valid_group ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_read_group( NULL,
(const unsigned char **) &buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_read_group( &grp, NULL,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_read_group( &grp, &null_buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_read_group_id( NULL,
(const unsigned char **) &buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_read_group_id( &valid_group, NULL,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_read_group_id( &valid_group,
&null_buf,
sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_write_group( NULL, &olen,
buf, sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_write_group( &grp, NULL,
buf, sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_tls_write_group( &grp, &olen,
NULL, sizeof( buf ) ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_mul( NULL, &P, &m, &P,
mbedtls_test_rnd_std_rand,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_mul( &grp, NULL, &m, &P,
mbedtls_test_rnd_std_rand,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_mul( &grp, &P, NULL, &P,
mbedtls_test_rnd_std_rand,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_mul( &grp, &P, &m, NULL,
mbedtls_test_rnd_std_rand,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_mul_restartable( NULL, &P, &m, &P,
mbedtls_test_rnd_std_rand,
NULL , NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_mul_restartable( &grp, NULL, &m, &P,
mbedtls_test_rnd_std_rand,
NULL , NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_mul_restartable( &grp, &P, NULL, &P,
mbedtls_test_rnd_std_rand,
NULL , NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_mul_restartable( &grp, &P, &m, NULL,
mbedtls_test_rnd_std_rand,
NULL , NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd( NULL, &P, &m, &P,
&m, &P ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd( &grp, NULL, &m, &P,
&m, &P ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd( &grp, &P, NULL, &P,
&m, &P ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd( &grp, &P, &m, NULL,
&m, &P ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd( &grp, &P, &m, &P,
NULL, &P ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd( &grp, &P, &m, &P,
&m, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd_restartable( NULL, &P, &m, &P,
&m, &P, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd_restartable( &grp, NULL, &m, &P,
&m, &P, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd_restartable( &grp, &P, NULL, &P,
&m, &P, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd_restartable( &grp, &P, &m, NULL,
&m, &P, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd_restartable( &grp, &P, &m, &P,
NULL, &P, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_muladd_restartable( &grp, &P, &m, &P,
&m, NULL, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_check_pubkey( NULL, &P ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_check_pubkey( &grp, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_check_pub_priv( NULL, &kp ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_check_pub_priv( &kp, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_check_privkey( NULL, &m ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_check_privkey( &grp, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_keypair_base( NULL, &P, &m, &P,
mbedtls_test_rnd_std_rand, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_keypair_base( &grp, NULL, &m, &P,
mbedtls_test_rnd_std_rand, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_keypair_base( &grp, &P, NULL, &P,
mbedtls_test_rnd_std_rand, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_keypair_base( &grp, &P, &m, NULL,
mbedtls_test_rnd_std_rand, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_keypair_base( &grp, &P, &m, &P, NULL, NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_keypair( NULL,
&m, &P,
mbedtls_test_rnd_std_rand,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_keypair( &grp,
NULL, &P,
mbedtls_test_rnd_std_rand,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_keypair( &grp,
&m, NULL,
mbedtls_test_rnd_std_rand,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_keypair( &grp,
&m, &P,
NULL,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_key( valid_group, NULL,
mbedtls_test_rnd_std_rand,
NULL ) );
TEST_INVALID_PARAM_RET( MBEDTLS_ERR_ECP_BAD_INPUT_DATA,
mbedtls_ecp_gen_key( valid_group, &kp,
NULL, NULL ) );
exit:
return;
}
/* END_CASE */
/* BEGIN_CASE */
void mbedtls_ecp_curve_info( int id, int tls_id, int size, char * name )
{
const mbedtls_ecp_curve_info *by_id, *by_tls, *by_name;
by_id = mbedtls_ecp_curve_info_from_grp_id( id );
by_tls = mbedtls_ecp_curve_info_from_tls_id( tls_id );
by_name = mbedtls_ecp_curve_info_from_name( name );
TEST_ASSERT( by_id != NULL );
TEST_ASSERT( by_tls != NULL );
TEST_ASSERT( by_name != NULL );
TEST_ASSERT( by_id == by_tls );
TEST_ASSERT( by_id == by_name );
TEST_ASSERT( by_id->bit_size == size );
}
/* END_CASE */
/* BEGIN_CASE */
void ecp_check_pub( int grp_id, char * x_hex, char * y_hex, char * z_hex,
int ret )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point P;
mbedtls_ecp_group_init( &grp );
mbedtls_ecp_point_init( &P );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, grp_id ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &P.X, 16, x_hex ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &P.Y, 16, y_hex ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &P.Z, 16, z_hex ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &P ) == ret );
exit:
mbedtls_ecp_group_free( &grp );
mbedtls_ecp_point_free( &P );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
void ecp_test_vect_restart( int id,
char *dA_str, char *xA_str, char *yA_str,
char *dB_str, char *xZ_str, char *yZ_str,
int max_ops, int min_restarts, int max_restarts )
{
/*
* Test for early restart. Based on test vectors like ecp_test_vect(),
* but for the sake of simplicity only does half of each side. It's
* important to test both base point and random point, though, as memory
* management is different in each case.
*
* Don't try using too precise bounds for restarts as the exact number
* will depend on settings such as MBEDTLS_ECP_FIXED_POINT_OPTIM and
* MBEDTLS_ECP_WINDOW_SIZE, as well as implementation details that may
* change in the future. A factor 2 is a minimum safety margin.
*
* For reference, with mbed TLS 2.4 and default settings, for P-256:
* - Random point mult: ~3250M
* - Cold base point mult: ~3300M
* - Hot base point mult: ~1100M
* With MBEDTLS_ECP_WINDOW_SIZE set to 2 (minimum):
* - Random point mult: ~3850M
*/
mbedtls_ecp_restart_ctx ctx;
mbedtls_ecp_group grp;
mbedtls_ecp_point R, P;
mbedtls_mpi dA, xA, yA, dB, xZ, yZ;
int cnt_restarts;
int ret;
mbedtls_ecp_restart_init( &ctx );
mbedtls_ecp_group_init( &grp );
mbedtls_ecp_point_init( &R ); mbedtls_ecp_point_init( &P );
mbedtls_mpi_init( &dA ); mbedtls_mpi_init( &xA ); mbedtls_mpi_init( &yA );
mbedtls_mpi_init( &dB ); mbedtls_mpi_init( &xZ ); mbedtls_mpi_init( &yZ );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &dA, 16, dA_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &xA, 16, xA_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &yA, 16, yA_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &dB, 16, dB_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &xZ, 16, xZ_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &yZ, 16, yZ_str ) == 0 );
mbedtls_ecp_set_max_ops( (unsigned) max_ops );
/* Base point case */
cnt_restarts = 0;
do {
ECP_PT_RESET( &R );
ret = mbedtls_ecp_mul_restartable( &grp, &R, &dA, &grp.G, NULL, NULL, &ctx );
} while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS && ++cnt_restarts );
TEST_ASSERT( ret == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xA ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.Y, &yA ) == 0 );
TEST_ASSERT( cnt_restarts >= min_restarts );
TEST_ASSERT( cnt_restarts <= max_restarts );
/* Non-base point case */
mbedtls_ecp_copy( &P, &R );
cnt_restarts = 0;
do {
ECP_PT_RESET( &R );
ret = mbedtls_ecp_mul_restartable( &grp, &R, &dB, &P, NULL, NULL, &ctx );
} while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS && ++cnt_restarts );
TEST_ASSERT( ret == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xZ ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.Y, &yZ ) == 0 );
TEST_ASSERT( cnt_restarts >= min_restarts );
TEST_ASSERT( cnt_restarts <= max_restarts );
/* Do we leak memory when aborting an operation?
* This test only makes sense when we actually restart */
if( min_restarts > 0 )
{
ret = mbedtls_ecp_mul_restartable( &grp, &R, &dB, &P, NULL, NULL, &ctx );
TEST_ASSERT( ret == MBEDTLS_ERR_ECP_IN_PROGRESS );
}
exit:
mbedtls_ecp_restart_free( &ctx );
mbedtls_ecp_group_free( &grp );
mbedtls_ecp_point_free( &R ); mbedtls_ecp_point_free( &P );
mbedtls_mpi_free( &dA ); mbedtls_mpi_free( &xA ); mbedtls_mpi_free( &yA );
mbedtls_mpi_free( &dB ); mbedtls_mpi_free( &xZ ); mbedtls_mpi_free( &yZ );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
void ecp_muladd_restart( int id, char *xR_str, char *yR_str,
char *u1_str, char *u2_str,
char *xQ_str, char *yQ_str,
int max_ops, int min_restarts, int max_restarts )
{
/*
* Compute R = u1 * G + u2 * Q
* (test vectors mostly taken from ECDSA intermediate results)
*
* See comments at the top of ecp_test_vect_restart()
*/
mbedtls_ecp_restart_ctx ctx;
mbedtls_ecp_group grp;
mbedtls_ecp_point R, Q;
mbedtls_mpi u1, u2, xR, yR;
int cnt_restarts;
int ret;
mbedtls_ecp_restart_init( &ctx );
mbedtls_ecp_group_init( &grp );
mbedtls_ecp_point_init( &R );
mbedtls_ecp_point_init( &Q );
mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 );
mbedtls_mpi_init( &xR ); mbedtls_mpi_init( &yR );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &u1, 16, u1_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &u2, 16, u2_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &xR, 16, xR_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &yR, 16, yR_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &Q.X, 16, xQ_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &Q.Y, 16, yQ_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_lset( &Q.Z, 1 ) == 0 );
mbedtls_ecp_set_max_ops( (unsigned) max_ops );
cnt_restarts = 0;
do {
ECP_PT_RESET( &R );
ret = mbedtls_ecp_muladd_restartable( &grp, &R,
&u1, &grp.G, &u2, &Q, &ctx );
} while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS && ++cnt_restarts );
TEST_ASSERT( ret == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xR ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.Y, &yR ) == 0 );
TEST_ASSERT( cnt_restarts >= min_restarts );
TEST_ASSERT( cnt_restarts <= max_restarts );
/* Do we leak memory when aborting an operation?
* This test only makes sense when we actually restart */
if( min_restarts > 0 )
{
ret = mbedtls_ecp_muladd_restartable( &grp, &R,
&u1, &grp.G, &u2, &Q, &ctx );
TEST_ASSERT( ret == MBEDTLS_ERR_ECP_IN_PROGRESS );
}
exit:
mbedtls_ecp_restart_free( &ctx );
mbedtls_ecp_group_free( &grp );
mbedtls_ecp_point_free( &R );
mbedtls_ecp_point_free( &Q );
mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 );
mbedtls_mpi_free( &xR ); mbedtls_mpi_free( &yR );
}
/* END_CASE */
/* BEGIN_CASE */
void ecp_test_vect( int id, char * dA_str, char * xA_str, char * yA_str,
char * dB_str, char * xB_str, char * yB_str,
char * xZ_str, char * yZ_str )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point R;
mbedtls_mpi dA, xA, yA, dB, xB, yB, xZ, yZ;
mbedtls_test_rnd_pseudo_info rnd_info;
mbedtls_ecp_group_init( &grp ); mbedtls_ecp_point_init( &R );
mbedtls_mpi_init( &dA ); mbedtls_mpi_init( &xA ); mbedtls_mpi_init( &yA ); mbedtls_mpi_init( &dB );
mbedtls_mpi_init( &xB ); mbedtls_mpi_init( &yB ); mbedtls_mpi_init( &xZ ); mbedtls_mpi_init( &yZ );
memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &grp.G ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &dA, 16, dA_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &xA, 16, xA_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &yA, 16, yA_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &dB, 16, dB_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &xB, 16, xB_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &yB, 16, yB_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &xZ, 16, xZ_str ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &yZ, 16, yZ_str ) == 0 );
TEST_ASSERT( mbedtls_ecp_mul( &grp, &R, &dA, &grp.G,
&mbedtls_test_rnd_pseudo_rand, &rnd_info ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xA ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.Y, &yA ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &R ) == 0 );
TEST_ASSERT( mbedtls_ecp_mul( &grp, &R, &dB, &R, NULL, NULL ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xZ ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.Y, &yZ ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &R ) == 0 );
TEST_ASSERT( mbedtls_ecp_mul( &grp, &R, &dB, &grp.G, NULL, NULL ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xB ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.Y, &yB ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &R ) == 0 );
TEST_ASSERT( mbedtls_ecp_mul( &grp, &R, &dA, &R,
&mbedtls_test_rnd_pseudo_rand, &rnd_info ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xZ ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.Y, &yZ ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &R ) == 0 );
exit:
mbedtls_ecp_group_free( &grp ); mbedtls_ecp_point_free( &R );
mbedtls_mpi_free( &dA ); mbedtls_mpi_free( &xA ); mbedtls_mpi_free( &yA ); mbedtls_mpi_free( &dB );
mbedtls_mpi_free( &xB ); mbedtls_mpi_free( &yB ); mbedtls_mpi_free( &xZ ); mbedtls_mpi_free( &yZ );
}
/* END_CASE */
/* BEGIN_CASE */
void ecp_test_vec_x( int id, char * dA_hex, char * xA_hex, char * dB_hex,
char * xB_hex, char * xS_hex )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point R;
mbedtls_mpi dA, xA, dB, xB, xS;
mbedtls_test_rnd_pseudo_info rnd_info;
mbedtls_ecp_group_init( &grp ); mbedtls_ecp_point_init( &R );
mbedtls_mpi_init( &dA ); mbedtls_mpi_init( &xA );
mbedtls_mpi_init( &dB ); mbedtls_mpi_init( &xB );
mbedtls_mpi_init( &xS );
memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &grp.G ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &dA, 16, dA_hex ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &dB, 16, dB_hex ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &xA, 16, xA_hex ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &xB, 16, xB_hex ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &xS, 16, xS_hex ) == 0 );
TEST_ASSERT( mbedtls_ecp_mul( &grp, &R, &dA, &grp.G,
&mbedtls_test_rnd_pseudo_rand, &rnd_info ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &R ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xA ) == 0 );
TEST_ASSERT( mbedtls_ecp_mul( &grp, &R, &dB, &R,
&mbedtls_test_rnd_pseudo_rand, &rnd_info ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &R ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xS ) == 0 );
TEST_ASSERT( mbedtls_ecp_mul( &grp, &R, &dB, &grp.G, NULL, NULL ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &R ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xB ) == 0 );
TEST_ASSERT( mbedtls_ecp_mul( &grp, &R, &dA, &R, NULL, NULL ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &R ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R.X, &xS ) == 0 );
exit:
mbedtls_ecp_group_free( &grp ); mbedtls_ecp_point_free( &R );
mbedtls_mpi_free( &dA ); mbedtls_mpi_free( &xA );
mbedtls_mpi_free( &dB ); mbedtls_mpi_free( &xB );
mbedtls_mpi_free( &xS );
}
/* END_CASE */
/* BEGIN_CASE */
void ecp_test_mul( int id, data_t * n_hex,
data_t * Px_hex, data_t * Py_hex, data_t * Pz_hex,
data_t * nPx_hex, data_t * nPy_hex, data_t * nPz_hex,
int expected_ret )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point P, nP, R;
mbedtls_mpi n;
mbedtls_test_rnd_pseudo_info rnd_info;
mbedtls_ecp_group_init( &grp ); mbedtls_ecp_point_init( &R );
mbedtls_ecp_point_init( &P ); mbedtls_ecp_point_init( &nP );
mbedtls_mpi_init( &n );
memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &grp.G ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_binary( &n, n_hex->x, n_hex->len ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_binary( &P.X, Px_hex->x, Px_hex->len ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_binary( &P.Y, Py_hex->x, Py_hex->len ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_binary( &P.Z, Pz_hex->x, Pz_hex->len ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_binary( &nP.X, nPx_hex->x, nPx_hex->len )
== 0 );
TEST_ASSERT( mbedtls_mpi_read_binary( &nP.Y, nPy_hex->x, nPy_hex->len )
== 0 );
TEST_ASSERT( mbedtls_mpi_read_binary( &nP.Z, nPz_hex->x, nPz_hex->len )
== 0 );
TEST_ASSERT( mbedtls_ecp_mul( &grp, &R, &n, &P,
&mbedtls_test_rnd_pseudo_rand, &rnd_info )
== expected_ret );
if( expected_ret == 0 )
{
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &nP.X, &R.X ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &nP.Y, &R.Y ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &nP.Z, &R.Z ) == 0 );
}
exit:
mbedtls_ecp_group_free( &grp ); mbedtls_ecp_point_free( &R );
mbedtls_ecp_point_free( &P ); mbedtls_ecp_point_free( &nP );
mbedtls_mpi_free( &n );
}
/* END_CASE */
/* BEGIN_CASE */
void ecp_test_mul_rng( int id, data_t * d_hex)
{
mbedtls_ecp_group grp;
mbedtls_mpi d;
mbedtls_ecp_point Q;
mbedtls_ecp_group_init( &grp ); mbedtls_mpi_init( &d );
mbedtls_ecp_point_init( &Q );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &grp.G ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_binary( &d, d_hex->x, d_hex->len ) == 0 );
TEST_ASSERT( mbedtls_ecp_mul( &grp, &Q, &d, &grp.G,
&mbedtls_test_rnd_zero_rand, NULL )
== MBEDTLS_ERR_ECP_RANDOM_FAILED );
exit:
mbedtls_ecp_group_free( &grp ); mbedtls_mpi_free( &d );
mbedtls_ecp_point_free( &Q );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
void ecp_muladd( int id,
data_t *u1_bin, data_t *P1_bin,
data_t *u2_bin, data_t *P2_bin,
data_t *expected_result )
{
/* Compute R = u1 * P1 + u2 * P2 */
mbedtls_ecp_group grp;
mbedtls_ecp_point P1, P2, R;
mbedtls_mpi u1, u2;
uint8_t actual_result[MBEDTLS_ECP_MAX_PT_LEN];
size_t len;
mbedtls_ecp_group_init( &grp );
mbedtls_ecp_point_init( &P1 );
mbedtls_ecp_point_init( &P2 );
mbedtls_ecp_point_init( &R );
mbedtls_mpi_init( &u1 );
mbedtls_mpi_init( &u2 );
TEST_EQUAL( 0, mbedtls_ecp_group_load( &grp, id ) );
TEST_EQUAL( 0, mbedtls_mpi_read_binary( &u1, u1_bin->x, u1_bin->len ) );
TEST_EQUAL( 0, mbedtls_mpi_read_binary( &u2, u2_bin->x, u2_bin->len ) );
TEST_EQUAL( 0, mbedtls_ecp_point_read_binary( &grp, &P1,
P1_bin->x, P1_bin->len ) );
TEST_EQUAL( 0, mbedtls_ecp_point_read_binary( &grp, &P2,
P2_bin->x, P2_bin->len ) );
TEST_EQUAL( 0, mbedtls_ecp_muladd( &grp, &R, &u1, &P1, &u2, &P2 ) );
TEST_EQUAL( 0, mbedtls_ecp_point_write_binary(
&grp, &R, MBEDTLS_ECP_PF_UNCOMPRESSED,
&len, actual_result, sizeof( actual_result ) ) );
ASSERT_COMPARE( expected_result->x, expected_result->len,
actual_result, len );
exit:
mbedtls_ecp_group_free( &grp );
mbedtls_ecp_point_free( &P1 );
mbedtls_ecp_point_free( &P2 );
mbedtls_ecp_point_free( &R );
mbedtls_mpi_free( &u1 );
mbedtls_mpi_free( &u2 );
}
/* END_CASE */
/* BEGIN_CASE */
void ecp_fast_mod( int id, char * N_str )
{
mbedtls_ecp_group grp;
mbedtls_mpi N, R;
mbedtls_mpi_init( &N ); mbedtls_mpi_init( &R );
mbedtls_ecp_group_init( &grp );
TEST_ASSERT( mbedtls_mpi_read_string( &N, 16, N_str ) == 0 );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( grp.modp != NULL );
/*
* Store correct result before we touch N
*/
TEST_ASSERT( mbedtls_mpi_mod_mpi( &R, &N, &grp.P ) == 0 );
TEST_ASSERT( grp.modp( &N ) == 0 );
TEST_ASSERT( mbedtls_mpi_bitlen( &N ) <= grp.pbits + 3 );
/*
* Use mod rather than addition/subtraction in case previous test fails
*/
TEST_ASSERT( mbedtls_mpi_mod_mpi( &N, &N, &grp.P ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &N, &R ) == 0 );
exit:
mbedtls_mpi_free( &N ); mbedtls_mpi_free( &R );
mbedtls_ecp_group_free( &grp );
}
/* END_CASE */
/* BEGIN_CASE */
void ecp_write_binary( int id, char * x, char * y, char * z, int format,
data_t * out, int blen, int ret )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point P;
unsigned char buf[256];
size_t olen;
memset( buf, 0, sizeof( buf ) );
mbedtls_ecp_group_init( &grp ); mbedtls_ecp_point_init( &P );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &P.X, 16, x ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &P.Y, 16, y ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &P.Z, 16, z ) == 0 );
TEST_ASSERT( mbedtls_ecp_point_write_binary( &grp, &P, format,
&olen, buf, blen ) == ret );
if( ret == 0 )
{
TEST_ASSERT( mbedtls_test_hexcmp( buf, out->x, olen, out->len ) == 0 );
}
exit:
mbedtls_ecp_group_free( &grp ); mbedtls_ecp_point_free( &P );
}
/* END_CASE */
/* BEGIN_CASE */
void ecp_read_binary( int id, data_t * buf, char * x, char * y, char * z,
int ret )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point P;
mbedtls_mpi X, Y, Z;
mbedtls_ecp_group_init( &grp ); mbedtls_ecp_point_init( &P );
mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &X, 16, x ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &Y, 16, y ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &Z, 16, z ) == 0 );
TEST_ASSERT( mbedtls_ecp_point_read_binary( &grp, &P, buf->x, buf->len ) == ret );
if( ret == 0 )
{
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.X, &X ) == 0 );
if( mbedtls_ecp_get_type( &grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
{
TEST_ASSERT( mbedtls_mpi_cmp_int( &Y, 0 ) == 0 );
TEST_ASSERT( P.Y.p == NULL );
TEST_ASSERT( mbedtls_mpi_cmp_int( &Z, 1 ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_int( &P.Z, 1 ) == 0 );
}
else
{
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Y, &Y ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Z, &Z ) == 0 );
}
}
exit:
mbedtls_ecp_group_free( &grp ); mbedtls_ecp_point_free( &P );
mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
}
/* END_CASE */
/* BEGIN_CASE */
void mbedtls_ecp_tls_read_point( int id, data_t * buf, char * x, char * y,
char * z, int ret )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point P;
mbedtls_mpi X, Y, Z;
const unsigned char *vbuf = buf->x;
mbedtls_ecp_group_init( &grp ); mbedtls_ecp_point_init( &P );
mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &X, 16, x ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &Y, 16, y ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &Z, 16, z ) == 0 );
TEST_ASSERT( mbedtls_ecp_tls_read_point( &grp, &P, &vbuf, buf->len ) == ret );
if( ret == 0 )
{
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.X, &X ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Y, &Y ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Z, &Z ) == 0 );
TEST_ASSERT( (uint32_t)( vbuf - buf->x ) == buf->len );
}
exit:
mbedtls_ecp_group_free( &grp ); mbedtls_ecp_point_free( &P );
mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
}
/* END_CASE */
/* BEGIN_CASE */
void ecp_tls_write_read_point( int id )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point pt;
unsigned char buf[256];
const unsigned char *vbuf;
size_t olen;
mbedtls_ecp_group_init( &grp );
mbedtls_ecp_point_init( &pt );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
memset( buf, 0x00, sizeof( buf ) ); vbuf = buf;
TEST_ASSERT( mbedtls_ecp_tls_write_point( &grp, &grp.G,
MBEDTLS_ECP_PF_COMPRESSED, &olen, buf, 256 ) == 0 );
TEST_ASSERT( mbedtls_ecp_tls_read_point( &grp, &pt, &vbuf, olen )
== MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
TEST_ASSERT( vbuf == buf + olen );
memset( buf, 0x00, sizeof( buf ) ); vbuf = buf;
TEST_ASSERT( mbedtls_ecp_tls_write_point( &grp, &grp.G,
MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, buf, 256 ) == 0 );
TEST_ASSERT( mbedtls_ecp_tls_read_point( &grp, &pt, &vbuf, olen ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &grp.G.X, &pt.X ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &grp.G.Y, &pt.Y ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &grp.G.Z, &pt.Z ) == 0 );
TEST_ASSERT( vbuf == buf + olen );
memset( buf, 0x00, sizeof( buf ) ); vbuf = buf;
TEST_ASSERT( mbedtls_ecp_set_zero( &pt ) == 0 );
TEST_ASSERT( mbedtls_ecp_tls_write_point( &grp, &pt,
MBEDTLS_ECP_PF_COMPRESSED, &olen, buf, 256 ) == 0 );
TEST_ASSERT( mbedtls_ecp_tls_read_point( &grp, &pt, &vbuf, olen ) == 0 );
TEST_ASSERT( mbedtls_ecp_is_zero( &pt ) );
TEST_ASSERT( vbuf == buf + olen );
memset( buf, 0x00, sizeof( buf ) ); vbuf = buf;
TEST_ASSERT( mbedtls_ecp_set_zero( &pt ) == 0 );
TEST_ASSERT( mbedtls_ecp_tls_write_point( &grp, &pt,
MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, buf, 256 ) == 0 );
TEST_ASSERT( mbedtls_ecp_tls_read_point( &grp, &pt, &vbuf, olen ) == 0 );
TEST_ASSERT( mbedtls_ecp_is_zero( &pt ) );
TEST_ASSERT( vbuf == buf + olen );
exit:
mbedtls_ecp_group_free( &grp );
mbedtls_ecp_point_free( &pt );
}
/* END_CASE */
/* BEGIN_CASE */
void mbedtls_ecp_tls_read_group( data_t * buf, int result, int bits,
int record_len )
{
mbedtls_ecp_group grp;
const unsigned char *vbuf = buf->x;
int ret;
mbedtls_ecp_group_init( &grp );
ret = mbedtls_ecp_tls_read_group( &grp, &vbuf, buf->len );
TEST_ASSERT( ret == result );
if( ret == 0)
{
TEST_ASSERT( mbedtls_mpi_bitlen( &grp.P ) == (size_t) bits );
TEST_ASSERT( vbuf - buf->x == record_len);
}
exit:
mbedtls_ecp_group_free( &grp );
}
/* END_CASE */
/* BEGIN_CASE */
void ecp_tls_write_read_group( int id )
{
mbedtls_ecp_group grp1, grp2;
unsigned char buf[10];
const unsigned char *vbuf = buf;
size_t len;
int ret;
mbedtls_ecp_group_init( &grp1 );
mbedtls_ecp_group_init( &grp2 );
memset( buf, 0x00, sizeof( buf ) );
TEST_ASSERT( mbedtls_ecp_group_load( &grp1, id ) == 0 );
TEST_ASSERT( mbedtls_ecp_tls_write_group( &grp1, &len, buf, 10 ) == 0 );
ret = mbedtls_ecp_tls_read_group( &grp2, &vbuf, len );
TEST_ASSERT( ret == 0 );
if( ret == 0 )
{
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &grp1.N, &grp2.N ) == 0 );
TEST_ASSERT( grp1.id == grp2.id );
}
exit:
mbedtls_ecp_group_free( &grp1 );
mbedtls_ecp_group_free( &grp2 );
}
/* END_CASE */
/* BEGIN_CASE */
void mbedtls_ecp_check_privkey( int id, char * key_hex, int ret )
{
mbedtls_ecp_group grp;
mbedtls_mpi d;
mbedtls_ecp_group_init( &grp );
mbedtls_mpi_init( &d );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &d, 16, key_hex ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_privkey( &grp, &d ) == ret );
exit:
mbedtls_ecp_group_free( &grp );
mbedtls_mpi_free( &d );
}
/* END_CASE */
/* BEGIN_CASE */
void mbedtls_ecp_check_pub_priv( int id_pub, char * Qx_pub, char * Qy_pub,
int id, char * d, char * Qx, char * Qy,
int ret )
{
mbedtls_ecp_keypair pub, prv;
mbedtls_ecp_keypair_init( &pub );
mbedtls_ecp_keypair_init( &prv );
if( id_pub != MBEDTLS_ECP_DP_NONE )
TEST_ASSERT( mbedtls_ecp_group_load( &pub.grp, id_pub ) == 0 );
TEST_ASSERT( mbedtls_ecp_point_read_string( &pub.Q, 16, Qx_pub, Qy_pub ) == 0 );
if( id != MBEDTLS_ECP_DP_NONE )
TEST_ASSERT( mbedtls_ecp_group_load( &prv.grp, id ) == 0 );
TEST_ASSERT( mbedtls_ecp_point_read_string( &prv.Q, 16, Qx, Qy ) == 0 );
TEST_ASSERT( mbedtls_mpi_read_string( &prv.d, 16, d ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pub_priv( &pub, &prv ) == ret );
exit:
mbedtls_ecp_keypair_free( &pub );
mbedtls_ecp_keypair_free( &prv );
}
/* END_CASE */
/* BEGIN_CASE */
void mbedtls_ecp_gen_keypair( int id )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point Q;
mbedtls_mpi d;
mbedtls_test_rnd_pseudo_info rnd_info;
mbedtls_ecp_group_init( &grp );
mbedtls_ecp_point_init( &Q );
mbedtls_mpi_init( &d );
memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_ecp_gen_keypair( &grp, &d, &Q,
&mbedtls_test_rnd_pseudo_rand,
&rnd_info ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &grp, &Q ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_privkey( &grp, &d ) == 0 );
exit:
mbedtls_ecp_group_free( &grp );
mbedtls_ecp_point_free( &Q );
mbedtls_mpi_free( &d );
}
/* END_CASE */
/* BEGIN_CASE */
void mbedtls_ecp_gen_key( int id )
{
mbedtls_ecp_keypair key;
mbedtls_test_rnd_pseudo_info rnd_info;
mbedtls_ecp_keypair_init( &key );
memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
TEST_ASSERT( mbedtls_ecp_gen_key( id, &key,
&mbedtls_test_rnd_pseudo_rand,
&rnd_info ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_pubkey( &key.grp, &key.Q ) == 0 );
TEST_ASSERT( mbedtls_ecp_check_privkey( &key.grp, &key.d ) == 0 );
exit:
mbedtls_ecp_keypair_free( &key );
}
/* END_CASE */
/* BEGIN_CASE */
void mbedtls_ecp_read_key( int grp_id, data_t* in_key, int expected, int canonical )
{
int ret = 0;
mbedtls_ecp_keypair key;
mbedtls_ecp_keypair key2;
mbedtls_ecp_keypair_init( &key );
mbedtls_ecp_keypair_init( &key2 );
ret = mbedtls_ecp_read_key( grp_id, &key, in_key->x, in_key->len );
TEST_ASSERT( ret == expected );
if( expected == 0 )
{
ret = mbedtls_ecp_check_privkey( &key.grp, &key.d );
TEST_ASSERT( ret == 0 );
if( canonical )
{
unsigned char buf[MBEDTLS_ECP_MAX_BYTES];
ret = mbedtls_ecp_write_key( &key, buf, in_key->len );
TEST_ASSERT( ret == 0 );
ASSERT_COMPARE( in_key->x, in_key->len,
buf, in_key->len );
}
else
{
unsigned char export1[MBEDTLS_ECP_MAX_BYTES];
unsigned char export2[MBEDTLS_ECP_MAX_BYTES];
ret = mbedtls_ecp_write_key( &key, export1, in_key->len );
TEST_ASSERT( ret == 0 );
ret = mbedtls_ecp_read_key( grp_id, &key2, export1, in_key->len );
TEST_ASSERT( ret == expected );
ret = mbedtls_ecp_write_key( &key2, export2, in_key->len );
TEST_ASSERT( ret == 0 );
ASSERT_COMPARE( export1, in_key->len,
export2, in_key->len );
}
}
exit:
mbedtls_ecp_keypair_free( &key );
mbedtls_ecp_keypair_free( &key2 );
}
/* END_CASE */
/* BEGIN_CASE depends_on:HAVE_FIX_NEGATIVE */
void fix_negative( data_t *N_bin, int c, int bits )
{
mbedtls_mpi C, M, N;
mbedtls_mpi_init( &C );
mbedtls_mpi_init( &M );
mbedtls_mpi_init( &N );
/* C = - c * 2^bits (positive since c is negative) */
TEST_EQUAL( 0, mbedtls_mpi_lset( &C, -c ) );
TEST_EQUAL( 0, mbedtls_mpi_shift_l( &C, bits ) );
TEST_EQUAL( 0, mbedtls_mpi_read_binary( &N, N_bin->x, N_bin->len ) );
TEST_EQUAL( 0, mbedtls_mpi_grow( &N, C.n ) );
/* M = N - C = - ( C - N ) (expected result of fix_negative) */
TEST_EQUAL( 0, mbedtls_mpi_sub_mpi( &M, &N, &C ) );
mbedtls_ecp_fix_negative( &N, c, bits );
TEST_EQUAL( 0, mbedtls_mpi_cmp_mpi( &N, &M ) );
exit:
mbedtls_mpi_free( &C );
mbedtls_mpi_free( &M );
mbedtls_mpi_free( &N );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS:MBEDTLS_ECP_MONTGOMERY_ENABLED */
void genkey_mx_known_answer( int bits, data_t *seed, data_t *expected )
{
mbedtls_test_rnd_buf_info rnd_info;
mbedtls_mpi d;
int ret;
uint8_t *actual = NULL;
mbedtls_mpi_init( &d );
rnd_info.buf = seed->x;
rnd_info.length = seed->len;
rnd_info.fallback_f_rng = NULL;
rnd_info.fallback_p_rng = NULL;
ASSERT_ALLOC( actual, expected->len );
ret = mbedtls_ecp_gen_privkey_mx( bits, &d,
mbedtls_test_rnd_buffer_rand, &rnd_info );
if( expected->len == 0 )
{
/* Expecting an error (happens if there isn't enough randomness) */
TEST_ASSERT( ret != 0 );
}
else
{
TEST_EQUAL( ret, 0 );
TEST_EQUAL( (size_t) bits + 1, mbedtls_mpi_bitlen( &d ) );
TEST_EQUAL( 0, mbedtls_mpi_write_binary( &d, actual, expected->len ) );
/* Test the exact result. This assumes that the output of the
* RNG is used in a specific way, which is overly constraining.
* The advantage is that it's easier to test the expected properties
* of the generated key:
* - The most significant bit must be at a specific positions
* (can be enforced by checking the bit-length).
* - The least significant bits must have specific values
* (can be enforced by checking these bits).
* - Other bits must be random (by testing with different RNG outputs,
* we validate that those bits are indeed influenced by the RNG). */
ASSERT_COMPARE( expected->x, expected->len,
actual, expected->len );
}
exit:
mbedtls_free( actual );
mbedtls_mpi_free( &d );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS:MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
void genkey_sw_many( data_t *bound_bytes, int iterations )
{
/* Generate numbers in the range 1..bound-1. Do it iterations times.
* This function assumes that the value of bound is at least 2 and
* that iterations is large enough that a one-in-2^iterations chance
* effectively never occurs.
*/
mbedtls_mpi bound;
size_t n_bits;
mbedtls_mpi result;
size_t b;
/* If bound is small, stats[b] is the number of times the value b
* has been generated. Otherwise stats[b] is the number of times a
* value with bit b set has been generated. */
size_t *stats = NULL;
size_t stats_len;
int full_stats;
size_t i;
mbedtls_mpi_init( &bound );
mbedtls_mpi_init( &result );
TEST_EQUAL( 0, mbedtls_mpi_read_binary( &bound,
bound_bytes->x, bound_bytes->len ) );
n_bits = mbedtls_mpi_bitlen( &bound );
/* Consider a bound "small" if it's less than 2^5. This value is chosen
* to be small enough that the probability of missing one value is
* negligible given the number of iterations. It must be less than
* 256 because some of the code below assumes that "small" values
* fit in a byte. */
if( n_bits <= 5 )
{
full_stats = 1;
stats_len = bound_bytes->x[bound_bytes->len - 1];
}
else
{
full_stats = 0;
stats_len = n_bits;
}
ASSERT_ALLOC( stats, stats_len );
for( i = 0; i < (size_t) iterations; i++ )
{
mbedtls_test_set_step( i );
TEST_EQUAL( 0, mbedtls_ecp_gen_privkey_sw(
&bound, n_bits, &result,
mbedtls_test_rnd_std_rand, NULL ) );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &bound ) < 0 );
TEST_ASSERT( mbedtls_mpi_cmp_int( &result, 1 ) >= 0 );
if( full_stats )
{
uint8_t value;
TEST_EQUAL( 0, mbedtls_mpi_write_binary( &result, &value, 1 ) );
TEST_ASSERT( value < stats_len );
++stats[value];
}
else
{
for( b = 0; b < n_bits; b++ )
stats[b] += mbedtls_mpi_get_bit( &result, b );
}
}
if( full_stats )
{
for( b = 1; b < stats_len; b++ )
{
mbedtls_test_set_step( 1000000 + b );
/* Assert that each value has been reached at least once.
* This is almost guaranteed if the iteration count is large
* enough. This is a very crude way of checking the distribution.
*/
TEST_ASSERT( stats[b] > 0 );
}
}
else
{
for( b = 0; b < n_bits; b++ )
{
mbedtls_test_set_step( 1000000 + b );
/* Assert that each bit has been set in at least one result and
* clear in at least one result. Provided that iterations is not
* too small, it would be extremely unlikely for this not to be
* the case if the results are uniformly distributed.
*
* As an exception, the top bit may legitimately never be set
* if bound is a power of 2 or only slightly above.
*/
if( b != n_bits - 1 ||
is_significantly_above_a_power_of_2( bound_bytes ) )
{
TEST_ASSERT( stats[b] > 0 );
}
TEST_ASSERT( stats[b] < (size_t) iterations );
}
}
exit:
mbedtls_mpi_free( &bound );
mbedtls_mpi_free( &result );
mbedtls_free( stats );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */
void ecp_selftest( )
{
TEST_ASSERT( mbedtls_ecp_self_test( 1 ) == 0 );
}
/* END_CASE */