From 1c33057a6345ee580a2630eec3b26e0e5b5764b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Sat, 24 Nov 2012 12:05:44 +0100 Subject: [PATCH] Added ecp_check_pubkey(). --- include/polarssl/ecp.h | 19 ++++++++++++ library/ecp.c | 45 ++++++++++++++++++++++++++++ tests/suites/test_suite_ecp.data | 30 +++++++++++++++++++ tests/suites/test_suite_ecp.function | 29 ++++++++++++++++++ 4 files changed, 123 insertions(+) diff --git a/include/polarssl/ecp.h b/include/polarssl/ecp.h index 3336553857..96c135b56b 100644 --- a/include/polarssl/ecp.h +++ b/include/polarssl/ecp.h @@ -158,6 +158,25 @@ int ecp_set_zero( ecp_point *pt ); */ int ecp_copy( ecp_point *P, const ecp_point *Q ); +/** + * \brief Check that a point is a valid public key on this curve + * + * \param grp Curve/group the point should belong to + * \param pt Point to check + * + * \return 0 if point is a valid public key, + * POLARSSL_ERR_ECP_GENERIC otherwise. + * + * \note This function only checks the point is non-zero, has valid + * coordinates and lies on the curve, but not that it is + * indeed a multiple of G. This is additional check is more + * expensive, isn't required by standards, and shouldn't be + * necessary if the group used has a small cofactor. In + * particular, it is useless for the NIST groups which all + * have a cofactor of 1. + */ +int ecp_check_pubkey( const ecp_group *grp, const ecp_point *pt ); + /** * \brief Import a non-zero point from two ASCII strings * diff --git a/library/ecp.c b/library/ecp.c index 3bef06c154..40732885c7 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -467,6 +467,51 @@ int ecp_use_known_dp( ecp_group *grp, size_t index ) while( mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \ MPI_CHK( mpi_sub_mpi( &N, &N, &grp->P ) ) +/* + * Check that a point is valid as a public key (SEC1 3.2.3.1) + */ +int ecp_check_pubkey( const ecp_group *grp, const ecp_point *pt ) +{ + int ret; + mpi YY, RHS; + + if( mpi_cmp_int( &pt->Z, 0 ) == 0 ) + return( POLARSSL_ERR_ECP_GENERIC ); + + /* + * pt coordinates must be normalized for our checks + */ + if( mpi_cmp_int( &pt->Z, 1 ) != 0 ) + return( POLARSSL_ERR_ECP_GENERIC ); + + if( mpi_cmp_int( &pt->X, 0 ) < 0 || + mpi_cmp_int( &pt->Y, 0 ) < 0 || + mpi_cmp_mpi( &pt->X, &grp->P ) >= 0 || + mpi_cmp_mpi( &pt->Y, &grp->P ) >= 0 ) + return( POLARSSL_ERR_ECP_GENERIC ); + + mpi_init( &YY ); mpi_init( &RHS ); + + /* + * YY = Y^2 + * RHS = X (X^2 - 3) + B = X^3 - 3X + B + */ + MPI_CHK( mpi_mul_mpi( &YY, &pt->Y, &pt->Y ) ); MOD_MUL( YY ); + MPI_CHK( mpi_mul_mpi( &RHS, &pt->X, &pt->X ) ); MOD_MUL( RHS ); + MPI_CHK( mpi_sub_int( &RHS, &RHS, 3 ) ); MOD_SUB( RHS ); + MPI_CHK( mpi_mul_mpi( &RHS, &RHS, &pt->X ) ); MOD_MUL( RHS ); + MPI_CHK( mpi_add_mpi( &RHS, &RHS, &grp->B ) ); MOD_ADD( RHS ); + + if( mpi_cmp_mpi( &YY, &RHS ) != 0 ) + ret = POLARSSL_ERR_ECP_GENERIC; + +cleanup: + + mpi_free( &YY ); mpi_free( &RHS ); + + return( ret ); +} + /* * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) */ diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index c8e76b29da..15f90945d9 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -103,6 +103,36 @@ ecp_small_mul:2:0:20:01:0 ECP small multiplication too big ecp_small_mul:-1:0:0:0:POLARSSL_ERR_ECP_GENERIC +ECP small check pubkey #1 +ecp_small_check_pub:1:1:0:POLARSSL_ERR_ECP_GENERIC + +ECP small check pubkey #2 +ecp_small_check_pub:9:-1:1:POLARSSL_ERR_ECP_GENERIC + +ECP small check pubkey #3 +ecp_small_check_pub:9:46:1:0 + +ECP small check pubkey #4 +ecp_small_check_pub:13:47:1:POLARSSL_ERR_ECP_GENERIC + +ECP small check pubkey #5 +ecp_small_check_pub:13:0:1:0 + +ECP small check pubkey #6 +ecp_small_check_pub:-1:10:1:POLARSSL_ERR_ECP_GENERIC + +ECP small check pubkey #7 +ecp_small_check_pub:46:10:1:0 + +ECP small check pubkey #8 +ecp_small_check_pub:47:2:1:POLARSSL_ERR_ECP_GENERIC + +ECP small check pubkey #9 +ecp_small_check_pub:0:2:1:0 + +ECP small check pubkey #10 +ecp_small_check_pub:10:25:1:POLARSSL_ERR_ECP_GENERIC + ECP mod p192 readable ecp_fast_mod:SECP192R1:"000000000000010500000000000001040000000000000103000000000000010200000000000001010000000000000100" diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 389bc6e911..0fcc842da3 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -122,6 +122,29 @@ ecp_small_mul:m:r_zero:x_r:y_r:ret } END_CASE +BEGIN_CASE +ecp_small_check_pub:x:y:z:ret +{ + ecp_group grp; + ecp_point P; + + ecp_group_init( &grp ); + ecp_point_init( &P ); + + TEST_ASSERT( ecp_group_read_string( &grp, 10, + "47", "4", "17", "42", "13" ) == 0 ); + + TEST_ASSERT( mpi_lset( &P.X, {x} ) == 0 ); + TEST_ASSERT( mpi_lset( &P.Y, {y} ) == 0 ); + TEST_ASSERT( mpi_lset( &P.Z, {z} ) == 0 ); + + TEST_ASSERT( ecp_check_pubkey( &grp, &P ) == {ret} ); + + ecp_group_free( &grp ); + ecp_point_free( &P ); +} +END_CASE + BEGIN_CASE ecp_test_vect:id:dA:xA:yA:dB:xB:yB:xZ:yZ { @@ -135,6 +158,8 @@ ecp_test_vect:id:dA:xA:yA:dB:xB:yB:xZ:yZ TEST_ASSERT( ecp_use_known_dp( &grp, POLARSSL_ECP_DP_{id} ) == 0 ); + TEST_ASSERT( ecp_check_pubkey( &grp, &grp.G ) == 0 ); + TEST_ASSERT( mpi_read_string( &dA, 16, {dA} ) == 0 ); TEST_ASSERT( mpi_read_string( &xA, 16, {xA} ) == 0 ); TEST_ASSERT( mpi_read_string( &yA, 16, {yA} ) == 0 ); @@ -147,16 +172,20 @@ ecp_test_vect:id:dA:xA:yA:dB:xB:yB:xZ:yZ TEST_ASSERT( ecp_mul( &grp, &R, &dA, &grp.G ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.X, &xA ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.Y, &yA ) == 0 ); + TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); TEST_ASSERT( ecp_mul( &grp, &R, &dB, &R ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.X, &xZ ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.Y, &yZ ) == 0 ); + TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); TEST_ASSERT( ecp_mul( &grp, &R, &dB, &grp.G ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.X, &xB ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.Y, &yB ) == 0 ); + TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); TEST_ASSERT( ecp_mul( &grp, &R, &dA, &R ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.X, &xZ ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.Y, &yZ ) == 0 ); + TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); ecp_group_free( &grp ); ecp_point_free( &R ); mpi_free( &dA ); mpi_free( &xA ); mpi_free( &yA ); mpi_free( &dB );