mbedtls/tests/suites/test_suite_ecdsa.function
Andrzej Kurek 1af61cb75b Introduce a new macro for hash size in ecdsa tests
Previously these tests depended on the definition from
inside the MD module, which in turn could be 32 or 64
bytes depending on whether MBEDTLS_SHA512_C was
defined. This is unnecessary, so a constant is itnroduced
instead.
Signed-off-by: Andrzej Kurek <andrzej.kurek@arm.com>
2022-08-11 09:19:42 -04:00

468 lines
18 KiB
Text

/* BEGIN_HEADER */
#include "mbedtls/ecdsa.h"
#include "legacy_or_psa.h"
#if ( defined(MBEDTLS_ECDSA_DETERMINISTIC) && defined(MBEDTLS_SHA256_C) ) || \
( !defined(MBEDTLS_ECDSA_DETERMINISTIC) && defined(MBEDTLS_HAS_ALG_SHA_256_VIA_LOWLEVEL_OR_PSA) )
#define MBEDTLS_HAS_ALG_SHA_256_VIA_MD_IF_DETERMINISTIC
#endif
#define MBEDTLS_TEST_HASH_MAX_SIZE 64
/* END_HEADER */
/* BEGIN_DEPENDENCIES
* depends_on:MBEDTLS_ECDSA_C
* END_DEPENDENCIES
*/
/* BEGIN_CASE */
void ecdsa_prim_zero( int id )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point Q;
mbedtls_mpi d, r, s;
mbedtls_test_rnd_pseudo_info rnd_info;
unsigned char buf[MBEDTLS_TEST_HASH_MAX_SIZE];
mbedtls_ecp_group_init( &grp );
mbedtls_ecp_point_init( &Q );
mbedtls_mpi_init( &d ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s );
memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
memset( buf, 0, sizeof( buf ) );
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_ecdsa_sign( &grp, &r, &s, &d, buf, sizeof( buf ),
&mbedtls_test_rnd_pseudo_rand,
&rnd_info ) == 0 );
TEST_ASSERT( mbedtls_ecdsa_verify( &grp, buf, sizeof( buf ), &Q, &r, &s ) == 0 );
exit:
mbedtls_ecp_group_free( &grp );
mbedtls_ecp_point_free( &Q );
mbedtls_mpi_free( &d ); mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s );
}
/* END_CASE */
/* BEGIN_CASE */
void ecdsa_prim_random( int id )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point Q;
mbedtls_mpi d, r, s;
mbedtls_test_rnd_pseudo_info rnd_info;
unsigned char buf[MBEDTLS_TEST_HASH_MAX_SIZE];
mbedtls_ecp_group_init( &grp );
mbedtls_ecp_point_init( &Q );
mbedtls_mpi_init( &d ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s );
memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
memset( buf, 0, sizeof( buf ) );
/* prepare material for signature */
TEST_ASSERT( mbedtls_test_rnd_pseudo_rand( &rnd_info,
buf, sizeof( buf ) ) == 0 );
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_ecdsa_sign( &grp, &r, &s, &d, buf, sizeof( buf ),
&mbedtls_test_rnd_pseudo_rand,
&rnd_info ) == 0 );
TEST_ASSERT( mbedtls_ecdsa_verify( &grp, buf, sizeof( buf ), &Q, &r, &s ) == 0 );
exit:
mbedtls_ecp_group_free( &grp );
mbedtls_ecp_point_free( &Q );
mbedtls_mpi_free( &d ); mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s );
}
/* END_CASE */
/* BEGIN_CASE */
void ecdsa_prim_test_vectors( int id, char * d_str, char * xQ_str,
char * yQ_str, data_t * rnd_buf,
data_t * hash, char * r_str, char * s_str,
int result )
{
mbedtls_ecp_group grp;
mbedtls_ecp_point Q;
mbedtls_mpi d, r, s, r_check, s_check, zero;
mbedtls_test_rnd_buf_info rnd_info;
mbedtls_ecp_group_init( &grp );
mbedtls_ecp_point_init( &Q );
mbedtls_mpi_init( &d ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s );
mbedtls_mpi_init( &r_check ); mbedtls_mpi_init( &s_check );
mbedtls_mpi_init( &zero );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_ecp_point_read_string( &Q, 16, xQ_str, yQ_str ) == 0 );
TEST_ASSERT( mbedtls_test_read_mpi( &d, d_str ) == 0 );
TEST_ASSERT( mbedtls_test_read_mpi( &r_check, r_str ) == 0 );
TEST_ASSERT( mbedtls_test_read_mpi( &s_check, s_str ) == 0 );
rnd_info.fallback_f_rng = mbedtls_test_rnd_std_rand;
rnd_info.fallback_p_rng = NULL;
rnd_info.buf = rnd_buf->x;
rnd_info.length = rnd_buf->len;
/* Fix rnd_buf->x by shifting it left if necessary */
if( grp.nbits % 8 != 0 )
{
unsigned char shift = 8 - ( grp.nbits % 8 );
size_t i;
for( i = 0; i < rnd_info.length - 1; i++ )
rnd_buf->x[i] = rnd_buf->x[i] << shift | rnd_buf->x[i+1] >> ( 8 - shift );
rnd_buf->x[rnd_info.length-1] <<= shift;
}
TEST_ASSERT( mbedtls_ecdsa_sign( &grp, &r, &s, &d, hash->x, hash->len,
mbedtls_test_rnd_buffer_rand, &rnd_info ) == result );
if ( result == 0)
{
/* Check we generated the expected values */
TEST_EQUAL( mbedtls_mpi_cmp_mpi( &r, &r_check ), 0 );
TEST_EQUAL( mbedtls_mpi_cmp_mpi( &s, &s_check ), 0 );
/* Valid signature */
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len,
&Q, &r_check, &s_check ), 0 );
/* Invalid signature: wrong public key (G instead of Q) */
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len,
&grp.G, &r_check, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
/* Invalid signatures: r or s or both one off */
TEST_EQUAL( mbedtls_mpi_sub_int( &r, &r_check, 1 ), 0 );
TEST_EQUAL( mbedtls_mpi_add_int( &s, &s_check, 1 ), 0 );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r_check, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
/* Invalid signatures: r, s or both (CVE-2022-21449) are zero */
TEST_EQUAL( mbedtls_mpi_lset( &zero, 0 ), 0 );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&zero, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r_check, &zero ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&zero, &zero ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
/* Invalid signatures: r, s or both are == N */
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&grp.N, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r_check, &grp.N ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&grp.N, &grp.N ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
/* Invalid signatures: r, s or both are negative */
TEST_EQUAL( mbedtls_mpi_sub_mpi( &r, &r_check, &grp.N ), 0 );
TEST_EQUAL( mbedtls_mpi_sub_mpi( &s, &s_check, &grp.N ), 0 );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r_check, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
/* Invalid signatures: r or s or both are > N */
TEST_EQUAL( mbedtls_mpi_add_mpi( &r, &r_check, &grp.N ), 0 );
TEST_EQUAL( mbedtls_mpi_add_mpi( &s, &s_check, &grp.N ), 0 );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r_check, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
&r, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
}
exit:
mbedtls_ecp_group_free( &grp );
mbedtls_ecp_point_free( &Q );
mbedtls_mpi_free( &d ); mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s );
mbedtls_mpi_free( &r_check ); mbedtls_mpi_free( &s_check );
mbedtls_mpi_free( &zero );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_ECDSA_DETERMINISTIC */
void ecdsa_det_test_vectors( int id, char * d_str, int md_alg, data_t * hash,
char * r_str, char * s_str )
{
mbedtls_ecp_group grp;
mbedtls_mpi d, r, s, r_check, s_check;
mbedtls_ecp_group_init( &grp );
mbedtls_mpi_init( &d ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s );
mbedtls_mpi_init( &r_check ); mbedtls_mpi_init( &s_check );
TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
TEST_ASSERT( mbedtls_test_read_mpi( &d, d_str ) == 0 );
TEST_ASSERT( mbedtls_test_read_mpi( &r_check, r_str ) == 0 );
TEST_ASSERT( mbedtls_test_read_mpi( &s_check, s_str ) == 0 );
TEST_ASSERT(
mbedtls_ecdsa_sign_det_ext( &grp, &r, &s, &d,
hash->x, hash->len, md_alg,
mbedtls_test_rnd_std_rand,
NULL )
== 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &r, &r_check ) == 0 );
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &s, &s_check ) == 0 );
exit:
mbedtls_ecp_group_free( &grp );
mbedtls_mpi_free( &d ); mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s );
mbedtls_mpi_free( &r_check ); mbedtls_mpi_free( &s_check );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_IF_DETERMINISTIC */
void ecdsa_write_read_zero( int id )
{
mbedtls_ecdsa_context ctx;
mbedtls_test_rnd_pseudo_info rnd_info;
unsigned char hash[32];
unsigned char sig[200];
size_t sig_len, i;
mbedtls_ecdsa_init( &ctx );
memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
memset( hash, 0, sizeof( hash ) );
memset( sig, 0x2a, sizeof( sig ) );
/* generate signing key */
TEST_ASSERT( mbedtls_ecdsa_genkey( &ctx, id,
&mbedtls_test_rnd_pseudo_rand,
&rnd_info ) == 0 );
/* generate and write signature, then read and verify it */
TEST_ASSERT( mbedtls_ecdsa_write_signature( &ctx, MBEDTLS_MD_SHA256,
hash, sizeof( hash ),
sig, sizeof( sig ), &sig_len, &mbedtls_test_rnd_pseudo_rand,
&rnd_info ) == 0 );
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len ) == 0 );
/* check we didn't write past the announced length */
for( i = sig_len; i < sizeof( sig ); i++ )
TEST_ASSERT( sig[i] == 0x2a );
/* try verification with invalid length */
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len - 1 ) != 0 );
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len + 1 ) != 0 );
/* try invalid sequence tag */
sig[0]++;
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len ) != 0 );
sig[0]--;
/* try modifying r */
sig[10]++;
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len ) == MBEDTLS_ERR_ECP_VERIFY_FAILED );
sig[10]--;
/* try modifying s */
sig[sig_len - 1]++;
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len ) == MBEDTLS_ERR_ECP_VERIFY_FAILED );
sig[sig_len - 1]--;
exit:
mbedtls_ecdsa_free( &ctx );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_IF_DETERMINISTIC */
void ecdsa_write_read_random( int id )
{
mbedtls_ecdsa_context ctx;
mbedtls_test_rnd_pseudo_info rnd_info;
unsigned char hash[32];
unsigned char sig[200];
size_t sig_len, i;
mbedtls_ecdsa_init( &ctx );
memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
memset( hash, 0, sizeof( hash ) );
memset( sig, 0x2a, sizeof( sig ) );
/* prepare material for signature */
TEST_ASSERT( mbedtls_test_rnd_pseudo_rand( &rnd_info,
hash, sizeof( hash ) ) == 0 );
/* generate signing key */
TEST_ASSERT( mbedtls_ecdsa_genkey( &ctx, id,
&mbedtls_test_rnd_pseudo_rand,
&rnd_info ) == 0 );
/* generate and write signature, then read and verify it */
TEST_ASSERT( mbedtls_ecdsa_write_signature( &ctx, MBEDTLS_MD_SHA256,
hash, sizeof( hash ),
sig, sizeof( sig ), &sig_len, &mbedtls_test_rnd_pseudo_rand,
&rnd_info ) == 0 );
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len ) == 0 );
/* check we didn't write past the announced length */
for( i = sig_len; i < sizeof( sig ); i++ )
TEST_ASSERT( sig[i] == 0x2a );
/* try verification with invalid length */
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len - 1 ) != 0 );
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len + 1 ) != 0 );
/* try invalid sequence tag */
sig[0]++;
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len ) != 0 );
sig[0]--;
/* try modifying r */
sig[10]++;
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len ) == MBEDTLS_ERR_ECP_VERIFY_FAILED );
sig[10]--;
/* try modifying s */
sig[sig_len - 1]++;
TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
sig, sig_len ) == MBEDTLS_ERR_ECP_VERIFY_FAILED );
sig[sig_len - 1]--;
exit:
mbedtls_ecdsa_free( &ctx );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
void ecdsa_read_restart( int id, data_t *pk, data_t *hash, data_t *sig,
int max_ops, int min_restart, int max_restart )
{
mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_restart_ctx rs_ctx;
int ret, cnt_restart;
mbedtls_ecdsa_init( &ctx );
mbedtls_ecdsa_restart_init( &rs_ctx );
TEST_ASSERT( mbedtls_ecp_group_load( &ctx.grp, id ) == 0 );
TEST_ASSERT( mbedtls_ecp_point_read_binary( &ctx.grp, &ctx.Q,
pk->x, pk->len ) == 0 );
mbedtls_ecp_set_max_ops( max_ops );
cnt_restart = 0;
do {
ret = mbedtls_ecdsa_read_signature_restartable( &ctx,
hash->x, hash->len, sig->x, sig->len, &rs_ctx );
} while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS && ++cnt_restart );
TEST_ASSERT( ret == 0 );
TEST_ASSERT( cnt_restart >= min_restart );
TEST_ASSERT( cnt_restart <= max_restart );
/* try modifying r */
TEST_ASSERT( sig->len > 10 );
sig->x[10]++;
do {
ret = mbedtls_ecdsa_read_signature_restartable( &ctx,
hash->x, hash->len, sig->x, sig->len, &rs_ctx );
} while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS );
TEST_ASSERT( ret == MBEDTLS_ERR_ECP_VERIFY_FAILED );
sig->x[10]--;
/* try modifying s */
sig->x[sig->len - 1]++;
do {
ret = mbedtls_ecdsa_read_signature_restartable( &ctx,
hash->x, hash->len, sig->x, sig->len, &rs_ctx );
} while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS );
TEST_ASSERT( ret == MBEDTLS_ERR_ECP_VERIFY_FAILED );
sig->x[sig->len - 1]--;
/* Do we leak memory when aborting an operation?
* This test only makes sense when we actually restart */
if( min_restart > 0 )
{
ret = mbedtls_ecdsa_read_signature_restartable( &ctx,
hash->x, hash->len, sig->x, sig->len, &rs_ctx );
TEST_ASSERT( ret == MBEDTLS_ERR_ECP_IN_PROGRESS );
}
exit:
mbedtls_ecdsa_free( &ctx );
mbedtls_ecdsa_restart_free( &rs_ctx );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE:MBEDTLS_ECDSA_DETERMINISTIC */
void ecdsa_write_restart( int id, char *d_str, int md_alg,
data_t *hash, data_t *sig_check,
int max_ops, int min_restart, int max_restart )
{
int ret, cnt_restart;
mbedtls_ecdsa_restart_ctx rs_ctx;
mbedtls_ecdsa_context ctx;
unsigned char sig[MBEDTLS_ECDSA_MAX_LEN];
size_t slen;
mbedtls_ecdsa_restart_init( &rs_ctx );
mbedtls_ecdsa_init( &ctx );
memset( sig, 0, sizeof( sig ) );
TEST_ASSERT( mbedtls_ecp_group_load( &ctx.grp, id ) == 0 );
TEST_ASSERT( mbedtls_test_read_mpi( &ctx.d, d_str ) == 0 );
mbedtls_ecp_set_max_ops( max_ops );
slen = sizeof( sig );
cnt_restart = 0;
do {
ret = mbedtls_ecdsa_write_signature_restartable( &ctx,
md_alg, hash->x, hash->len, sig, sizeof( sig ), &slen,
mbedtls_test_rnd_std_rand, NULL, &rs_ctx );
} while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS && ++cnt_restart );
TEST_ASSERT( ret == 0 );
TEST_ASSERT( slen == sig_check->len );
TEST_ASSERT( memcmp( sig, sig_check->x, slen ) == 0 );
TEST_ASSERT( cnt_restart >= min_restart );
TEST_ASSERT( cnt_restart <= max_restart );
/* Do we leak memory when aborting an operation?
* This test only makes sense when we actually restart */
if( min_restart > 0 )
{
ret = mbedtls_ecdsa_write_signature_restartable( &ctx,
md_alg, hash->x, hash->len, sig, sizeof( sig ), &slen,
mbedtls_test_rnd_std_rand, NULL, &rs_ctx );
TEST_ASSERT( ret == MBEDTLS_ERR_ECP_IN_PROGRESS );
}
exit:
mbedtls_ecdsa_restart_free( &rs_ctx );
mbedtls_ecdsa_free( &ctx );
}
/* END_CASE */