Some RSA private keys are specified with only n, e and d. Although we can use these keys directly, it's nice to have a uniform representation that includes the precomputed CRT values. This change adds a function that can recover the primes from a minimal private key of that form.kris/onging/CECPQ3_patch15
@@ -367,6 +367,12 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator, | |||
* remainder or (BN_ULONG)-1 on error. */ | |||
BN_ULONG BN_div_word(BIGNUM *numerator, BN_ULONG divisor); | |||
/* BN_sqrt sets |*out_sqrt| (which may be the same |BIGNUM| as |in|) to the | |||
* square root of |in|, using |ctx|. It returns one on success or zero on | |||
* error. Negative numbers and non-square numbers will result in an error with | |||
* appropriate errors on the error queue. */ | |||
int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx); | |||
/* Comparison functions */ | |||
@@ -781,6 +787,7 @@ unsigned BN_num_bits_word(BN_ULONG l); | |||
#define BN_F_BN_mod_inverse_no_branch 121 | |||
#define BN_F_BN_generate_dsa_nonce 122 | |||
#define BN_F_BN_generate_prime_ex 123 | |||
#define BN_F_BN_sqrt 124 | |||
#define BN_R_NOT_A_SQUARE 100 | |||
#define BN_R_TOO_MANY_ITERATIONS 101 | |||
#define BN_R_INPUT_NOT_REDUCED 102 | |||
@@ -797,5 +804,6 @@ unsigned BN_num_bits_word(BN_ULONG l); | |||
#define BN_R_BIGNUM_TOO_LONG 113 | |||
#define BN_R_PRIVATE_KEY_TOO_LARGE 114 | |||
#define BN_R_BITS_TOO_SMALL 115 | |||
#define BN_R_NEGATIVE_NUMBER 116 | |||
#endif /* OPENSSL_HEADER_BN_H */ |
@@ -38,6 +38,7 @@ const ERR_STRING_DATA BN_error_string_data[] = { | |||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_new, 0), "BN_new"}, | |||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_rand, 0), "BN_rand"}, | |||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_rand_range, 0), "BN_rand_range"}, | |||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_sqrt, 0), "BN_sqrt"}, | |||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_usub, 0), "BN_usub"}, | |||
{ERR_PACK(ERR_LIB_BN, BN_F_bn_wexpand, 0), "bn_wexpand"}, | |||
{ERR_PACK(ERR_LIB_BN, BN_F_mod_exp_recp, 0), "mod_exp_recp"}, | |||
@@ -50,6 +51,7 @@ const ERR_STRING_DATA BN_error_string_data[] = { | |||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA), "EXPAND_ON_STATIC_BIGNUM_DATA"}, | |||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_INPUT_NOT_REDUCED), "INPUT_NOT_REDUCED"}, | |||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_INVALID_RANGE), "INVALID_RANGE"}, | |||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_NEGATIVE_NUMBER), "NEGATIVE_NUMBER"}, | |||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_NOT_A_SQUARE), "NOT_A_SQUARE"}, | |||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_NOT_INITIALIZED), "NOT_INITIALIZED"}, | |||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_NO_INVERSE), "NO_INVERSE"}, | |||
@@ -69,9 +69,10 @@ | |||
#include <stdio.h> | |||
#include <openssl/bio.h> | |||
#include <openssl/bn.h> | |||
#include <openssl/err.h> | |||
#include <openssl/bio.h> | |||
#include <openssl/mem.h> | |||
#include "internal.h" | |||
@@ -101,6 +102,7 @@ int test_mod_sqrt(BIO *bp, BN_CTX *ctx); | |||
static int test_exp_mod_zero(); | |||
int test_small_prime(BIO *bp,BN_CTX *ctx); | |||
int test_mod_exp_mont5(BIO *bp, BN_CTX *ctx); | |||
int test_sqrt(BIO *bp, BN_CTX *ctx); | |||
#if 0 | |||
int test_gf2m_add(BIO *bp); | |||
int test_gf2m_mod(BIO *bp); | |||
@@ -269,6 +271,11 @@ int main(int argc, char *argv[]) { | |||
goto err; | |||
(void)BIO_flush(out); | |||
message(out, "BN_sqrt"); | |||
if (!test_sqrt(out, ctx)) | |||
goto err; | |||
(void)BIO_flush(out); | |||
BN_CTX_free(ctx); | |||
BIO_free(out); | |||
@@ -1289,3 +1296,46 @@ err: | |||
BN_free(&r); | |||
return ret; | |||
} | |||
int test_sqrt(BIO *bp, BN_CTX *ctx) { | |||
BIGNUM *n = BN_new(), *nn = BN_new(), *sqrt = BN_new(); | |||
unsigned i; | |||
/* Test some random squares. */ | |||
for (i = 0; i < 100; i++) { | |||
if (!BN_rand(n, 1024 /* bit length */, -1 /* no modification of top bits */, | |||
0 /* don't modify bottom bit */) || | |||
!BN_mul(nn, n, n, ctx) || | |||
!BN_sqrt(sqrt, nn, ctx)) { | |||
BIO_print_errors_fp(stderr); | |||
return 0; | |||
} | |||
if (BN_cmp(n, sqrt) != 0) { | |||
fprintf(stderr, "Bad result from BN_sqrt.\n"); | |||
return 0; | |||
} | |||
} | |||
/* Test some non-squares */ | |||
for (i = 0; i < 100; i++) { | |||
if (!BN_rand(n, 1024 /* bit length */, -1 /* no modification of top bits */, | |||
0 /* don't modify bottom bit */) || | |||
!BN_mul(nn, n, n, ctx) || | |||
!BN_add(nn, nn, BN_value_one())) { | |||
BIO_print_errors_fp(stderr); | |||
return 0; | |||
} | |||
if (BN_sqrt(sqrt, nn, ctx)) { | |||
char *nn_str = BN_bn2dec(nn); | |||
fprintf(stderr, "BIO_sqrt didn't fail on a non-square: %s\n", nn_str); | |||
OPENSSL_free(nn_str); | |||
} | |||
} | |||
BN_free(n); | |||
BN_free(sqrt); | |||
BN_free(nn); | |||
return 1; | |||
} |
@@ -428,3 +428,78 @@ end: | |||
BN_CTX_end(ctx); | |||
return ret; | |||
} | |||
int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx) { | |||
BIGNUM *estimate, *tmp, *delta, *last_delta, *tmp2; | |||
int ok = 0, last_delta_valid = 0; | |||
if (in->neg) { | |||
OPENSSL_PUT_ERROR(BN, BN_sqrt, BN_R_NEGATIVE_NUMBER); | |||
return 0; | |||
} | |||
if (BN_is_zero(in)) { | |||
BN_zero(out_sqrt); | |||
return 1; | |||
} | |||
BN_CTX_start(ctx); | |||
if (out_sqrt == in) { | |||
estimate = BN_CTX_get(ctx); | |||
} else { | |||
estimate = out_sqrt; | |||
} | |||
tmp = BN_CTX_get(ctx); | |||
last_delta = BN_CTX_get(ctx); | |||
delta = BN_CTX_get(ctx); | |||
if (estimate == NULL || tmp == NULL || last_delta == NULL || delta == NULL) { | |||
OPENSSL_PUT_ERROR(BN, BN_sqrt, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
/* We estimate that the square root of an n-bit number is 2^{n/2}. */ | |||
BN_lshift(estimate, BN_value_one(), BN_num_bits(in)/2); | |||
/* This is Newton's method for finding a root of the equation |estimate|^2 - | |||
* |in| = 0. */ | |||
for (;;) { | |||
/* |estimate| = 1/2 * (|estimate| + |in|/|estimate|) */ | |||
if (!BN_div(tmp, NULL, in, estimate, ctx) || | |||
!BN_add(tmp, tmp, estimate) || | |||
!BN_rshift1(estimate, tmp) || | |||
/* |tmp| = |estimate|^2 */ | |||
!BN_sqr(tmp, estimate, ctx) || | |||
/* |delta| = |in| - |tmp| */ | |||
!BN_sub(delta, in, tmp)) { | |||
OPENSSL_PUT_ERROR(BN, BN_sqrt, ERR_R_BN_LIB); | |||
goto err; | |||
} | |||
delta->neg = 0; | |||
/* The difference between |in| and |estimate| squared is required to always | |||
* decrease. This ensures that the loop always terminates, but I don't have | |||
* a proof that it always finds the square root for a given square. */ | |||
if (last_delta_valid && BN_cmp(delta, last_delta) >= 0) { | |||
break; | |||
} | |||
last_delta_valid = 1; | |||
tmp2 = last_delta; | |||
last_delta = delta; | |||
delta = tmp2; | |||
} | |||
if (BN_cmp(tmp, in) != 0) { | |||
OPENSSL_PUT_ERROR(BN, BN_sqrt, BN_R_NOT_A_SQUARE); | |||
goto err; | |||
} | |||
ok = 1; | |||
err: | |||
if (ok && out_sqrt == in) { | |||
BN_copy(out_sqrt, estimate); | |||
} | |||
BN_CTX_end(ctx); | |||
return ok; | |||
} |
@@ -486,3 +486,141 @@ out: | |||
} | |||
return ret; | |||
} | |||
static void bn_free_and_null(BIGNUM **bn) { | |||
if (*bn == NULL) { | |||
return; | |||
} | |||
BN_free(*bn); | |||
*bn = NULL; | |||
} | |||
int RSA_recover_crt_params(RSA *rsa) { | |||
BN_CTX *ctx; | |||
BIGNUM *totient, *rem, *multiple, *p_plus_q, *p_minus_q; | |||
int ok = 0; | |||
if (rsa->n == NULL || rsa->e == NULL || rsa->d == NULL) { | |||
OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, RSA_R_EMPTY_PUBLIC_KEY); | |||
return 0; | |||
} | |||
if (rsa->p || rsa->q || rsa->dmp1 || rsa->dmq1 || rsa->iqmp) { | |||
OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, | |||
RSA_R_CRT_PARAMS_ALREADY_GIVEN); | |||
return 0; | |||
} | |||
/* This uses the algorithm from section 9B of the RSA paper: | |||
* http://people.csail.mit.edu/rivest/Rsapaper.pdf */ | |||
ctx = BN_CTX_new(); | |||
if (ctx == NULL) { | |||
OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_MALLOC_FAILURE); | |||
return 0; | |||
} | |||
BN_CTX_start(ctx); | |||
totient = BN_CTX_get(ctx); | |||
rem = BN_CTX_get(ctx); | |||
multiple = BN_CTX_get(ctx); | |||
p_plus_q = BN_CTX_get(ctx); | |||
p_minus_q = BN_CTX_get(ctx); | |||
if (totient == NULL || rem == NULL || multiple == NULL || p_plus_q == NULL || | |||
p_minus_q == NULL) { | |||
OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
/* ed-1 is a small multiple of φ(n). */ | |||
if (!BN_mul(totient, rsa->e, rsa->d, ctx) || | |||
!BN_sub_word(totient, 1) || | |||
/* φ(n) = | |||
* pq - p - q + 1 = | |||
* n - (p + q) + 1 | |||
* | |||
* Thus n is a reasonable estimate for φ(n). So, (ed-1)/n will be very | |||
* close. But, when we calculate the quotient, we'll be truncating it | |||
* because we discard the remainder. Thus (ed-1)/multiple will be >= n, | |||
* which the totient cannot be. So we add one to the estimate. | |||
* | |||
* Consider ed-1 as: | |||
* | |||
* multiple * (n - (p+q) + 1) = | |||
* multiple*n - multiple*(p+q) + multiple | |||
* | |||
* When we divide by n, the first term becomes multiple and, since | |||
* multiple and p+q is tiny compared to n, the second and third terms can | |||
* be ignored. Thus I claim that subtracting one from the estimate is | |||
* sufficient. */ | |||
!BN_div(multiple, NULL, totient, rsa->n, ctx) || | |||
!BN_add_word(multiple, 1) || | |||
!BN_div(totient, rem, totient, multiple, ctx)) { | |||
OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_BN_LIB); | |||
goto err; | |||
} | |||
if (!BN_is_zero(rem)) { | |||
OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, RSA_R_BAD_RSA_PARAMETERS); | |||
goto err; | |||
} | |||
rsa->p = BN_new(); | |||
rsa->q = BN_new(); | |||
rsa->dmp1 = BN_new(); | |||
rsa->dmq1 = BN_new(); | |||
rsa->iqmp = BN_new(); | |||
if (rsa->p == NULL || rsa->q == NULL || rsa->dmp1 == NULL || rsa->dmq1 == | |||
NULL || rsa->iqmp == NULL) { | |||
OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
/* φ(n) = n - (p + q) + 1 => | |||
* n - totient + 1 = p + q */ | |||
if (!BN_sub(p_plus_q, rsa->n, totient) || | |||
!BN_add_word(p_plus_q, 1) || | |||
/* p - q = sqrt((p+q)^2 - 4n) */ | |||
!BN_sqr(rem, p_plus_q, ctx) || | |||
!BN_lshift(multiple, rsa->n, 2) || | |||
!BN_sub(rem, rem, multiple) || | |||
!BN_sqrt(p_minus_q, rem, ctx) || | |||
/* q is 1/2 (p+q)-(p-q) */ | |||
!BN_sub(rsa->q, p_plus_q, p_minus_q) || | |||
!BN_rshift1(rsa->q, rsa->q) || | |||
!BN_div(rsa->p, NULL, rsa->n, rsa->q, ctx) || | |||
!BN_mul(multiple, rsa->p, rsa->q, ctx)) { | |||
OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_BN_LIB); | |||
goto err; | |||
} | |||
if (BN_cmp(multiple, rsa->n) != 0) { | |||
OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, RSA_R_INTERNAL_ERROR); | |||
goto err; | |||
} | |||
if (!BN_sub(rem, rsa->p, BN_value_one()) || | |||
!BN_mod(rsa->dmp1, rsa->d, rem, ctx) || | |||
!BN_sub(rem, rsa->q, BN_value_one()) || | |||
!BN_mod(rsa->dmq1, rsa->d, rem, ctx) || | |||
!BN_mod_inverse(rsa->iqmp, rsa->q, rsa->p, ctx)) { | |||
OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_BN_LIB); | |||
goto err; | |||
} | |||
ok = 1; | |||
err: | |||
BN_CTX_end(ctx); | |||
BN_CTX_free(ctx); | |||
if (!ok) { | |||
bn_free_and_null(&rsa->p); | |||
bn_free_and_null(&rsa->q); | |||
bn_free_and_null(&rsa->dmp1); | |||
bn_free_and_null(&rsa->dmq1); | |||
bn_free_and_null(&rsa->iqmp); | |||
} | |||
return ok; | |||
} |
@@ -244,6 +244,13 @@ RSA *RSAPublicKey_dup(const RSA *rsa); | |||
* |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */ | |||
RSA *RSAPrivateKey_dup(const RSA *rsa); | |||
/* RSA_recover_crt_params uses |rsa->n|, |rsa->d| and |rsa->e| in order to | |||
* calculate the two primes used and thus the precomputed, CRT values. These | |||
* values are set in the |p|, |q|, |dmp1|, |dmq1| and |iqmp| members of |rsa|, | |||
* which must be |NULL| on entry. It returns one on success and zero | |||
* otherwise. */ | |||
int RSA_recover_crt_params(RSA *rsa); | |||
/* ASN.1 functions. */ | |||
@@ -421,6 +428,7 @@ struct rsa_st { | |||
#define RSA_F_BN_BLINDING_create_param 124 | |||
#define RSA_F_decrypt 125 | |||
#define RSA_F_RSA_padding_check_PKCS1_type_2 126 | |||
#define RSA_F_RSA_recover_crt_params 127 | |||
#define RSA_R_INVALID_MESSAGE_LENGTH 100 | |||
#define RSA_R_DATA_GREATER_THAN_MOD_LEN 101 | |||
#define RSA_R_NO_PUBLIC_EXPONENT 102 | |||
@@ -456,5 +464,8 @@ struct rsa_st { | |||
#define RSA_R_BAD_SIGNATURE 132 | |||
#define RSA_R_BN_NOT_INITIALIZED 133 | |||
#define RSA_R_PKCS_DECODING_ERROR 134 | |||
#define RSA_R_BAD_RSA_PARAMETERS 135 | |||
#define RSA_R_INTERNAL_ERROR 136 | |||
#define RSA_R_CRT_PARAMS_ALREADY_GIVEN 137 | |||
#endif /* OPENSSL_HEADER_RSA_H */ |
@@ -34,6 +34,7 @@ const ERR_STRING_DATA RSA_error_string_data[] = { | |||
{ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_check_PKCS1_type_2, 0), "RSA_padding_check_PKCS1_type_2"}, | |||
{ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_check_SSLv23, 0), "RSA_padding_check_SSLv23"}, | |||
{ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_check_none, 0), "RSA_padding_check_none"}, | |||
{ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_recover_crt_params, 0), "RSA_recover_crt_params"}, | |||
{ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_sign, 0), "RSA_sign"}, | |||
{ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_verify, 0), "RSA_verify"}, | |||
{ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_verify_PKCS1_PSS_mgf1, 0), "RSA_verify_PKCS1_PSS_mgf1"}, | |||
@@ -47,10 +48,12 @@ const ERR_STRING_DATA RSA_error_string_data[] = { | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BAD_E_VALUE), "BAD_E_VALUE"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BAD_FIXED_HEADER_DECRYPT), "BAD_FIXED_HEADER_DECRYPT"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BAD_PAD_BYTE_COUNT), "BAD_PAD_BYTE_COUNT"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BAD_RSA_PARAMETERS), "BAD_RSA_PARAMETERS"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BAD_SIGNATURE), "BAD_SIGNATURE"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BLOCK_TYPE_IS_NOT_01), "BLOCK_TYPE_IS_NOT_01"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BLOCK_TYPE_IS_NOT_02), "BLOCK_TYPE_IS_NOT_02"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BN_NOT_INITIALIZED), "BN_NOT_INITIALIZED"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_CRT_PARAMS_ALREADY_GIVEN), "CRT_PARAMS_ALREADY_GIVEN"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_GREATER_THAN_MOD_LEN), "DATA_GREATER_THAN_MOD_LEN"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_TOO_LARGE), "DATA_TOO_LARGE"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE), "DATA_TOO_LARGE_FOR_KEY_SIZE"}, | |||
@@ -60,6 +63,7 @@ const ERR_STRING_DATA RSA_error_string_data[] = { | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY), "DIGEST_TOO_BIG_FOR_RSA_KEY"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_EMPTY_PUBLIC_KEY), "EMPTY_PUBLIC_KEY"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_FIRST_OCTET_INVALID), "FIRST_OCTET_INVALID"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INTERNAL_ERROR), "INTERNAL_ERROR"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_MESSAGE_LENGTH), "INVALID_MESSAGE_LENGTH"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_KEY_SIZE_TOO_SMALL), "KEY_SIZE_TOO_SMALL"}, | |||
{ERR_PACK(ERR_LIB_RSA, 0, RSA_R_LAST_OCTET_INVALID), "LAST_OCTET_INVALID"}, | |||
@@ -276,6 +276,63 @@ err: | |||
return ret; | |||
} | |||
static int test_recover_crt_params() { | |||
RSA *key1, *key2; | |||
BIGNUM *e = BN_new(); | |||
uint8_t buf[128]; | |||
unsigned buf_len = sizeof(buf); | |||
const uint8_t kDummyHash[16] = {0}; | |||
unsigned i; | |||
BN_set_word(e, RSA_F4); | |||
ERR_clear_error(); | |||
for (i = 0; i < 1; i++) { | |||
key1 = RSA_new(); | |||
if (!RSA_generate_key_ex(key1, 512, e, NULL)) { | |||
fprintf(stderr, "RSA_generate_key_ex failed.\n"); | |||
BIO_print_errors_fp(stderr); | |||
return 0; | |||
} | |||
key2 = RSA_new(); | |||
key2->n = BN_dup(key1->n); | |||
key2->e = BN_dup(key1->e); | |||
key2->d = BN_dup(key1->d); | |||
RSA_free(key1); | |||
if (!RSA_recover_crt_params(key2)) { | |||
fprintf(stderr, "RSA_recover_crt_params failed.\n"); | |||
BIO_print_errors_fp(stderr); | |||
return 0; | |||
} | |||
if (RSA_size(key2) > buf_len) { | |||
return 0; | |||
} | |||
if (!RSA_sign(NID_md5, kDummyHash, sizeof(kDummyHash), buf, &buf_len, | |||
key2)) { | |||
fprintf(stderr, "RSA_sign failed with recovered key.\n"); | |||
BIO_print_errors_fp(stderr); | |||
return 0; | |||
} | |||
if (!RSA_verify(NID_md5, kDummyHash, sizeof(kDummyHash), buf, buf_len, | |||
key2)) { | |||
fprintf(stderr, "RSA_verify failed with recovered key.\n"); | |||
BIO_print_errors_fp(stderr); | |||
return 0; | |||
} | |||
RSA_free(key2); | |||
} | |||
BN_free(e); | |||
return 1; | |||
} | |||
int main(int argc, char *argv[]) { | |||
int err = 0; | |||
int v; | |||
@@ -380,7 +437,8 @@ int main(int argc, char *argv[]) { | |||
} | |||
if (err != 0 || | |||
!test_only_d_given()) { | |||
!test_only_d_given() || | |||
!test_recover_crt_params()) { | |||
err = 1; | |||
} | |||