X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fecdsa%2Fecs_ossl.c;h=8336bceb673b6fcd96552a8fa7ed2a9e2e50d83a;hp=f8b5d4ed6a2e53f4116dc1621f5c98f0bcff1a7a;hb=ea8c77a55bcf3ac0744ac8724ca2476818787330;hpb=da989402f22d44bab2e920ec4872e711991e0047 diff --git a/crypto/ecdsa/ecs_ossl.c b/crypto/ecdsa/ecs_ossl.c index f8b5d4ed6a..8336bceb67 100644 --- a/crypto/ecdsa/ecs_ossl.c +++ b/crypto/ecdsa/ecs_ossl.c @@ -56,6 +56,8 @@ * */ +#define OPENSSL_FIPSAPI + #include "ecs_locl.h" #include #include @@ -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