Fix ecdsatest.c.
[openssl.git] / crypto / ecdsa / ecs_ossl.c
index f8b5d4ed6a2e53f4116dc1621f5c98f0bcff1a7a..8336bceb673b6fcd96552a8fa7ed2a9e2e50d83a 100644 (file)
@@ -56,6 +56,8 @@
  *
  */
 
+#define OPENSSL_FIPSAPI
+
 #include "ecs_locl.h"
 #include <openssl/err.h>
 #include <openssl/obj_mac.h>
@@ -77,7 +79,7 @@ static ECDSA_METHOD openssl_ecdsa_meth = {
        NULL, /* init     */
        NULL, /* finish   */
 #endif
-       0,    /* flags    */
+       ECDSA_FLAG_FIPS_METHOD,    /* flags    */
        NULL  /* app_data */
 };
 
@@ -131,6 +133,11 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
                ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB);
                goto err;
        }
+
+#ifdef OPENSSL_FIPS
+       if (!fips_check_ec_prng(eckey))
+               goto err;
+#endif
        
        do
        {
@@ -144,6 +151,14 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
                        }
                while (BN_is_zero(k));
 
+               /* 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. */
+
+               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;
+
                /* compute r the x-coordinate of generator * k */
                if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx))
                {
@@ -159,6 +174,7 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
                                goto err;
                        }
                }
+#ifndef OPENSSL_NO_EC2M
                else /* NID_X9_62_characteristic_two_field */
                {
                        if (!EC_POINT_get_affine_coordinates_GF2m(group,
@@ -168,6 +184,7 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
                                goto err;
                        }
                }
+#endif
                if (!BN_nnmod(r, X, order, ctx))
                {
                        ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
@@ -212,7 +229,7 @@ err:
 static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len, 
                const BIGNUM *in_kinv, const BIGNUM *in_r, EC_KEY *eckey)
 {
-       int     ok = 0;
+       int     ok = 0, i;
        BIGNUM *kinv=NULL, *s, *m=NULL,*tmp=NULL,*order=NULL;
        const BIGNUM *ckinv;
        BN_CTX     *ctx = NULL;
@@ -221,6 +238,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);
@@ -231,6 +256,11 @@ static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len,
                return NULL;
        }
 
+#ifdef OPENSSL_FIPS
+       if (!fips_check_ec_prng(eckey))
+               return NULL;
+#endif
+
        ret = ECDSA_SIG_new();
        if (!ret)
        {
@@ -251,22 +281,19 @@ static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len,
                ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_EC_LIB);
                goto err;
        }
-       if (8 * dgst_len > BN_num_bits(order))
+       i = BN_num_bits(order);
+       /* Need to truncate digest if it is too long: first truncate whole
+        * bytes.
+        */
+       if (8 * dgst_len > i)
+               dgst_len = (i + 7)/8;
+       if (!BN_bin2bn(dgst, dgst_len, m))
        {
-               /* XXX
-                * 
-                * Should provide for optional hash truncation:
-                * Keep the BN_num_bits(order) leftmost bits of dgst
-                * (see March 2006 FIPS 186-3 draft, which has a few
-                * confusing errors in this part though)
-                */
-
-               ECDSAerr(ECDSA_F_ECDSA_DO_SIGN,
-                       ECDSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+               ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
                goto err;
        }
-
-       if (!BN_bin2bn(dgst, dgst_len, m))
+       /* If still too long truncate remaining bits with a shift */
+       if ((8 * dgst_len > i) && !BN_rshift(m, m, 8 - (i & 0x7)))
        {
                ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
                goto err;
@@ -275,7 +302,8 @@ static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len,
        {
                if (in_kinv == NULL || in_r == NULL)
                {
-                       if (!ECDSA_sign_setup(eckey, ctx, &kinv, &ret->r))
+                       if (!ecdsa->meth->ecdsa_sign_setup(eckey, ctx,
+                                                               &kinv, &ret->r))
                        {
                                ECDSAerr(ECDSA_F_ECDSA_DO_SIGN,ERR_R_ECDSA_LIB);
                                goto err;
@@ -346,13 +374,21 @@ err:
 static int ecdsa_do_verify(const unsigned char *dgst, int dgst_len,
                const ECDSA_SIG *sig, EC_KEY *eckey)
 {
-       int ret = -1;
+       int ret = -1, i;
        BN_CTX   *ctx;
        BIGNUM   *order, *u1, *u2, *m, *X;
        EC_POINT *point = NULL;
        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)
@@ -400,11 +436,23 @@ static int ecdsa_do_verify(const unsigned char *dgst, int dgst_len,
                goto err;
        }
        /* digest -> m */
+       i = BN_num_bits(order);
+       /* Need to truncate digest if it is too long: first truncate whole
+        * bytes.
+        */
+       if (8 * dgst_len > i)
+               dgst_len = (i + 7)/8;
        if (!BN_bin2bn(dgst, dgst_len, m))
        {
                ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB);
                goto err;
        }
+       /* If still too long truncate remaining bits with a shift */
+       if ((8 * dgst_len > i) && !BN_rshift(m, m, 8 - (i & 0x7)))
+       {
+               ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB);
+               goto err;
+       }
        /* u1 = m * tmp mod order */
        if (!BN_mod_mul(u1, m, u2, order, ctx))
        {
@@ -437,6 +485,7 @@ static int ecdsa_do_verify(const unsigned char *dgst, int dgst_len,
                        goto err;
                }
        }
+#ifndef OPENSSL_NO_EC2M
        else /* NID_X9_62_characteristic_two_field */
        {
                if (!EC_POINT_get_affine_coordinates_GF2m(group,
@@ -446,7 +495,7 @@ static int ecdsa_do_verify(const unsigned char *dgst, int dgst_len,
                        goto err;
                }
        }
-       
+#endif 
        if (!BN_nnmod(u1, X, order, ctx))
        {
                ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB);
@@ -461,3 +510,32 @@ err:
                EC_POINT_free(point);
        return ret;
 }
+
+#ifdef OPENSSL_FIPSCANISTER
+/* FIPS stanadlone version of ecdsa_check: just return FIPS method */
+ECDSA_DATA *fips_ecdsa_check(EC_KEY *key)
+       {
+       static ECDSA_DATA rv = {
+               0,0,0,
+               &openssl_ecdsa_meth
+               };
+       return &rv;
+       }
+/* Standalone digest sign and verify */
+int FIPS_ecdsa_verify_digest(EC_KEY *key,
+                       const unsigned char *dig, int dlen, ECDSA_SIG *s)
+       {
+       ECDSA_DATA *ecdsa = ecdsa_check(key);
+       if (ecdsa == NULL)
+               return 0;
+       return ecdsa->meth->ecdsa_do_verify(dig, dlen, s, key);
+       }
+ECDSA_SIG * FIPS_ecdsa_sign_digest(EC_KEY *key,
+                                       const unsigned char *dig, int dlen)
+       {
+       ECDSA_DATA *ecdsa = ecdsa_check(key);
+       if (ecdsa == NULL)
+               return NULL;
+       return ecdsa->meth->ecdsa_do_sign(dig, dlen, NULL, NULL, key);
+       }
+#endif