Add minified HMAC_DRBG for deterministic ECDSA
diff --git a/include/polarssl/config.h b/include/polarssl/config.h
index ca0c176..f4f5f77 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -279,6 +279,18 @@
#define POLARSSL_ECP_NIST_OPTIM
/**
+ * \def POLARSSL_ECDSA_DETERMINISTIC
+ *
+ * Enable deterministic ECDSA (RFC 6979).
+ * Standard ECDSA is "fragile" in the sense that lack of entropy when signing
+ * may result in a compromise of the long-term signing key. This is avoided by
+ * the deterministic variant.
+ *
+ * Comment this macro to disable deterministic ECDSA.
+ */
+#define POLARSSL_ECDSA_DETERMINISTIC
+
+/**
* \def POLARSSL_KEY_EXCHANGE_PSK_ENABLED
*
* Enable the PSK based ciphersuite modes in SSL / TLS.
diff --git a/library/ecdsa.c b/library/ecdsa.c
index 6f09994..3ab6921 100644
--- a/library/ecdsa.c
+++ b/library/ecdsa.c
@@ -36,6 +36,125 @@
#include "polarssl/ecdsa.h"
#include "polarssl/asn1write.h"
+#if defined(POLARSSL_ECDSA_DETERMINISTIC)
+#include "polarssl/md.h"
+#endif
+
+/*
+ * If using deterministic ECDSA (RFC 6979), we need HMAC_DRBG.
+ * Actually a simplified version is enough, so we implement it below.
+ */
+#if defined(POLARSSL_ECDSA_DETERMINISTIC)
+/*
+ * Simplified HMAC_DRBG context.
+ * No reseed counter, no prediction resistance flag.
+ */
+typedef struct
+{
+ md_context_t md_ctx;
+ unsigned char V[POLARSSL_MD_MAX_SIZE];
+ unsigned char K[POLARSSL_MD_MAX_SIZE];
+} hmac_drbg_context;
+
+/*
+ * Simplified HMAC_DRBG initialisation.
+ *
+ * Uses an entropy buffer rather than callback,
+ * assumes personalisation is not null,
+ * assumes md_info is not NULL and valid.
+ */
+static int hmac_drbg_init( hmac_drbg_context *ctx,
+ const md_info_t * md_info,
+ const unsigned char *entropy, size_t entropy_len,
+ const unsigned char *pers, size_t pers_len )
+{
+ unsigned char sep[1];
+ size_t md_len = md_info->size;
+
+ memset( ctx, 0, sizeof( hmac_drbg_context ) );
+ md_init_ctx( &ctx->md_ctx, md_info );
+
+ memset( ctx->V, 0x01, md_len );
+ /* ctx->K is already 0 */
+
+ sep[0] = 0x00;
+ md_hmac_starts( &ctx->md_ctx, ctx->K, md_len );
+ md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
+ md_hmac_update( &ctx->md_ctx, sep, 1 );
+ md_hmac_update( &ctx->md_ctx, entropy, entropy_len );
+ md_hmac_update( &ctx->md_ctx, pers, pers_len );
+ md_hmac_finish( &ctx->md_ctx, ctx->K );
+
+ /* Step e */
+ md_hmac_starts( &ctx->md_ctx, ctx->K, md_len );
+ md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
+ md_hmac_finish( &ctx->md_ctx, ctx->V );
+
+ /* Step f */
+ sep[0] = 0x01;
+ md_hmac_starts( &ctx->md_ctx, ctx->K, md_len );
+ md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
+ md_hmac_update( &ctx->md_ctx, sep, 1 );
+ md_hmac_update( &ctx->md_ctx, entropy, entropy_len );
+ md_hmac_update( &ctx->md_ctx, pers, pers_len );
+ md_hmac_finish( &ctx->md_ctx, ctx->K );
+
+ /* Step g */
+ md_hmac_starts( &ctx->md_ctx, ctx->K, md_len );
+ md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
+ md_hmac_finish( &ctx->md_ctx, ctx->V );
+
+ return( 0 );
+}
+
+/*
+ * Simplified HMAC_DRBG random function
+ */
+static int hmac_drbg_random( void *state,
+ unsigned char *output, size_t out_len )
+{
+ hmac_drbg_context *ctx = (hmac_drbg_context *) state;
+ unsigned char sep[1] = { 0 };
+ size_t md_len = ctx->md_ctx.md_info->size;
+ size_t left = out_len;
+ unsigned char *out = output;
+
+ while( left != 0 )
+ {
+ size_t use_len = left > md_len ? md_len : left;
+
+ md_hmac_starts( &ctx->md_ctx, ctx->K, md_len );
+ md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
+ md_hmac_finish( &ctx->md_ctx, ctx->V );
+
+ memcpy( out, ctx->V, use_len );
+ out += use_len;
+ left -= use_len;
+ }
+
+ md_hmac_starts( &ctx->md_ctx, ctx->K, md_len );
+ md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
+ md_hmac_update( &ctx->md_ctx, sep, 1 );
+ md_hmac_finish( &ctx->md_ctx, ctx->K );
+
+ md_hmac_starts( &ctx->md_ctx, ctx->K, md_len );
+ md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
+ md_hmac_finish( &ctx->md_ctx, ctx->V );
+
+ return( 0 );
+}
+
+static void hmac_drbg_free( hmac_drbg_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ md_free_ctx( &ctx->md_ctx );
+
+ memset( ctx, 0, sizeof( hmac_drbg_context ) );
+}
+#endif
+
/*
* Derive a suitable integer for group grp from a buffer of length len
* SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3
@@ -51,6 +170,10 @@
if( use_size * 8 > grp->nbits )
MPI_CHK( mpi_shift_r( x, use_size * 8 - grp->nbits ) );
+ /* While at it, reduce modulo N */
+ if( mpi_cmp_mpi( x, &grp->N ) >= 0 )
+ MPI_CHK( mpi_sub_mpi( x, x, &grp->N ) );
+
cleanup:
return( ret );
}