From 0a5154b8a1fe3d5588c68b3370fabbd8b80420df Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Fri, 10 Mar 2017 11:31:41 +0000 Subject: [PATCH] Clarify the use of ECDSA API In the ecdsa.c sample application we don't use hashing, we use ecdsa directly on a buffer containing plain text. Although the text explains that it should be the message hash it still can be confusing. Any misunderstandings here are potentially very dangerous, because ECDSA truncates the message hash if necessary and this can lead to trivial signature forgeries if the API is misused and the message is passed directly to the function without hashing. This commit adds a hash computation step to the ecdsa.c sample application and clarification to the doxygen documentation of the ECDSA functions involved. --- ChangeLog | 6 ++++++ include/mbedtls/ecdsa.h | 26 +++++++++++++++++++++++++- programs/pkey/ecdsa.c | 31 +++++++++++++++++++++++++------ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 88e2bc92b..a63658b7e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ mbed TLS ChangeLog (Sorted per branch, date) +Changes + * Clarify ECDSA documentation and improve the sample code to avoid + misunderstandings and potentially dangerous use of the API. Pointed out + by Jean-Philippe Aumasson. + + = mbed TLS x.x.x branch released xxxx-xx-xx Bugfix diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index 52827d8d1..a277715b3 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -69,6 +69,10 @@ extern "C" { * \param f_rng RNG function * \param p_rng RNG parameter * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.3 step 5. + * * \return 0 if successful, * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code */ @@ -89,6 +93,10 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, * \param blen Length of buf * \param md_alg MD algorithm used to hash the message * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.3 step 5. + * * \return 0 if successful, * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code */ @@ -107,6 +115,10 @@ int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi * \param r First integer of the signature * \param s Second integer of the signature * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.4 step 3. + * * \return 0 if successful, * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code @@ -120,7 +132,7 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, * serialized as defined in RFC 4492 page 20. * (Not thread-safe to use same context in multiple threads) * - * \note The deterministice version (RFC 6979) is used if + * \note The deterministic version (RFC 6979) is used if * MBEDTLS_ECDSA_DETERMINISTIC is defined. * * \param ctx ECDSA context @@ -136,6 +148,10 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.3 step 5. + * * \return 0 if successful, * or a MBEDTLS_ERR_ECP_XXX, MBEDTLS_ERR_MPI_XXX or * MBEDTLS_ERR_ASN1_XXX error code @@ -172,6 +188,10 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.3 step 5. + * * \return 0 if successful, * or a MBEDTLS_ERR_ECP_XXX, MBEDTLS_ERR_MPI_XXX or * MBEDTLS_ERR_ASN1_XXX error code @@ -193,6 +213,10 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, * \param sig Signature to read and verify * \param slen Size of sig * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * prescribed by SEC1 4.1.4 step 3. + * * \return 0 if successful, * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid, * MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if the signature is diff --git a/programs/pkey/ecdsa.c b/programs/pkey/ecdsa.c index 069d31202..c3ce56a0f 100644 --- a/programs/pkey/ecdsa.c +++ b/programs/pkey/ecdsa.c @@ -37,6 +37,7 @@ #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" #include "mbedtls/ecdsa.h" +#include "mbedtls/sha256.h" #include #endif @@ -101,8 +102,10 @@ int main( int argc, char *argv[] ) mbedtls_ecdsa_context ctx_sign, ctx_verify; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; - unsigned char hash[] = "This should be the hash of a message."; - unsigned char sig[512]; + mbedtls_sha256_context sha256_ctx; + unsigned char message[100]; + unsigned char hash[32]; + unsigned char sig[MBEDTLS_ECDSA_MAX_LEN]; size_t sig_len; const char *pers = "ecdsa"; ((void) argv); @@ -110,8 +113,10 @@ int main( int argc, char *argv[] ) mbedtls_ecdsa_init( &ctx_sign ); mbedtls_ecdsa_init( &ctx_verify ); mbedtls_ctr_drbg_init( &ctr_drbg ); + mbedtls_sha256_init( &sha256_ctx ); - memset(sig, 0, sizeof( sig ) ); + memset( sig, 0, sizeof( sig ) ); + memset( message, 0x25, sizeof( message ) ); ret = 1; if( argc != 1 ) @@ -155,9 +160,23 @@ int main( int argc, char *argv[] ) dump_pubkey( " + Public key: ", &ctx_sign ); /* - * Sign some message hash + * Compute message hash */ - mbedtls_printf( " . Signing message..." ); + mbedtls_printf( " . Computing message hash..." ); + fflush( stdout ); + + mbedtls_sha256_starts( &sha256_ctx, 0 ); + mbedtls_sha256_update( &sha256_ctx, message, sizeof( message ) ); + mbedtls_sha256_finish( &sha256_ctx, hash ); + + mbedtls_printf( " ok\n" ); + + dump_buf( " + Hash: ", hash, sizeof( hash ) ); + + /* + * Sign message hash + */ + mbedtls_printf( " . Signing message hash..." ); fflush( stdout ); if( ( ret = mbedtls_ecdsa_write_signature( &ctx_sign, MBEDTLS_MD_SHA256, @@ -170,7 +189,6 @@ int main( int argc, char *argv[] ) } mbedtls_printf( " ok (signature length = %u)\n", (unsigned int) sig_len ); - dump_buf( " + Hash: ", hash, sizeof hash ); dump_buf( " + Signature: ", sig, sig_len ); /* @@ -224,6 +242,7 @@ exit: mbedtls_ecdsa_free( &ctx_sign ); mbedtls_ctr_drbg_free( &ctr_drbg ); mbedtls_entropy_free( &entropy ); + mbedtls_sha256_free( &sha256_ctx ); return( ret ); }