Reserve option to use BN_mod_exp_mont_consttime in ECDSA.
[openssl.git] / crypto / ecdsa / ecs_ossl.c
index 8b407c5470fd371921eca09dafded7ed0d1b9856..97541a24b5feb2801b42d781408fab5385702c53 100644 (file)
 #include <openssl/err.h>
 #include <openssl/obj_mac.h>
 #include <openssl/bn.h>
+#include <openssl/rand.h>
 
 static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dlen, 
                const BIGNUM *, const BIGNUM *, EC_KEY *eckey);
-static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, 
-               BIGNUM **rp);
+static int ecdsa_sign_setup_no_digest(EC_KEY *eckey,
+               BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp);
+static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in,
+                                       BIGNUM **kinvp, BIGNUM **rp,
+                                       const unsigned char *dgst, int dlen);
 static int ecdsa_do_verify(const unsigned char *dgst, int dgst_len, 
                const ECDSA_SIG *sig, EC_KEY *eckey);
 
 static ECDSA_METHOD openssl_ecdsa_meth = {
        "OpenSSL ECDSA method",
        ecdsa_do_sign,
-       ecdsa_sign_setup,
+       ecdsa_sign_setup_no_digest,
        ecdsa_do_verify,
 #if 0
        NULL, /* init     */
@@ -88,8 +92,14 @@ const ECDSA_METHOD *ECDSA_OpenSSL(void)
        return &openssl_ecdsa_meth;
 }
 
-static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
-               BIGNUM **rp)
+static int ecdsa_sign_setup_no_digest(EC_KEY *eckey,
+               BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp) {
+       return ecdsa_sign_setup(eckey, ctx_in, kinvp, rp, NULL, 0);
+}
+
+static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in,
+                                       BIGNUM **kinvp, BIGNUM **rp,
+                                       const unsigned char *dgst, int dlen)
 {
        BN_CTX   *ctx = NULL;
        BIGNUM   *k = NULL, *r = NULL, *order = NULL, *X = NULL;
@@ -143,15 +153,29 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
        {
                /* get random k */      
                do
-                       if (!BN_rand_range(k, order))
+#ifndef OPENSSL_NO_SHA512
+                       if (dgst != NULL)
                        {
-                               ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,
-                                ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);      
-                               goto err;
+                               if (!BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey),
+                                                          dgst, dlen, ctx))
+                                       {
+                                       ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,
+                                                ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
+                                       goto err;
+                                       }
+                       }
+                       else
+#endif
+                       {
+                               if (!BN_rand_range(k, order))
+                               {
+                                       ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,
+                                                ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
+                                       goto err;
+                               }
                        }
                while (BN_is_zero(k));
 
-#ifdef ECDSA_POINT_MUL_NO_CONSTTIME
                /* We do not want timing information to leak the length of k,
                 * so we compute G*k using an equivalent scalar of fixed
                 * bit-length. */
@@ -159,7 +183,6 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
                if (!BN_add(k, k, order)) goto err;
                if (BN_num_bits(k) <= BN_num_bits(order))
                        if (!BN_add(k, k, order)) goto err;
-#endif /* def(ECDSA_POINT_MUL_NO_CONSTTIME) */
 
                /* compute r the x-coordinate of generator * k */
                if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx))
@@ -196,11 +219,37 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
        while (BN_is_zero(r));
 
        /* compute the inverse of k */
-       if (!BN_mod_inverse(k, k, order, ctx))
-       {
-               ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
-               goto err;       
-       }
+       if (EC_GROUP_get_mont_data(group) != NULL)
+               {
+               /* We want inverse in constant time, therefore we utilize the
+                * fact order must be prime and use Fermats Little Theorem
+                * instead. */
+               if (!BN_set_word(X, 2) )
+                       {
+                       ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
+                       goto err;
+                       }
+               if (!BN_mod_sub(X, order, X, order, ctx))
+                       {
+                       ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
+                       goto err;
+                       }
+               BN_set_flags(X, BN_FLG_CONSTTIME);
+               if (!BN_mod_exp_mont_consttime(k, k, X, order, ctx, EC_GROUP_get_mont_data(group)))
+                       {
+                       ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
+                       goto err;
+                       }
+               }
+       else
+               {
+               if (!BN_mod_inverse(k, k, order, ctx))
+                       {
+                       ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
+                       goto err;       
+                       }
+               }
+
        /* clear old values if necessary */
        if (*rp != NULL)
                BN_clear_free(*rp);
@@ -240,6 +289,14 @@ static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len,
        ECDSA_DATA *ecdsa;
        const BIGNUM *priv_key;
 
+#ifdef OPENSSL_FIPS
+       if(FIPS_selftest_failed())
+               {
+               FIPSerr(FIPS_F_ECDSA_DO_SIGN,FIPS_R_FIPS_SELFTEST_FAILED);
+               return NULL;
+               }
+#endif
+
        ecdsa    = ecdsa_check(eckey);
        group    = EC_KEY_get0_group(eckey);
        priv_key = EC_KEY_get0_private_key(eckey);
@@ -296,8 +353,8 @@ static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len,
        {
                if (in_kinv == NULL || in_r == NULL)
                {
-                       if (!ecdsa->meth->ecdsa_sign_setup(eckey, ctx,
-                                                               &kinv, &ret->r))
+                       if (!ecdsa_sign_setup(
+                               eckey, ctx, &kinv, &ret->r, dgst, dgst_len))
                        {
                                ECDSAerr(ECDSA_F_ECDSA_DO_SIGN,ERR_R_ECDSA_LIB);
                                goto err;
@@ -375,6 +432,14 @@ static int ecdsa_do_verify(const unsigned char *dgst, int dgst_len,
        const EC_GROUP *group;
        const EC_POINT *pub_key;
 
+#ifdef OPENSSL_FIPS
+       if(FIPS_selftest_failed())
+               {
+               FIPSerr(FIPS_F_ECDSA_DO_VERIFY,FIPS_R_FIPS_SELFTEST_FAILED);
+               return -1;
+               }
+#endif
+
        /* check input values */
        if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL ||
            (pub_key = EC_KEY_get0_public_key(eckey)) == NULL || sig == NULL)