Add function to recover RSA CRT params.

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.
diff --git a/crypto/bn/bn.h b/crypto/bn/bn.h
index 23fca81..40ae790 100644
--- a/crypto/bn/bn.h
+++ b/crypto/bn/bn.h
@@ -367,6 +367,12 @@
  * 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 @@
 #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 @@
 #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 */
diff --git a/crypto/bn/bn_error.c b/crypto/bn/bn_error.c
index 679033b..e0404d9 100644
--- a/crypto/bn/bn_error.c
+++ b/crypto/bn/bn_error.c
@@ -38,6 +38,7 @@
   {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 @@
   {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"},
diff --git a/crypto/bn/bn_test.c b/crypto/bn/bn_test.c
index aa9cecc..45303fc 100644
--- a/crypto/bn/bn_test.c
+++ b/crypto/bn/bn_test.c
@@ -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 @@
 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 @@
     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 @@
   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;
+}
diff --git a/crypto/bn/sqrt.c b/crypto/bn/sqrt.c
index 3ec763b..07041f9 100644
--- a/crypto/bn/sqrt.c
+++ b/crypto/bn/sqrt.c
@@ -428,3 +428,78 @@
   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;
+}
diff --git a/crypto/rsa/rsa.c b/crypto/rsa/rsa.c
index 061bc49c..583e667 100644
--- a/crypto/rsa/rsa.c
+++ b/crypto/rsa/rsa.c
@@ -486,3 +486,141 @@
   }
   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;
+}
diff --git a/crypto/rsa/rsa.h b/crypto/rsa/rsa.h
index b60a59c..403e833 100644
--- a/crypto/rsa/rsa.h
+++ b/crypto/rsa/rsa.h
@@ -244,6 +244,13 @@
  * |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 @@
 #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 @@
 #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 */
diff --git a/crypto/rsa/rsa_error.c b/crypto/rsa/rsa_error.c
index a165e16..6bcf850 100644
--- a/crypto/rsa/rsa_error.c
+++ b/crypto/rsa/rsa_error.c
@@ -34,6 +34,7 @@
   {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 @@
   {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 @@
   {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"},
diff --git a/crypto/rsa/rsa_test.c b/crypto/rsa/rsa_test.c
index e8d6d20..bd8e492 100644
--- a/crypto/rsa/rsa_test.c
+++ b/crypto/rsa/rsa_test.c
@@ -276,6 +276,63 @@
   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 @@
   }
 
   if (err != 0 ||
-      !test_only_d_given()) {
+      !test_only_d_given() ||
+      !test_recover_crt_params()) {
     err = 1;
   }