diff --git a/include/polarssl/ecp.h b/include/polarssl/ecp.h index 7192f1e6c..9b83bc51b 100644 --- a/include/polarssl/ecp.h +++ b/include/polarssl/ecp.h @@ -635,6 +635,18 @@ int ecp_gen_keypair( ecp_group *grp, mpi *d, ecp_point *Q, int ecp_gen_key( ecp_group_id grp_id, ecp_keypair *key, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); +/** + * \brief Check a public-private key pair + * + * \param pub Keypair structure holding a public key + * \param prv Keypair structure holding a private (plus public) key + * + * \return 0 if successfull (keys are valid and match), or + * POLARSSL_ERR_ECP_BAD_INPUT_DATA, or + * a POLARSSL_ERR_ECP_XXX or POLARSSL_ERR_MPI_XXX code. + */ +int ecp_check_pub_priv( const ecp_keypair *pub, const ecp_keypair *prv ); + #if defined(POLARSSL_SELF_TEST) /** * \brief Checkup routine diff --git a/library/ecp.c b/library/ecp.c index ece781d5e..41e25e9e0 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -1897,6 +1897,48 @@ int ecp_gen_key( ecp_group_id grp_id, ecp_keypair *key, return( ecp_gen_keypair( &key->grp, &key->d, &key->Q, f_rng, p_rng ) ); } +/* + * Check a public-private key pair + */ +int ecp_check_pub_priv( const ecp_keypair *pub, const ecp_keypair *prv ) +{ + int ret; + ecp_point Q; + ecp_group grp; + + if( pub->grp.id == POLARSSL_ECP_DP_NONE || + pub->grp.id != prv->grp.id || + mpi_cmp_mpi( &pub->Q.X, &prv->Q.X ) || + mpi_cmp_mpi( &pub->Q.Y, &prv->Q.Y ) || + mpi_cmp_mpi( &pub->Q.Z, &prv->Q.Z ) ) + { + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); + } + + ecp_point_init( &Q ); + ecp_group_init( &grp ); + + /* ecp_mul() needs a non-const group... */ + ecp_group_copy( &grp, &prv->grp ); + + /* Also checks d is valid */ + MPI_CHK( ecp_mul( &grp, &Q, &prv->d, &prv->grp.G, NULL, NULL ) ); + + if( mpi_cmp_mpi( &Q.X, &prv->Q.X ) || + mpi_cmp_mpi( &Q.Y, &prv->Q.Y ) || + mpi_cmp_mpi( &Q.Z, &prv->Q.Z ) ) + { + ret = POLARSSL_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + ecp_point_free( &Q ); + ecp_group_free( &grp ); + + return( ret ); +} + #if defined(POLARSSL_SELF_TEST) /* diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index d871a8dfc..a5dc528e4 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -324,6 +324,33 @@ ECP check privkey #11 (montgomery, OK) depends_on:POLARSSL_ECP_DP_M255_ENABLED ecp_check_privkey:POLARSSL_ECP_DP_M255:"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8":0 +ECP check public-private #1 (OK) +depends_on:POLARSSL_ECP_DP_SECP256R1_ENABLED +ecp_check_pub_priv:POLARSSL_ECP_DP_SECP256R1:"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":POLARSSL_ECP_DP_SECP256R1:"00f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":0 + +ECP check public-private #2 (group none) +ecp_check_pub_priv:POLARSSL_ECP_DP_NONE:"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":POLARSSL_ECP_DP_NONE:"00f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":POLARSSL_ERR_ECP_BAD_INPUT_DATA + +ECP check public-private #3 (group mismatch) +depends_on:POLARSSL_ECP_DP_SECP256R1_ENABLED:POLARSSL_ECP_DP_SECP384R1_ENABLED +ecp_check_pub_priv:POLARSSL_ECP_DP_SECP384R1:"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":POLARSSL_ECP_DP_SECP256R1:"00f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":POLARSSL_ERR_ECP_BAD_INPUT_DATA + +ECP check public-private #4 (Qx mismatch) +depends_on:POLARSSL_ECP_DP_SECP256R1_ENABLED +ecp_check_pub_priv:POLARSSL_ECP_DP_SECP256R1:"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596293":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":POLARSSL_ECP_DP_SECP256R1:"00f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":POLARSSL_ERR_ECP_BAD_INPUT_DATA + +ECP check public-private #5 (Qy mismatch) +depends_on:POLARSSL_ECP_DP_SECP256R1_ENABLED +ecp_check_pub_priv:POLARSSL_ECP_DP_SECP256R1:"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edfe":POLARSSL_ECP_DP_SECP256R1:"00f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":POLARSSL_ERR_ECP_BAD_INPUT_DATA + +ECP check public-private #6 (wrong Qx) +depends_on:POLARSSL_ECP_DP_SECP256R1_ENABLED +ecp_check_pub_priv:POLARSSL_ECP_DP_SECP256R1:"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596293":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":POLARSSL_ECP_DP_SECP256R1:"00f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596293":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":POLARSSL_ERR_ECP_BAD_INPUT_DATA + +ECP check public-private #7 (wrong Qy) +depends_on:POLARSSL_ECP_DP_SECP256R1_ENABLED +ecp_check_pub_priv:POLARSSL_ECP_DP_SECP256R1:"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edfe":POLARSSL_ECP_DP_SECP256R1:"00f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":"37cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f76822596292":"4ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edfe":POLARSSL_ERR_ECP_BAD_INPUT_DATA + ECP gen keypair depends_on:POLARSSL_ECP_DP_SECP192R1_ENABLED ecp_gen_keypair:POLARSSL_ECP_DP_SECP192R1 diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 62dc6065e..1c22a846d 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -598,6 +598,32 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void ecp_check_pub_priv( int id_pub, char *Qx_pub, char *Qy_pub, + int id, char *d, char *Qx, char *Qy, int ret ) +{ + ecp_keypair pub, prv; + + ecp_keypair_init( &pub ); + ecp_keypair_init( &prv ); + + if( id_pub != POLARSSL_ECP_DP_NONE ) + TEST_ASSERT( ecp_use_known_dp( &pub.grp, id_pub ) == 0 ); + TEST_ASSERT( ecp_point_read_string( &pub.Q, 16, Qx_pub, Qy_pub ) == 0 ); + + if( id != POLARSSL_ECP_DP_NONE ) + TEST_ASSERT( ecp_use_known_dp( &prv.grp, id ) == 0 ); + TEST_ASSERT( ecp_point_read_string( &prv.Q, 16, Qx, Qy ) == 0 ); + TEST_ASSERT( mpi_read_string( &prv.d, 16, d ) == 0 ); + + TEST_ASSERT( ecp_check_pub_priv( &pub, &prv ) == ret ); + +exit: + ecp_keypair_free( &pub ); + ecp_keypair_free( &prv ); +} +/* END_CASE */ + /* BEGIN_CASE */ void ecp_gen_keypair( int id ) {