Make ECC self tests lazy.

Change-Id: I1b7e4bd5403031232fc1e1ffb3c6e40decac23b9
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51565
Reviewed-by: David Benjamin <davidben@google.com>
fips-20220613
Adam Langley 3 years ago committed by Adam Langley
parent c76da9d46a
commit 3053b739ba
  1. 12
      crypto/fipsmodule/ec/ec.c
  2. 2
      crypto/fipsmodule/ec/ec_key.c
  3. 7
      crypto/fipsmodule/ec/internal.h
  4. 3
      crypto/fipsmodule/ecdh/ecdh.c
  5. 13
      crypto/fipsmodule/ecdsa/ecdsa.c
  6. 6
      crypto/fipsmodule/ecdsa/internal.h
  7. 94
      crypto/fipsmodule/self_check/self_check.c
  8. 6
      crypto/internal.h

@ -943,8 +943,9 @@ static int arbitrary_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
return ok; return ok;
} }
int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, int ec_point_mul_no_self_test(const EC_GROUP *group, EC_POINT *r,
const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx) { const BIGNUM *g_scalar, const EC_POINT *p,
const BIGNUM *p_scalar, BN_CTX *ctx) {
// Previously, this function set |r| to the point at infinity if there was // Previously, this function set |r| to the point at infinity if there was
// nothing to multiply. But, nobody should be calling this function with // nothing to multiply. But, nobody should be calling this function with
// nothing to multiply in the first place. // nothing to multiply in the first place.
@ -1010,6 +1011,13 @@ err:
return ret; return ret;
} }
int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx) {
boringssl_ensure_ecc_self_test();
return ec_point_mul_no_self_test(group, r, g_scalar, p, p_scalar, ctx);
}
int ec_point_mul_scalar_public(const EC_GROUP *group, EC_RAW_POINT *r, int ec_point_mul_scalar_public(const EC_GROUP *group, EC_RAW_POINT *r,
const EC_SCALAR *g_scalar, const EC_RAW_POINT *p, const EC_SCALAR *g_scalar, const EC_RAW_POINT *p,
const EC_SCALAR *p_scalar) { const EC_SCALAR *p_scalar) {

@ -439,6 +439,8 @@ int EC_KEY_generate_key(EC_KEY *key) {
} }
int EC_KEY_generate_key_fips(EC_KEY *eckey) { int EC_KEY_generate_key_fips(EC_KEY *eckey) {
boringssl_ensure_ecc_self_test();
if (EC_KEY_generate_key(eckey) && EC_KEY_check_fips(eckey)) { if (EC_KEY_generate_key(eckey) && EC_KEY_check_fips(eckey)) {
return 1; return 1;
} }

@ -301,6 +301,13 @@ int ec_jacobian_to_affine_batch(const EC_GROUP *group, EC_AFFINE *out,
int ec_point_set_affine_coordinates(const EC_GROUP *group, EC_AFFINE *out, int ec_point_set_affine_coordinates(const EC_GROUP *group, EC_AFFINE *out,
const EC_FELEM *x, const EC_FELEM *y); const EC_FELEM *x, const EC_FELEM *y);
// ec_point_mul_no_self_test does the same as |EC_POINT_mul|, but doesn't try to
// run the self-test first. This is for use in the self tests themselves, to
// prevent an infinite loop.
int ec_point_mul_no_self_test(const EC_GROUP *group, EC_POINT *r,
const BIGNUM *g_scalar, const EC_POINT *p,
const BIGNUM *p_scalar, BN_CTX *ctx);
// ec_point_mul_scalar sets |r| to |p| * |scalar|. Both inputs are considered // ec_point_mul_scalar sets |r| to |p| * |scalar|. Both inputs are considered
// secret. // secret.
int ec_point_mul_scalar(const EC_GROUP *group, EC_RAW_POINT *r, int ec_point_mul_scalar(const EC_GROUP *group, EC_RAW_POINT *r,

@ -75,10 +75,13 @@
#include <openssl/sha.h> #include <openssl/sha.h>
#include "../ec/internal.h" #include "../ec/internal.h"
#include "../../internal.h"
int ECDH_compute_key_fips(uint8_t *out, size_t out_len, const EC_POINT *pub_key, int ECDH_compute_key_fips(uint8_t *out, size_t out_len, const EC_POINT *pub_key,
const EC_KEY *priv_key) { const EC_KEY *priv_key) {
boringssl_ensure_ecc_self_test();
if (priv_key->priv_key == NULL) { if (priv_key->priv_key == NULL) {
OPENSSL_PUT_ERROR(ECDH, ECDH_R_NO_PRIVATE_VALUE); OPENSSL_PUT_ERROR(ECDH, ECDH_R_NO_PRIVATE_VALUE);
return 0; return 0;

@ -151,7 +151,7 @@ int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) {
return 1; return 1;
} }
int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, int ecdsa_do_verify_no_self_test(const uint8_t *digest, size_t digest_len,
const ECDSA_SIG *sig, const EC_KEY *eckey) { const ECDSA_SIG *sig, const EC_KEY *eckey) {
const EC_GROUP *group = EC_KEY_get0_group(eckey); const EC_GROUP *group = EC_KEY_get0_group(eckey);
const EC_POINT *pub_key = EC_KEY_get0_public_key(eckey); const EC_POINT *pub_key = EC_KEY_get0_public_key(eckey);
@ -198,6 +198,13 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
return 1; return 1;
} }
int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
const ECDSA_SIG *sig, const EC_KEY *eckey) {
boringssl_ensure_ecc_self_test();
return ecdsa_do_verify_no_self_test(digest, digest_len, sig, eckey);
}
static ECDSA_SIG *ecdsa_sign_impl(const EC_GROUP *group, int *out_retry, static ECDSA_SIG *ecdsa_sign_impl(const EC_GROUP *group, int *out_retry,
const EC_SCALAR *priv_key, const EC_SCALAR *k, const EC_SCALAR *priv_key, const EC_SCALAR *k,
const uint8_t *digest, size_t digest_len) { const uint8_t *digest, size_t digest_len) {
@ -292,12 +299,16 @@ ECDSA_SIG *ecdsa_sign_with_nonce_for_known_answer_test(const uint8_t *digest,
ECDSA_SIG *ECDSA_sign_with_nonce_and_leak_private_key_for_testing( ECDSA_SIG *ECDSA_sign_with_nonce_and_leak_private_key_for_testing(
const uint8_t *digest, size_t digest_len, const EC_KEY *eckey, const uint8_t *digest, size_t digest_len, const EC_KEY *eckey,
const uint8_t *nonce, size_t nonce_len) { const uint8_t *nonce, size_t nonce_len) {
boringssl_ensure_ecc_self_test();
return ecdsa_sign_with_nonce_for_known_answer_test(digest, digest_len, eckey, return ecdsa_sign_with_nonce_for_known_answer_test(digest, digest_len, eckey,
nonce, nonce_len); nonce, nonce_len);
} }
ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len, ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
const EC_KEY *eckey) { const EC_KEY *eckey) {
boringssl_ensure_ecc_self_test();
if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
return NULL; return NULL;

@ -31,6 +31,12 @@ ECDSA_SIG *ecdsa_sign_with_nonce_for_known_answer_test(const uint8_t *digest,
const uint8_t *nonce, const uint8_t *nonce,
size_t nonce_len); size_t nonce_len);
// ecdsa_do_verify_no_self_test does the same as |ECDSA_do_verify|, but doesn't
// try to run the self-test first. This is for use in the self tests themselves,
// to prevent an infinite loop.
int ecdsa_do_verify_no_self_test(const uint8_t *digest, size_t digest_len,
const ECDSA_SIG *sig, const EC_KEY *eckey);
#if defined(__cplusplus) #if defined(__cplusplus)
} }

@ -400,28 +400,7 @@ err:
return ret; return ret;
} }
#if defined(BORINGSSL_FIPS) static int boringssl_self_test_ecc(void) {
static void run_self_test_rsa(void) {
if (!boringssl_self_test_rsa()) {
BORINGSSL_FIPS_abort();
}
}
DEFINE_STATIC_ONCE(g_self_test_once_rsa);
void boringssl_ensure_rsa_self_test(void) {
CRYPTO_once(g_self_test_once_rsa_bss_get(), run_self_test_rsa);
}
#endif // BORINGSSL_FIPS
// Startup self tests.
//
// These tests are run at process start when in FIPS mode.
static int boringssl_self_test_slow(void) {
int ret = 0; int ret = 0;
EC_KEY *ec_key = NULL; EC_KEY *ec_key = NULL;
EC_GROUP *ec_group = NULL; EC_GROUP *ec_group = NULL;
@ -429,8 +408,6 @@ static int boringssl_self_test_slow(void) {
EC_POINT *ec_point_out = NULL; EC_POINT *ec_point_out = NULL;
BIGNUM *ec_scalar = NULL; BIGNUM *ec_scalar = NULL;
ECDSA_SIG *sig = NULL; ECDSA_SIG *sig = NULL;
DH *dh = NULL;
BIGNUM *ffdhe2048_value = NULL;
ec_key = self_test_ecdsa_key(); ec_key = self_test_ecdsa_key();
if (ec_key == NULL) { if (ec_key == NULL) {
@ -487,8 +464,9 @@ static int boringssl_self_test_slow(void) {
ECDSA_SIG_free(sig); ECDSA_SIG_free(sig);
sig = parse_ecdsa_sig(kECDSAVerifySig, sizeof(kECDSAVerifySig)); sig = parse_ecdsa_sig(kECDSAVerifySig, sizeof(kECDSAVerifySig));
if (!sig || !ECDSA_do_verify(kECDSAVerifyDigest, sizeof(kECDSAVerifyDigest), if (!sig ||
sig, ec_key)) { !ecdsa_do_verify_no_self_test(kECDSAVerifyDigest,
sizeof(kECDSAVerifyDigest), sig, ec_key)) {
fprintf(stderr, "ECDSA-verify KAT failed.\n"); fprintf(stderr, "ECDSA-verify KAT failed.\n");
goto err; goto err;
} }
@ -533,8 +511,8 @@ static int boringssl_self_test_slow(void) {
!EC_POINT_oct2point(ec_group, ec_point_in, kP256Point, sizeof(kP256Point), !EC_POINT_oct2point(ec_group, ec_point_in, kP256Point, sizeof(kP256Point),
NULL) || NULL) ||
!BN_bin2bn(kP256Scalar, sizeof(kP256Scalar), ec_scalar) || !BN_bin2bn(kP256Scalar, sizeof(kP256Scalar), ec_scalar) ||
!EC_POINT_mul(ec_group, ec_point_out, NULL, ec_point_in, ec_scalar, !ec_point_mul_no_self_test(ec_group, ec_point_out, NULL, ec_point_in,
NULL) || ec_scalar, NULL) ||
!EC_POINT_point2oct(ec_group, ec_point_out, POINT_CONVERSION_UNCOMPRESSED, !EC_POINT_point2oct(ec_group, ec_point_out, POINT_CONVERSION_UNCOMPRESSED,
z_comp_result, sizeof(z_comp_result), NULL) || z_comp_result, sizeof(z_comp_result), NULL) ||
!check_test(kP256PointResult, z_comp_result, sizeof(z_comp_result), !check_test(kP256PointResult, z_comp_result, sizeof(z_comp_result),
@ -543,6 +521,57 @@ static int boringssl_self_test_slow(void) {
goto err; goto err;
} }
ret = 1;
err:
EC_KEY_free(ec_key);
EC_POINT_free(ec_point_in);
EC_POINT_free(ec_point_out);
EC_GROUP_free(ec_group);
BN_free(ec_scalar);
ECDSA_SIG_free(sig);
return ret;
}
#if defined(BORINGSSL_FIPS)
static void run_self_test_rsa(void) {
if (!boringssl_self_test_rsa()) {
BORINGSSL_FIPS_abort();
}
}
DEFINE_STATIC_ONCE(g_self_test_once_rsa);
void boringssl_ensure_rsa_self_test(void) {
CRYPTO_once(g_self_test_once_rsa_bss_get(), run_self_test_rsa);
}
static void run_self_test_ecc(void) {
if (!boringssl_self_test_ecc()) {
BORINGSSL_FIPS_abort();
}
}
DEFINE_STATIC_ONCE(g_self_test_once_ecc);
void boringssl_ensure_ecc_self_test(void) {
CRYPTO_once(g_self_test_once_ecc_bss_get(), run_self_test_ecc);
}
#endif // BORINGSSL_FIPS
// Startup self tests.
//
// These tests are run at process start when in FIPS mode.
static int boringssl_self_test_slow(void) {
int ret = 0;
DH *dh = NULL;
BIGNUM *ffdhe2048_value = NULL;
// FFC Diffie-Hellman KAT // FFC Diffie-Hellman KAT
// kFFDHE2048PublicValueData is an arbitrary public value, mod // kFFDHE2048PublicValueData is an arbitrary public value, mod
@ -608,12 +637,6 @@ static int boringssl_self_test_slow(void) {
ret = 1; ret = 1;
err: err:
EC_KEY_free(ec_key);
EC_POINT_free(ec_point_in);
EC_POINT_free(ec_point_out);
EC_GROUP_free(ec_group);
BN_free(ec_scalar);
ECDSA_SIG_free(sig);
DH_free(dh); DH_free(dh);
BN_free(ffdhe2048_value); BN_free(ffdhe2048_value);
@ -909,7 +932,8 @@ int BORINGSSL_self_test(void) {
if (!boringssl_self_test_fast() || if (!boringssl_self_test_fast() ||
!boringssl_self_test_slow() || !boringssl_self_test_slow() ||
// When requested to run self tests, also run the lazy tests. // When requested to run self tests, also run the lazy tests.
!boringssl_self_test_rsa()) { !boringssl_self_test_rsa() ||
!boringssl_self_test_ecc()) {
return 0; return 0;
} }

@ -952,11 +952,17 @@ int boringssl_self_test_startup(void);
// unsuccessful. // unsuccessful.
void boringssl_ensure_rsa_self_test(void); void boringssl_ensure_rsa_self_test(void);
// boringssl_ensure_ecc_self_test checks whether the ECDSA and ECDH self-test
// has been run in this address space. If not, it runs it and crashes the
// address space if unsuccessful.
void boringssl_ensure_ecc_self_test(void);
#else #else
// Outside of FIPS mode, the lazy tests are no-ops. // Outside of FIPS mode, the lazy tests are no-ops.
OPENSSL_INLINE void boringssl_ensure_rsa_self_test(void) {} OPENSSL_INLINE void boringssl_ensure_rsa_self_test(void) {}
OPENSSL_INLINE void boringssl_ensure_ecc_self_test(void) {}
#endif // FIPS #endif // FIPS

Loading…
Cancel
Save