diff --git a/ChangeLog.d/ecdsa-verify-fixes.txt b/ChangeLog.d/ecdsa-verify-fixes.txt new file mode 100644 index 000000000..b41b0461a --- /dev/null +++ b/ChangeLog.d/ecdsa-verify-fixes.txt @@ -0,0 +1,5 @@ +Bugfix + * Fix ECDSA verification, where it was not always validating the + public key. This bug meant that it was possible to verify a + signature with an invalid public key, in some cases. Reported by + Guido Vranken using Cryptofuzz in #4420. diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index 71b73eee5..967f07b9b 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -245,10 +245,8 @@ int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r, * This must be initialized. * * \return \c 0 on success. - * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the signature - * is invalid. * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX - * error code on failure for any other reason. + * error code on failure. */ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, const unsigned char *buf, size_t blen, diff --git a/library/ecp.c b/library/ecp.c index 08e33e217..37f6090a8 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -2662,14 +2662,17 @@ static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, if( mbedtls_mpi_cmp_int( m, 0 ) == 0 ) { + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_set_zero( R ) ); } else if( mbedtls_mpi_cmp_int( m, 1 ) == 0 ) { + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); } else if( mbedtls_mpi_cmp_int( m, -1 ) == 0 ) { + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); MPI_ECP_NEG( &R->Y ); } diff --git a/tests/suites/test_suite_ecdsa.data b/tests/suites/test_suite_ecdsa.data index 9bb35c54a..50411e9b1 100644 --- a/tests/suites/test_suite_ecdsa.data +++ b/tests/suites/test_suite_ecdsa.data @@ -361,3 +361,63 @@ ecdsa_prim_test_vectors:MBEDTLS_ECP_DP_SECP521R1:"0":"0151518F1AF0F563517EDD5485 ECDSA private parameter greater than n p521 depends_on:MBEDTLS_ECP_DP_SECP521R1_ENABLED ecdsa_prim_test_vectors:MBEDTLS_ECP_DP_SECP521R1:"0065FDA3409451DCAB0A0EAD45495112A3D813C17BFD34BDF8C1209D7DF5849120597779060A7FF9D704ADF78B570FFAD6F062E95C7E0C5D5481C5B153B48B375FA11":"0151518F1AF0F563517EDD5485190DF95A4BF57B5CBA4CF2A9A3F6474725A35F7AFE0A6DDEB8BEDBCD6A197E592D40188901CECD650699C9B5E456AEA5ADD19052A8":"006F3B142EA1BFFF7E2837AD44C9E4FF6D2D34C73184BBAD90026DD5E6E85317D9DF45CAD7803C6C20035B2F3FF63AFF4E1BA64D1C077577DA3F4286C58F0AEAE643":"00C1C2B305419F5A41344D7E4359933D734096F556197A9B244342B8B62F46F9373778F9DE6B6497B1EF825FF24F42F9B4A4BD7382CFC3378A540B1B7F0C1B956C2F":"DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA20A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F":"0154FD3836AF92D0DCA57DD5341D3053988534FDE8318FC6AAAAB68E2E6F4339B19F2F281A7E0B22C269D93CF8794A9278880ED7DBB8D9362CAEACEE544320552251":"017705A7030290D1CEB605A9A1BB03FF9CDD521E87A696EC926C8C10C8362DF4975367101F67D1CF9BCCBF2F3D239534FA509E70AAC851AE01AAC68D62F866472660":MBEDTLS_ERR_ECP_INVALID_KEY + +ECDSA verify invalid pub key (not on curve), zero bytes of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"1":"2":"1":"1":"":MBEDTLS_ERR_ECP_INVALID_KEY + +ECDSA verify invalid pub key (not on curve), one byte of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"1":"2":"1":"1":"00":MBEDTLS_ERR_ECP_INVALID_KEY + +ECDSA verify invalid pub key (not on curve), r=1, s=1 +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"1":"2":"1":"1":"0000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_ERR_ECP_INVALID_KEY + +ECDSA verify invalid pub key (also not on curve), r=1, s=1 +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"1":"12345":"1":"1":"0000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_ERR_ECP_INVALID_KEY + +ECDSA verify invalid pub key (not on curve), r=12345, s=1 +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"1":"2":"12345":"1":"0000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_ERR_ECP_INVALID_KEY + +ECDSA verify invalid pub key (not on curve), r=1, s=12345 +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"1":"2":"1":"12345":"0000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_ERR_ECP_INVALID_KEY + +ECDSA verify valid pub key, invalid sig (r=0), 0 bytes of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798":"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8":"0":"1":"":MBEDTLS_ERR_ECP_VERIFY_FAILED + +ECDSA verify valid pub key, invalid sig (r=0), 1 byte of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798":"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8":"0":"1":"00":MBEDTLS_ERR_ECP_VERIFY_FAILED + +ECDSA verify valid pub key, invalid sig (r>n-1), 32 bytes of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798":"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8":"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141":"12":"0000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_ERR_ECP_VERIFY_FAILED + +ECDSA verify valid pub key, valid/incorrect sig, 0 bytes of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798":"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8":"ed3bace23c5e17652e174c835fb72bf53ee306b3406a26890221b4cef7500f88":"84eead3fb3cdbdac882412af64cc125b6784690bebf575f1c32162ab65080037":"":MBEDTLS_ERR_ECP_VERIFY_FAILED + +ECDSA verify valid pub key, valid/incorrect sig, 1 byte of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798":"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8":"ed3bace23c5e17652e174c835fb72bf53ee306b3406a26890221b4cef7500f88":"84eead3fb3cdbdac882412af64cc125b6784690bebf575f1c32162ab65080037":"00":MBEDTLS_ERR_ECP_VERIFY_FAILED + +ECDSA verify valid pub key, valid/incorrect sig, 32 bytes of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798":"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8":"ed3bace23c5e17652e174c835fb72bf53ee306b3406a26890221b4cef7500f88":"84eead3fb3cdbdac882412af64cc125b6784690bebf575f1c32162ab65080037":"0000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_ERR_ECP_VERIFY_FAILED + +ECDSA verify valid public key, correct sig, 0 bytes of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798":"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8":"ed3bace23c5e17652e174c835fb72bf53ee306b3406a26890221b4cef7500f88":"c9cc1ba95156bc103055a5d7946f3a3ae7f0657d1e53f1d5c2c9782950aa69b":"":0 + +ECDSA verify valid pub key, correct sig, 1 byte of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798":"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8":"ed3bace23c5e17652e174c835fb72bf53ee306b3406a26890221b4cef7500f88":"c9cc1ba95156bc103055a5d7946f3a3ae7f0657d1e53f1d5c2c9782950aa69b":"00":0 + +ECDSA verify valid pub key, correct sig, 32 bytes of data +depends_on:MBEDTLS_ECP_DP_SECP256K1_ENABLED +ecdsa_verify:MBEDTLS_ECP_DP_SECP256K1:"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798":"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8":"ed3bace23c5e17652e174c835fb72bf53ee306b3406a26890221b4cef7500f88":"c9cc1ba95156bc103055a5d7946f3a3ae7f0657d1e53f1d5c2c9782950aa69b":"0000000000000000000000000000000000000000000000000000000000000000":0 diff --git a/tests/suites/test_suite_ecdsa.function b/tests/suites/test_suite_ecdsa.function index e82f39d32..0e2ac92c7 100644 --- a/tests/suites/test_suite_ecdsa.function +++ b/tests/suites/test_suite_ecdsa.function @@ -466,3 +466,40 @@ exit: mbedtls_ecdsa_free( &ctx ); } /* END_CASE */ + +/* BEGIN_CASE */ +void ecdsa_verify( int grp_id, char * x, char * y, char * r, char * s, data_t * content, int expected ) +{ + mbedtls_ecdsa_context ctx; + mbedtls_mpi sig_r, sig_s; + + mbedtls_ecdsa_init( &ctx ); + mbedtls_mpi_init( &sig_r ); + mbedtls_mpi_init( &sig_s ); + + /* Prepare ECP group context */ + TEST_EQUAL( mbedtls_ecp_group_load( &ctx.grp, grp_id ), 0 ); + + /* Prepare public key */ + TEST_EQUAL( mbedtls_test_read_mpi( &ctx.Q.X, x ), 0 ); + TEST_EQUAL( mbedtls_test_read_mpi( &ctx.Q.Y, y ), 0 ); + TEST_EQUAL( mbedtls_mpi_lset( &ctx.Q.Z, 1 ), 0 ); + + /* Prepare signature R & S */ + TEST_EQUAL( mbedtls_test_read_mpi( &sig_r, r ), 0 ); + TEST_EQUAL( mbedtls_test_read_mpi( &sig_s, s ), 0 ); + + /* Test whether public key has expected validity */ + TEST_EQUAL( mbedtls_ecp_check_pubkey( &ctx.grp, &ctx.Q ), + expected == MBEDTLS_ERR_ECP_INVALID_KEY ? MBEDTLS_ERR_ECP_INVALID_KEY : 0 ); + + /* Verification */ + int result = mbedtls_ecdsa_verify( &ctx.grp, content->x, content->len, &ctx.Q, &sig_r, &sig_s ); + + TEST_EQUAL( result, expected ); +exit: + mbedtls_ecdsa_free( &ctx ); + mbedtls_mpi_free( &sig_r ); + mbedtls_mpi_free( &sig_s ); +} +/* END_CASE */