int RSA_check_fips(RSA *key) { if (RSA_is_opaque(key)) { /* Opaque keys can't be checked. */ OPENSSL_PUT_ERROR(RSA, RSA_R_PUBLIC_KEY_VALIDATION_FAILED); return 0; } if (!RSA_check_key(key)) { return 0; } BN_CTX *ctx = BN_CTX_new(); if (ctx == NULL) { OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); return 0; } BIGNUM small_gcd; BN_init(&small_gcd); int ret = 1; /* Perform partial public key validation of RSA keys (SP 800-89 5.3.3). */ enum bn_primality_result_t primality_result; if (BN_num_bits(key->e) <= 16 || BN_num_bits(key->e) > 256 || !BN_is_odd(key->n) || !BN_is_odd(key->e) || !BN_gcd(&small_gcd, key->n, g_small_factors(), ctx) || !BN_is_one(&small_gcd) || !BN_enhanced_miller_rabin_primality_test(&primality_result, key->n, BN_prime_checks, ctx, NULL) || primality_result != bn_non_prime_power_composite) { OPENSSL_PUT_ERROR(RSA, RSA_R_PUBLIC_KEY_VALIDATION_FAILED); ret = 0; } BN_free(&small_gcd); BN_CTX_free(ctx); if (!ret || key->d == NULL || key->p == NULL) { /* On a failure or on only a public key, there's nothing else can be * checked. */ return ret; } /* FIPS pairwise consistency test (FIPS 140-2 4.9.2). Per FIPS 140-2 IG, * section 9.9, it is not known whether |rsa| will be used for signing or * encryption, so either pair-wise consistency self-test is acceptable. We * perform a signing test. */ uint8_t data[32] = {0}; unsigned sig_len = RSA_size(key); uint8_t *sig = OPENSSL_malloc(sig_len); if (sig == NULL) { OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); return 0; } if (!RSA_sign(NID_sha256, data, sizeof(data), sig, &sig_len, key)) { OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); ret = 0; goto cleanup; } #if defined(BORINGSSL_FIPS_BREAK_RSA_PWCT) data[0] = ~data[0]; #endif if (!RSA_verify(NID_sha256, data, sizeof(data), sig, sig_len, key)) { OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); ret = 0; } cleanup: OPENSSL_free(sig); return ret; }
int RSA_check_key(const RSA *key) { BIGNUM n, pm1, qm1, lcm, dmp1, dmq1, iqmp_times_q; BN_CTX *ctx; int ok = 0, has_crt_values; if (RSA_is_opaque(key)) { // Opaque keys can't be checked. return 1; } if ((key->p != NULL) != (key->q != NULL)) { OPENSSL_PUT_ERROR(RSA, RSA_R_ONLY_ONE_OF_P_Q_GIVEN); return 0; } if (!key->n || !key->e) { OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING); return 0; } if (!key->d || !key->p) { // For a public key, or without p and q, there's nothing that can be // checked. return 1; } ctx = BN_CTX_new(); if (ctx == NULL) { OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); return 0; } BN_init(&n); BN_init(&pm1); BN_init(&qm1); BN_init(&lcm); BN_init(&dmp1); BN_init(&dmq1); BN_init(&iqmp_times_q); int d_ok; if (!bn_mul_consttime(&n, key->p, key->q, ctx) || // lcm = lcm(p, q) !bn_usub_consttime(&pm1, key->p, BN_value_one()) || !bn_usub_consttime(&qm1, key->q, BN_value_one()) || !bn_lcm_consttime(&lcm, &pm1, &qm1, ctx) || // Other implementations use the Euler totient rather than the Carmichael // totient, so allow unreduced |key->d|. !check_mod_inverse(&d_ok, key->e, key->d, &lcm, 0 /* don't require reduced */, ctx)) { OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); goto out; } if (BN_cmp(&n, key->n) != 0) { OPENSSL_PUT_ERROR(RSA, RSA_R_N_NOT_EQUAL_P_Q); goto out; } if (!d_ok) { OPENSSL_PUT_ERROR(RSA, RSA_R_D_E_NOT_CONGRUENT_TO_1); goto out; } if (BN_is_negative(key->d) || BN_cmp(key->d, key->n) >= 0) { OPENSSL_PUT_ERROR(RSA, RSA_R_D_OUT_OF_RANGE); goto out; } has_crt_values = key->dmp1 != NULL; if (has_crt_values != (key->dmq1 != NULL) || has_crt_values != (key->iqmp != NULL)) { OPENSSL_PUT_ERROR(RSA, RSA_R_INCONSISTENT_SET_OF_CRT_VALUES); goto out; } if (has_crt_values) { int dmp1_ok, dmq1_ok, iqmp_ok; if (!check_mod_inverse(&dmp1_ok, key->e, key->dmp1, &pm1, 1 /* check reduced */, ctx) || !check_mod_inverse(&dmq1_ok, key->e, key->dmq1, &qm1, 1 /* check reduced */, ctx) || !check_mod_inverse(&iqmp_ok, key->q, key->iqmp, key->p, 1 /* check reduced */, ctx)) { OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); goto out; } if (!dmp1_ok || !dmq1_ok || !iqmp_ok) { OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_VALUES_INCORRECT); goto out; } } ok = 1; out: BN_free(&n); BN_free(&pm1); BN_free(&qm1); BN_free(&lcm); BN_free(&dmp1); BN_free(&dmq1); BN_free(&iqmp_times_q); BN_CTX_free(ctx); return ok; }
int RSA_check_key(const RSA *key) { BIGNUM n, pm1, qm1, lcm, gcd, de, dmp1, dmq1, iqmp_times_q; BN_CTX *ctx; int ok = 0, has_crt_values; if (RSA_is_opaque(key)) { /* Opaque keys can't be checked. */ return 1; } if ((key->p != NULL) != (key->q != NULL)) { OPENSSL_PUT_ERROR(RSA, RSA_R_ONLY_ONE_OF_P_Q_GIVEN); return 0; } if (!key->n || !key->e) { OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING); return 0; } if (!key->d || !key->p) { /* For a public key, or without p and q, there's nothing that can be * checked. */ return 1; } ctx = BN_CTX_new(); if (ctx == NULL) { OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); return 0; } BN_init(&n); BN_init(&pm1); BN_init(&qm1); BN_init(&lcm); BN_init(&gcd); BN_init(&de); BN_init(&dmp1); BN_init(&dmq1); BN_init(&iqmp_times_q); if (!BN_mul(&n, key->p, key->q, ctx) || /* lcm = lcm(p, q) */ !BN_sub(&pm1, key->p, BN_value_one()) || !BN_sub(&qm1, key->q, BN_value_one()) || !BN_mul(&lcm, &pm1, &qm1, ctx) || !BN_gcd(&gcd, &pm1, &qm1, ctx)) { OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); goto out; } if (!BN_div(&lcm, NULL, &lcm, &gcd, ctx) || !BN_gcd(&gcd, &pm1, &qm1, ctx) || /* de = d*e mod lcm(p, q). */ !BN_mod_mul(&de, key->d, key->e, &lcm, ctx)) { OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); goto out; } if (BN_cmp(&n, key->n) != 0) { OPENSSL_PUT_ERROR(RSA, RSA_R_N_NOT_EQUAL_P_Q); goto out; } if (!BN_is_one(&de)) { OPENSSL_PUT_ERROR(RSA, RSA_R_D_E_NOT_CONGRUENT_TO_1); goto out; } has_crt_values = key->dmp1 != NULL; if (has_crt_values != (key->dmq1 != NULL) || has_crt_values != (key->iqmp != NULL)) { OPENSSL_PUT_ERROR(RSA, RSA_R_INCONSISTENT_SET_OF_CRT_VALUES); goto out; } if (has_crt_values) { if (/* dmp1 = d mod (p-1) */ !BN_mod(&dmp1, key->d, &pm1, ctx) || /* dmq1 = d mod (q-1) */ !BN_mod(&dmq1, key->d, &qm1, ctx) || /* iqmp = q^-1 mod p */ !BN_mod_mul(&iqmp_times_q, key->iqmp, key->q, key->p, ctx)) { OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); goto out; } if (BN_cmp(&dmp1, key->dmp1) != 0 || BN_cmp(&dmq1, key->dmq1) != 0 || BN_cmp(key->iqmp, key->p) >= 0 || !BN_is_one(&iqmp_times_q)) { OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_VALUES_INCORRECT); goto out; } } ok = 1; out: BN_free(&n); BN_free(&pm1); BN_free(&qm1); BN_free(&lcm); BN_free(&gcd); BN_free(&de); BN_free(&dmp1); BN_free(&dmq1); BN_free(&iqmp_times_q); BN_CTX_free(ctx); return ok; }
static int rsa_opaque(const EVP_PKEY *pkey) { return RSA_is_opaque(pkey->pkey.rsa); }