Multi-prime RSA support.

RSA with more than two primes is specified in
https://tools.ietf.org/html/rfc3447, although the idea goes back far
earier than that.

This change ports some of the changes in
http://rt.openssl.org/Ticket/Display.html?id=3477&user=guest&pass=guest
to BoringSSL—specifically those bits that are under an OpenSSL license.

Change-Id: I51e8e345e2148702b8ce12e00518f6ef4683d3e1
Reviewed-on: https://boringssl-review.googlesource.com/4870
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/err/rsa.errordata b/crypto/err/rsa.errordata
index 64b390d..091d2cd 100644
--- a/crypto/err/rsa.errordata
+++ b/crypto/err/rsa.errordata
@@ -21,6 +21,7 @@
 RSA,function,120,decrypt
 RSA,function,121,encrypt
 RSA,function,122,keygen
+RSA,function,128,keygen_multiprime
 RSA,function,123,pkcs1_prefixed_msg
 RSA,function,124,private_transform
 RSA,function,125,rsa_setup_blinding
@@ -33,6 +34,7 @@
 RSA,reason,104,BAD_SIGNATURE
 RSA,reason,105,BLOCK_TYPE_IS_NOT_01
 RSA,reason,106,BN_NOT_INITIALIZED
+RSA,reason,142,CANNOT_RECOVER_MULTI_PRIME_KEY
 RSA,reason,107,CRT_PARAMS_ALREADY_GIVEN
 RSA,reason,108,CRT_VALUES_INCORRECT
 RSA,reason,109,DATA_LEN_NOT_EQUAL_TO_MOD_LEN
@@ -51,6 +53,7 @@
 RSA,reason,122,KEY_SIZE_TOO_SMALL
 RSA,reason,123,LAST_OCTET_INVALID
 RSA,reason,124,MODULUS_TOO_LARGE
+RSA,reason,141,MUST_HAVE_AT_LEAST_TWO_PRIMES
 RSA,reason,125,NO_PUBLIC_EXPONENT
 RSA,reason,126,NULL_BEFORE_BLOCK_MISSING
 RSA,reason,127,N_NOT_EQUAL_P_Q
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
index 1e2d3f6..7141ffb 100644
--- a/crypto/evp/p_rsa_asn1.c
+++ b/crypto/evp/p_rsa_asn1.c
@@ -198,6 +198,19 @@
     update_buflen(rsa->dmp1, &buf_len);
     update_buflen(rsa->dmq1, &buf_len);
     update_buflen(rsa->iqmp, &buf_len);
+
+    if (rsa->additional_primes != NULL) {
+      size_t i;
+
+      for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes);
+           i++) {
+        const RSA_additional_prime *ap =
+            sk_RSA_additional_prime_value(rsa->additional_primes, i);
+        update_buflen(ap->prime, &buf_len);
+        update_buflen(ap->exp, &buf_len);
+        update_buflen(ap->coeff, &buf_len);
+      }
+    }
   }
 
   m = (uint8_t *)OPENSSL_malloc(buf_len + 10);
@@ -215,7 +228,8 @@
   }
 
   if (include_private && rsa->d) {
-    if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) {
+    if (BIO_printf(out, "Private-Key: (%d bit)\nversion: %ld\n", mod_len,
+                   rsa->version) <= 0) {
       goto err;
     }
     str = "modulus:";
@@ -241,6 +255,28 @@
         !ASN1_bn_print(out, "coefficient:", rsa->iqmp, m, off)) {
       goto err;
     }
+
+    if (rsa->additional_primes != NULL &&
+        sk_RSA_additional_prime_num(rsa->additional_primes) > 0) {
+      size_t i;
+
+      if (BIO_printf(out, "otherPrimeInfos:\n") <= 0) {
+        goto err;
+      }
+      for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes);
+           i++) {
+        const RSA_additional_prime *ap =
+            sk_RSA_additional_prime_value(rsa->additional_primes, i);
+
+        if (BIO_printf(out, "otherPrimeInfo (prime %u):\n",
+                       (unsigned)(i + 3)) <= 0 ||
+            !ASN1_bn_print(out, "prime:", ap->prime, m, off) ||
+            !ASN1_bn_print(out, "exponent:", ap->exp, m, off) ||
+            !ASN1_bn_print(out, "coeff:", ap->coeff, m, off)) {
+          goto err;
+        }
+      }
+    }
   }
   ret = 1;
 
diff --git a/crypto/rsa/internal.h b/crypto/rsa/internal.h
index d15f2a5..d3e1d20 100644
--- a/crypto/rsa/internal.h
+++ b/crypto/rsa/internal.h
@@ -133,6 +133,26 @@
   X509_ALGOR *pSourceFunc;
 } RSA_OAEP_PARAMS;
 
+/* RSA_additional_prime contains information about the third, forth etc prime
+ * in a multi-prime RSA key. */
+typedef struct RSA_additional_prime_st {
+  BIGNUM *prime;
+  /* exp is d^{prime-1} mod prime */
+  BIGNUM *exp;
+  /* coeff is such that r×coeff ≡ 1 mod prime. */
+  BIGNUM *coeff;
+
+  /* Values below here are not in the ASN.1 serialisation. */
+
+  /* r is the product of all primes (including p and q) prior to this one. */
+  BIGNUM *r;
+  /* method_mod is managed by the |RSA_METHOD|. */
+  BN_MONT_CTX *method_mod;
+} RSA_additional_prime;
+
+void RSA_additional_prime_free(RSA_additional_prime *ap);
+
+
 #if defined(__cplusplus)
 } /* extern C */
 #endif
diff --git a/crypto/rsa/rsa.c b/crypto/rsa/rsa.c
index 17059b0..51cc790 100644
--- a/crypto/rsa/rsa.c
+++ b/crypto/rsa/rsa.c
@@ -114,6 +114,18 @@
   return rsa;
 }
 
+void RSA_additional_prime_free(RSA_additional_prime *ap) {
+  if (ap == NULL) {
+    return;
+  }
+
+  BN_clear_free(ap->prime);
+  BN_clear_free(ap->exp);
+  BN_clear_free(ap->coeff);
+  BN_clear_free(ap->r);
+  OPENSSL_free(ap);
+}
+
 void RSA_free(RSA *rsa) {
   unsigned u;
 
@@ -145,6 +157,10 @@
   }
   OPENSSL_free(rsa->blindings);
   OPENSSL_free(rsa->blindings_inuse);
+  if (rsa->additional_primes != NULL) {
+    sk_RSA_additional_prime_pop_free(rsa->additional_primes,
+                                     RSA_additional_prime_free);
+  }
   CRYPTO_MUTEX_cleanup(&rsa->lock);
   OPENSSL_free(rsa);
 }
@@ -162,6 +178,16 @@
   return RSA_default_method.keygen(rsa, bits, e_value, cb);
 }
 
+int RSA_generate_multi_prime_key(RSA *rsa, int bits, int num_primes,
+                                 BIGNUM *e_value, BN_GENCB *cb) {
+  if (rsa->meth->multi_prime_keygen) {
+    return rsa->meth->multi_prime_keygen(rsa, bits, num_primes, e_value, cb);
+  }
+
+  return RSA_default_method.multi_prime_keygen(rsa, bits, num_primes, e_value,
+                                               cb);
+}
+
 int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
                 const uint8_t *in, size_t in_len, int padding) {
   if (rsa->meth->encrypt) {
@@ -540,15 +566,37 @@
   BN_init(&dmq1);
   BN_init(&iqmp);
 
-  if (/* n = pq */
-      !BN_mul(&n, key->p, key->q, ctx) ||
-      /* lcm = lcm(p-1, q-1) */
+  if (!BN_mul(&n, key->p, key->q, ctx) ||
+      /* lcm = lcm(prime-1, for all primes) */
       !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, RSA_check_key, ERR_LIB_BN);
+    goto out;
+  }
+
+  size_t num_additional_primes = 0;
+  if (key->additional_primes != NULL) {
+    num_additional_primes = sk_RSA_additional_prime_num(key->additional_primes);
+  }
+
+  size_t i;
+  for (i = 0; i < num_additional_primes; i++) {
+    const RSA_additional_prime *ap =
+        sk_RSA_additional_prime_value(key->additional_primes, i);
+    if (!BN_mul(&n, &n, ap->prime, ctx) ||
+        !BN_sub(&pm1, ap->prime, BN_value_one()) ||
+        !BN_mul(&lcm, &lcm, &pm1, ctx) ||
+        !BN_gcd(&gcd, &gcd, &pm1, ctx)) {
+      OPENSSL_PUT_ERROR(RSA, RSA_check_key, ERR_LIB_BN);
+      goto out;
+    }
+  }
+
+  if (!BN_div(&lcm, NULL, &lcm, &gcd, ctx) ||
       !BN_gcd(&gcd, &pm1, &qm1, ctx) ||
-      !BN_div(&lcm, NULL, &lcm, &gcd, ctx) ||
-      /* de = d*e mod lcm(p-1, q-1) */
+      /* de = d*e mod lcm(prime-1, for all primes). */
       !BN_mod_mul(&de, key->d, key->e, &lcm, ctx)) {
     OPENSSL_PUT_ERROR(RSA, RSA_check_key, ERR_LIB_BN);
     goto out;
@@ -571,7 +619,7 @@
     goto out;
   }
 
-  if (has_crt_values) {
+  if (has_crt_values && num_additional_primes == 0) {
     if (/* dmp1 = d mod (p-1) */
         !BN_mod(&dmp1, key->d, &pm1, ctx) ||
         /* dmq1 = d mod (q-1) */
@@ -623,6 +671,12 @@
     return 0;
   }
 
+  if (rsa->additional_primes != NULL) {
+    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params,
+                      RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY);
+    return 0;
+  }
+
   /* This uses the algorithm from section 9B of the RSA paper:
    * http://people.csail.mit.edu/rivest/Rsapaper.pdf */
 
diff --git a/crypto/rsa/rsa_asn1.c b/crypto/rsa/rsa_asn1.c
index 924cb8a..b8f9d87 100644
--- a/crypto/rsa/rsa_asn1.c
+++ b/crypto/rsa/rsa_asn1.c
@@ -64,6 +64,11 @@
 /* Override the default free and new methods */
 static int rsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
                   void *exarg) {
+  RSA *rsa = (RSA *)*pval;
+  BN_CTX *ctx = NULL;
+  BIGNUM *product_of_primes_so_far = NULL;
+  int ret = 0;
+
   if (operation == ASN1_OP_NEW_PRE) {
     *pval = (ASN1_VALUE *)RSA_new();
     if (*pval) {
@@ -71,13 +76,48 @@
     }
     return 0;
   } else if (operation == ASN1_OP_FREE_PRE) {
-    RSA_free((RSA *)*pval);
+    RSA_free(rsa);
     *pval = NULL;
     return 2;
+  } else if (operation == ASN1_OP_D2I_POST) {
+    if (rsa->additional_primes != NULL) {
+      ctx = BN_CTX_new();
+      product_of_primes_so_far = BN_new();
+      if (ctx == NULL ||
+          product_of_primes_so_far == NULL ||
+          !BN_mul(product_of_primes_so_far, rsa->p, rsa->q, ctx)) {
+        goto err;
+      }
+
+      size_t i;
+      for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) {
+        RSA_additional_prime *ap =
+            sk_RSA_additional_prime_value(rsa->additional_primes, i);
+        ap->r = BN_dup(product_of_primes_so_far);
+        if (ap->r == NULL ||
+            !BN_mul(product_of_primes_so_far, product_of_primes_so_far,
+                    ap->prime, ctx)) {
+          goto err;
+        }
+      }
+    }
+    ret = 2;
+  } else {
+    return 1;
   }
-  return 1;
+
+err:
+  BN_CTX_free(ctx);
+  BN_free(product_of_primes_so_far);
+  return ret;
 }
 
+ASN1_SEQUENCE(RSA_additional_prime) = {
+    ASN1_SIMPLE(RSA_additional_prime, prime, BIGNUM),
+    ASN1_SIMPLE(RSA_additional_prime, exp, BIGNUM),
+    ASN1_SIMPLE(RSA_additional_prime, coeff, BIGNUM),
+} ASN1_SEQUENCE_END(RSA_additional_prime);
+
 ASN1_SEQUENCE_cb(RSAPrivateKey, rsa_cb) = {
   ASN1_SIMPLE(RSA, version, LONG),
   ASN1_SIMPLE(RSA, n, BIGNUM),
@@ -88,6 +128,7 @@
   ASN1_SIMPLE(RSA, dmp1, BIGNUM),
   ASN1_SIMPLE(RSA, dmq1, BIGNUM),
   ASN1_SIMPLE(RSA, iqmp, BIGNUM),
+  ASN1_SEQUENCE_OF_OPT(RSA, additional_primes, RSA_additional_prime),
 } ASN1_SEQUENCE_END_cb(RSA, RSAPrivateKey);
 
 ASN1_SEQUENCE_cb(RSAPublicKey, rsa_cb) = {
diff --git a/crypto/rsa/rsa_impl.c b/crypto/rsa/rsa_impl.c
index e14f0f5..95a274b 100644
--- a/crypto/rsa/rsa_impl.c
+++ b/crypto/rsa/rsa_impl.c
@@ -78,6 +78,15 @@
   BN_MONT_CTX_free(rsa->_method_mod_p);
   BN_MONT_CTX_free(rsa->_method_mod_q);
 
+  if (rsa->additional_primes != NULL) {
+    size_t i;
+    for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) {
+      RSA_additional_prime *ap =
+          sk_RSA_additional_prime_value(rsa->additional_primes, i);
+      BN_MONT_CTX_free(ap->method_mod);
+    }
+  }
+
   return 1;
 }
 
@@ -616,6 +625,11 @@
   BIGNUM local_dmp1, local_dmq1, local_c, local_r1;
   BIGNUM *dmp1, *dmq1, *c, *pr1;
   int ret = 0;
+  size_t i, num_additional_primes = 0;
+
+  if (rsa->additional_primes != NULL) {
+    num_additional_primes = sk_RSA_additional_prime_num(rsa->additional_primes);
+  }
 
   BN_CTX_start(ctx);
   r1 = BN_CTX_get(ctx);
@@ -724,6 +738,42 @@
     goto err;
   }
 
+  for (i = 0; i < num_additional_primes; i++) {
+    /* multi-prime RSA. */
+    BIGNUM local_exp, local_prime;
+    BIGNUM *exp = &local_exp, *prime = &local_prime;
+    RSA_additional_prime *ap =
+        sk_RSA_additional_prime_value(rsa->additional_primes, i);
+
+    BN_with_flags(exp, ap->exp, BN_FLG_CONSTTIME);
+    BN_with_flags(prime, ap->prime, BN_FLG_CONSTTIME);
+
+    /* c will already point to a BIGNUM with the correct flags. */
+    if (!BN_mod(r1, c, prime, ctx)) {
+      goto err;
+    }
+
+    if ((rsa->flags & RSA_FLAG_CACHE_PRIVATE) &&
+        !BN_MONT_CTX_set_locked(&ap->method_mod, &rsa->lock, prime, ctx)) {
+      goto err;
+    }
+
+    if (!rsa->meth->bn_mod_exp(m1, r1, exp, prime, ctx, ap->method_mod)) {
+      goto err;
+    }
+
+    BN_set_flags(m1, BN_FLG_CONSTTIME);
+
+    if (!BN_sub(m1, m1, r0) ||
+        !BN_mul(m1, m1, ap->coeff, ctx) ||
+        !BN_mod(m1, m1, prime, ctx) ||
+        (BN_is_negative(m1) && !BN_add(m1, m1, prime)) ||
+        !BN_mul(m1, m1, ap->r, ctx) ||
+        !BN_add(r0, r0, m1)) {
+      goto err;
+    }
+  }
+
   if (rsa->e && rsa->n) {
     if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx,
                                rsa->_method_mod_n)) {
@@ -766,12 +816,20 @@
   return ret;
 }
 
-static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
+static int keygen_multiprime(RSA *rsa, int bits, int num_primes,
+                             BIGNUM *e_value, BN_GENCB *cb) {
   BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp;
   BIGNUM local_r0, local_d, local_p;
   BIGNUM *pr0, *d, *p;
-  int bitsp, bitsq, ok = -1, n = 0;
+  int prime_bits, ok = -1, n = 0, i, j;
   BN_CTX *ctx = NULL;
+  STACK_OF(RSA_additional_prime) *additional_primes = NULL;
+
+  if (num_primes < 2) {
+    ok = 0; /* we set our own err */
+    OPENSSL_PUT_ERROR(RSA, keygen_multiprime, RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES);
+    goto err;
+  }
 
   ctx = BN_CTX_new();
   if (ctx == NULL) {
@@ -786,8 +844,32 @@
     goto err;
   }
 
-  bitsp = (bits + 1) / 2;
-  bitsq = bits - bitsp;
+  if (num_primes > 2) {
+    additional_primes = sk_RSA_additional_prime_new_null();
+    if (additional_primes == NULL) {
+      goto err;
+    }
+  }
+
+  for (i = 2; i < num_primes; i++) {
+    RSA_additional_prime *ap = OPENSSL_malloc(sizeof(RSA_additional_prime));
+    if (ap == NULL) {
+      goto err;
+    }
+    memset(ap, 0, sizeof(RSA_additional_prime));
+    ap->prime = BN_new();
+    ap->exp = BN_new();
+    ap->coeff = BN_new();
+    ap->r = BN_new();
+    if (ap->prime == NULL ||
+        ap->exp == NULL ||
+        ap->coeff == NULL ||
+        ap->r == NULL ||
+        !sk_RSA_additional_prime_push(additional_primes, ap)) {
+      RSA_additional_prime_free(ap);
+      goto err;
+    }
+  }
 
   /* We need the RSA components non-NULL */
   if (!rsa->n && ((rsa->n = BN_new()) == NULL)) {
@@ -818,8 +900,9 @@
   BN_copy(rsa->e, e_value);
 
   /* generate p and q */
+  prime_bits = (bits + (num_primes - 1)) / num_primes;
   for (;;) {
-    if (!BN_generate_prime_ex(rsa->p, bitsp, 0, NULL, NULL, cb) ||
+    if (!BN_generate_prime_ex(rsa->p, prime_bits, 0, NULL, NULL, cb) ||
         !BN_sub(r2, rsa->p, BN_value_one()) ||
         !BN_gcd(r1, r2, rsa->e, ctx)) {
       goto err;
@@ -834,19 +917,20 @@
   if (!BN_GENCB_call(cb, 3, 0)) {
     goto err;
   }
+  prime_bits = ((bits - prime_bits) + (num_primes - 2)) / (num_primes - 1);
   for (;;) {
     /* When generating ridiculously small keys, we can get stuck
      * continually regenerating the same prime values. Check for
      * this and bail if it happens 3 times. */
     unsigned int degenerate = 0;
     do {
-      if (!BN_generate_prime_ex(rsa->q, bitsq, 0, NULL, NULL, cb)) {
+      if (!BN_generate_prime_ex(rsa->q, prime_bits, 0, NULL, NULL, cb)) {
         goto err;
       }
     } while ((BN_cmp(rsa->p, rsa->q) == 0) && (++degenerate < 3));
     if (degenerate == 3) {
       ok = 0; /* we set our own err */
-      OPENSSL_PUT_ERROR(RSA, keygen, RSA_R_KEY_SIZE_TOO_SMALL);
+      OPENSSL_PUT_ERROR(RSA, keygen_multiprime, RSA_R_KEY_SIZE_TOO_SMALL);
       goto err;
     }
     if (!BN_sub(r2, rsa->q, BN_value_one()) ||
@@ -860,20 +944,91 @@
       goto err;
     }
   }
-  if (!BN_GENCB_call(cb, 3, 1)) {
+
+  if (!BN_GENCB_call(cb, 3, 1) ||
+      !BN_mul(rsa->n, rsa->p, rsa->q, ctx)) {
     goto err;
   }
+
+  for (i = 2; i < num_primes; i++) {
+    RSA_additional_prime *ap =
+        sk_RSA_additional_prime_value(additional_primes, i - 2);
+    prime_bits = ((bits - BN_num_bits(rsa->n)) + (num_primes - (i + 1))) /
+                 (num_primes - i);
+
+    for (;;) {
+      if (!BN_generate_prime_ex(ap->prime, prime_bits, 0, NULL, NULL, cb)) {
+        goto err;
+      }
+      if (BN_cmp(rsa->p, ap->prime) == 0 ||
+          BN_cmp(rsa->q, ap->prime) == 0) {
+        continue;
+      }
+
+      for (j = 0; j < i - 2; j++) {
+        if (BN_cmp(sk_RSA_additional_prime_value(additional_primes, j)->prime,
+                   ap->prime) == 0) {
+          break;
+        }
+      }
+      if (j != i - 2) {
+        continue;
+      }
+
+      if (!BN_sub(r2, ap->prime, BN_value_one()) ||
+          !BN_gcd(r1, r2, rsa->e, ctx)) {
+        goto err;
+      }
+
+      if (!BN_is_one(r1)) {
+        continue;
+      }
+      if (i != num_primes - 1) {
+        break;
+      }
+
+      /* For the last prime we'll check that it makes n large enough. In the
+       * two prime case this isn't a problem because we generate primes with
+       * the top two bits set and so the product is always of the expected
+       * size. In the multi prime case, this doesn't follow. */
+      if (!BN_mul(r1, rsa->n, ap->prime, ctx)) {
+        goto err;
+      }
+      if (BN_num_bits(r1) == bits) {
+        break;
+      }
+
+      if (!BN_GENCB_call(cb, 2, n++)) {
+        goto err;
+      }
+    }
+
+    /* ap->r is is the product of all the primes prior to the current one
+     * (including p and q). */
+    if (!BN_copy(ap->r, rsa->n)) {
+      goto err;
+    }
+    if (i == num_primes - 1) {
+      /* In the case of the last prime, we calculated n as |r1| in the loop
+       * above. */
+      if (!BN_copy(rsa->n, r1)) {
+        goto err;
+      }
+    } else if (!BN_mul(rsa->n, rsa->n, ap->prime, ctx)) {
+      goto err;
+    }
+
+    if (!BN_GENCB_call(cb, 3, 1)) {
+      goto err;
+    }
+  }
+
   if (BN_cmp(rsa->p, rsa->q) < 0) {
     tmp = rsa->p;
     rsa->p = rsa->q;
     rsa->q = tmp;
   }
 
-  /* calculate n */
-  if (!BN_mul(rsa->n, rsa->p, rsa->q, ctx)) {
-    goto err;
-  }
-
   /* calculate d */
   if (!BN_sub(r1, rsa->p, BN_value_one())) {
     goto err; /* p-1 */
@@ -884,6 +1039,14 @@
   if (!BN_mul(r0, r1, r2, ctx)) {
     goto err; /* (p-1)(q-1) */
   }
+  for (i = 2; i < num_primes; i++) {
+    RSA_additional_prime *ap =
+        sk_RSA_additional_prime_value(additional_primes, i - 2);
+    if (!BN_sub(r3, ap->prime, BN_value_one()) ||
+        !BN_mul(r0, r0, r3, ctx)) {
+      goto err;
+    }
+  }
   pr0 = &local_r0;
   BN_with_flags(pr0, r0, BN_FLG_CONSTTIME);
   if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) {
@@ -912,21 +1075,38 @@
     goto err;
   }
 
+  for (i = 2; i < num_primes; i++) {
+    RSA_additional_prime *ap =
+        sk_RSA_additional_prime_value(additional_primes, i - 2);
+    if (!BN_sub(ap->exp, ap->prime, BN_value_one()) ||
+        !BN_mod(ap->exp, rsa->d, ap->exp, ctx) ||
+        !BN_mod_inverse(ap->coeff, ap->r, ap->prime, ctx)) {
+      goto err;
+    }
+  }
+
   ok = 1;
+  rsa->additional_primes = additional_primes;
+  additional_primes = NULL;
 
 err:
   if (ok == -1) {
-    OPENSSL_PUT_ERROR(RSA, keygen, ERR_LIB_BN);
+    OPENSSL_PUT_ERROR(RSA, keygen_multiprime, ERR_LIB_BN);
     ok = 0;
   }
   if (ctx != NULL) {
     BN_CTX_end(ctx);
     BN_CTX_free(ctx);
   }
-
+  sk_RSA_additional_prime_pop_free(additional_primes,
+                                   RSA_additional_prime_free);
   return ok;
 }
 
+static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
+  return keygen_multiprime(rsa, bits, 2 /* num primes */, e_value, cb);
+}
+
 const struct rsa_meth_st RSA_default_method = {
   {
     0 /* references */,
@@ -955,4 +1135,5 @@
   RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE,
 
   keygen,
+  keygen_multiprime,
 };
diff --git a/crypto/rsa/rsa_test.c b/crypto/rsa/rsa_test.c
index 318cf3f..7e2be3d 100644
--- a/crypto/rsa/rsa_test.c
+++ b/crypto/rsa/rsa_test.c
@@ -240,6 +240,361 @@
   SetKey;
 }
 
+static const char two_prime_key[] =
+    "\x30\x82\x04\xa6\x02\x01\x00\x02\x82\x01\x01\x00\x93\x3a\x4f\xc9\x6a\x0a"
+    "\x6b\x28\x04\xfa\xb7\x05\x56\xdf\xa0\xaa\x4f\xaa\xab\x94\xa0\xa9\x25\xef"
+    "\xc5\x96\xd2\xd4\x66\x16\x62\x2c\x13\x7b\x91\xd0\x36\x0a\x10\x11\x6d\x7a"
+    "\x91\xb6\xe4\x74\x57\xc1\x3d\x7a\xbe\x24\x05\x3a\x04\x0b\x73\x91\x53\xb1"
+    "\x74\x10\xe1\x87\xdc\x91\x28\x9c\x1e\xe5\xf2\xb9\xfc\xa2\x48\x34\xb6\x78"
+    "\xed\x6d\x95\xfb\xf2\xc0\x4e\x1c\xa4\x15\x00\x3c\x8a\x68\x2b\xd6\xce\xd5"
+    "\xb3\x9f\x66\x02\xa7\x0d\x08\xa3\x23\x9b\xe5\x36\x96\x13\x22\xf9\x69\xa6"
+    "\x87\x88\x9b\x85\x3f\x83\x9c\xab\x1a\x1b\x6d\x8d\x16\xf4\x5e\xbd\xee\x4b"
+    "\x59\x56\xf8\x9d\x58\xcd\xd2\x83\x85\x59\x43\x84\x63\x4f\xe6\x1a\x86\x66"
+    "\x0d\xb5\xa0\x87\x89\xb6\x13\x82\x43\xda\x34\x92\x3b\x68\xc4\x95\x71\x2f"
+    "\x15\xc2\xe0\x43\x67\x3c\x08\x00\x36\x10\xc3\xb4\x46\x4c\x4e\x6e\xf5\x44"
+    "\xa9\x04\x44\x9d\xce\xc7\x05\x79\xee\x11\xcf\xaf\x2c\xd7\x9a\x32\xd3\xa5"
+    "\x30\xd4\x3a\x78\x43\x37\x74\x22\x90\x24\x04\x11\xd7\x95\x08\x52\xa4\x71"
+    "\x41\x68\x94\xb0\xa0\xc3\xec\x4e\xd2\xc4\x30\x71\x98\x64\x9c\xe3\x7c\x76"
+    "\xef\x33\xa3\x2b\xb1\x87\x63\xd2\x5c\x09\xfc\x90\x2d\x92\xf4\x57\x02\x01"
+    "\x03\x02\x82\x01\x00\x62\x26\xdf\xdb\x9c\x06\xf2\x1a\xad\xfc\x7a\x03\x8f"
+    "\x3f\xc0\x71\x8a\x71\xc7\xb8\x6b\x1b\x6e\x9f\xd9\x0f\x37\x38\x44\x0e\xec"
+    "\x1d\x62\x52\x61\x35\x79\x5c\x0a\xb6\x48\xfc\x61\x24\x98\x4d\x8f\xd6\x28"
+    "\xfc\x7e\xc2\xae\x26\xad\x5c\xf7\xb6\x37\xcb\xa2\xb5\xeb\xaf\xe8\x60\xc5"
+    "\xbd\x69\xee\xa1\xd1\x53\x16\xda\xcd\xce\xfb\x48\xf3\xb9\x52\xa1\xd5\x89"
+    "\x68\x6d\x63\x55\x7d\xb1\x9a\xc7\xe4\x89\xe3\xcd\x14\xee\xac\x6f\x5e\x05"
+    "\xc2\x17\xbd\x43\x79\xb9\x62\x17\x50\xf1\x19\xaf\xb0\x67\xae\x2a\x57\xbd"
+    "\xc7\x66\xbc\xf3\xb3\x64\xa1\xe3\x16\x74\x9e\xea\x02\x5c\xab\x94\xd8\x97"
+    "\x02\x42\x0c\x2c\xba\x54\xb9\xaf\xe0\x45\x93\xad\x7f\xb3\x10\x6a\x96\x50"
+    "\x4b\xaf\xcf\xc8\x27\x62\x2d\x83\xe9\x26\xc6\x94\xc1\xef\x5c\x8e\x06\x42"
+    "\x53\xe5\x56\xaf\xc2\x99\x01\xaa\x9a\x71\xbc\xe8\x21\x33\x2a\x2d\xa3\x36"
+    "\xac\x1b\x86\x19\xf8\xcd\x1f\x80\xa4\x26\x98\xb8\x9f\x62\x62\xd5\x1a\x7f"
+    "\xee\xdb\xdf\x81\xd3\x21\xdb\x33\x92\xee\xff\xe2\x2f\x32\x77\x73\x6a\x58"
+    "\xab\x21\xf3\xe3\xe1\xbc\x4f\x12\x72\xa6\xb5\xc2\xfb\x27\x9e\xc8\xca\xab"
+    "\x64\xa0\x87\x07\x9d\xef\xca\x0f\xdb\x02\x82\x00\x81\x00\xe6\xd3\x4d\xc0"
+    "\xa1\x91\x0e\x62\xfd\xb0\xdd\xc6\x30\xb8\x8c\xcb\x14\xc1\x4b\x69\x30\xdd"
+    "\xcd\x86\x67\xcb\x37\x14\xc5\x03\xd2\xb4\x69\xab\x3d\xe5\x16\x81\x0f\xe5"
+    "\x50\xf4\x18\xb1\xec\xbc\x71\xe9\x80\x99\x06\xe4\xa3\xfe\x44\x84\x4a\x2d"
+    "\x1e\x07\x7f\x22\x70\x6d\x4f\xd4\x93\x0b\x8b\x99\xce\x1e\xab\xcd\x4c\xd2"
+    "\xd3\x10\x47\x5c\x09\x9f\x6d\x82\xc0\x08\x75\xe3\x3d\x83\xc2\x19\x50\x29"
+    "\xec\x1f\x84\x29\xcc\xf1\x56\xee\xbd\x54\x5d\xe6\x19\xdf\x0d\x1c\xa4\xbb"
+    "\x0a\xfe\x84\x44\x29\x1d\xf9\x5c\x80\x96\x5b\x24\xb4\xf7\x02\x1b\x02\x82"
+    "\x00\x81\x00\xa3\x48\xf1\x9c\x58\xc2\x5f\x38\xfb\xd8\x12\x39\xf1\x8e\x73"
+    "\xa1\xcf\x78\x12\xe0\xed\x2a\xbb\xef\xac\x23\xb2\xbf\xd6\x0c\xe9\x6e\x1e"
+    "\xab\xea\x3f\x68\x36\xa7\x1f\xe5\xab\xe0\x86\xa5\x76\x32\x98\xdd\x75\xb5"
+    "\x2b\xbc\xcb\x8a\x03\x00\x7c\x2e\xca\xf8\xbc\x19\xe4\xe3\xa3\x31\xbd\x1d"
+    "\x20\x2b\x09\xad\x6f\x4c\xed\x48\xd4\xdf\x87\xf9\xf0\x46\xb9\x86\x4c\x4b"
+    "\x71\xe7\x48\x78\xdc\xed\xc7\x82\x02\x44\xd3\xa6\xb3\x10\x5f\x62\x81\xfc"
+    "\xb8\xe4\x0e\xf4\x1a\xdd\xab\x3f\xbc\x63\x79\x5b\x39\x69\x5e\xea\xa9\x15"
+    "\xfe\x90\xec\xda\x75\x02\x82\x00\x81\x00\x99\xe2\x33\xd5\xc1\x0b\x5e\xec"
+    "\xa9\x20\x93\xd9\x75\xd0\x5d\xdc\xb8\x80\xdc\xf0\xcb\x3e\x89\x04\x45\x32"
+    "\x24\xb8\x83\x57\xe1\xcd\x9b\xc7\x7e\x98\xb9\xab\x5f\xee\x35\xf8\x10\x76"
+    "\x9d\xd2\xf6\x9b\xab\x10\xaf\x43\x17\xfe\xd8\x58\x31\x73\x69\x5a\x54\xc1"
+    "\xa0\x48\xdf\xe3\x0c\xb2\x5d\x11\x34\x14\x72\x88\xdd\xe1\xe2\x0a\xda\x3d"
+    "\x5b\xbf\x9e\x57\x2a\xb0\x4e\x97\x7e\x57\xd6\xbb\x8a\xc6\x9d\x6a\x58\x1b"
+    "\xdd\xf6\x39\xf4\x7e\x38\x3e\x99\x66\x94\xb3\x68\x6d\xd2\x07\x54\x58\x2d"
+    "\x70\xbe\xa6\x3d\xab\x0e\xe7\x6d\xcd\xfa\x01\x67\x02\x82\x00\x80\x6c\xdb"
+    "\x4b\xbd\x90\x81\x94\xd0\xa7\xe5\x61\x7b\xf6\x5e\xf7\xc1\x34\xfa\xb7\x40"
+    "\x9e\x1c\x7d\x4a\x72\xc2\x77\x2a\x8e\xb3\x46\x49\x69\xc7\xf1\x7f\x9a\xcf"
+    "\x1a\x15\x43\xc7\xeb\x04\x6e\x4e\xcc\x65\xe8\xf9\x23\x72\x7d\xdd\x06\xac"
+    "\xaa\xfd\x74\x87\x50\x7d\x66\x98\x97\xc2\x21\x28\xbe\x15\x72\x06\x73\x9f"
+    "\x88\x9e\x30\x8d\xea\x5a\xa6\xa0\x2f\x26\x59\x88\x32\x4b\xef\x85\xa5\xe8"
+    "\x9e\x85\x01\x56\xd8\x8d\x19\xcc\xb5\x94\xec\x56\xa8\x7b\x42\xb4\xa2\xbc"
+    "\x93\xc7\x7f\xd2\xec\xfb\x92\x26\x46\x3f\x47\x1b\x63\xff\x0b\x48\x91\xa3"
+    "\x02\x82\x00\x80\x2c\x4a\xb9\xa4\x46\x7b\xff\x50\x7e\xbf\x60\x47\x3b\x2b"
+    "\x66\x82\xdc\x0e\x53\x65\x71\xe9\xda\x2a\xb8\x32\x93\x42\xb7\xff\xea\x67"
+    "\x66\xf1\xbc\x87\x28\x65\x29\x79\xca\xab\x93\x56\xda\x95\xc1\x26\x44\x3d"
+    "\x27\xc1\x91\xc6\x9b\xd9\xec\x9d\xb7\x49\xe7\x16\xee\x99\x87\x50\x95\x81"
+    "\xd4\x5c\x5b\x5a\x5d\x0a\x43\xa5\xa7\x8f\x5a\x80\x49\xa0\xb7\x10\x85\xc7"
+    "\xf4\x42\x34\x86\xb6\x5f\x3f\x88\x9e\xc7\xf5\x59\x29\x39\x68\x48\xf2\xd7"
+    "\x08\x5b\x92\x8e\x6b\xea\xa5\x63\x5f\xc0\xfb\xe4\xe1\xb2\x7d\xb7\x40\xe9"
+    "\x55\x06\xbf\x58\x25\x6f";
+
+static const uint8_t two_prime_encrypted_msg[] = {
+    0x63, 0x0a, 0x30, 0x45, 0x43, 0x11, 0x45, 0xb7, 0x99, 0x67, 0x90, 0x35,
+    0x37, 0x27, 0xff, 0xbc, 0xe0, 0xbf, 0xa6, 0xd1, 0x47, 0x50, 0xbb, 0x6c,
+    0x1c, 0xaa, 0x66, 0xf2, 0xff, 0x9d, 0x9a, 0xa6, 0xb4, 0x16, 0x63, 0xb0,
+    0xa1, 0x7c, 0x7c, 0x0c, 0xef, 0xb3, 0x66, 0x52, 0x42, 0xd7, 0x5e, 0xf3,
+    0xa4, 0x15, 0x33, 0x40, 0x43, 0xe8, 0xb1, 0xfc, 0xe0, 0x42, 0x83, 0x46,
+    0x28, 0xce, 0xde, 0x7b, 0x01, 0xeb, 0x28, 0x92, 0x70, 0xdf, 0x8d, 0x54,
+    0x9e, 0xed, 0x23, 0xb4, 0x78, 0xc3, 0xca, 0x85, 0x53, 0x48, 0xd6, 0x8a,
+    0x87, 0xf7, 0x69, 0xcd, 0x82, 0x8c, 0x4f, 0x5c, 0x05, 0x55, 0xa6, 0x78,
+    0x89, 0xab, 0x4c, 0xd8, 0xa9, 0xd6, 0xa5, 0xf4, 0x29, 0x4c, 0x23, 0xc8,
+    0xcf, 0xf0, 0x4c, 0x64, 0x6b, 0x4e, 0x02, 0x17, 0x69, 0xd6, 0x47, 0x83,
+    0x30, 0x43, 0x02, 0x29, 0xda, 0xda, 0x75, 0x3b, 0xd7, 0xa7, 0x2b, 0x31,
+    0xb3, 0xe9, 0x71, 0xa4, 0x41, 0xf7, 0x26, 0x9b, 0xcd, 0x23, 0xfa, 0x45,
+    0x3c, 0x9b, 0x7d, 0x28, 0xf7, 0xf9, 0x67, 0x04, 0xba, 0xfc, 0x46, 0x75,
+    0x11, 0x3c, 0xd5, 0x27, 0x43, 0x53, 0xb1, 0xb6, 0x9e, 0x18, 0xeb, 0x11,
+    0xb4, 0x25, 0x20, 0x30, 0x0b, 0xe0, 0x1c, 0x17, 0x36, 0x22, 0x10, 0x0f,
+    0x99, 0xb5, 0x50, 0x14, 0x73, 0x07, 0xf0, 0x2f, 0x5d, 0x4c, 0xe3, 0xf2,
+    0x86, 0xc2, 0x05, 0xc8, 0x38, 0xed, 0xeb, 0x2a, 0x4a, 0xab, 0x76, 0xe3,
+    0x1a, 0x75, 0x44, 0xf7, 0x6e, 0x94, 0xdc, 0x25, 0x62, 0x7e, 0x31, 0xca,
+    0xc2, 0x73, 0x51, 0xb5, 0x03, 0xfb, 0xf9, 0xf6, 0xb5, 0x8d, 0x4e, 0x6c,
+    0x21, 0x0e, 0xf9, 0x97, 0x26, 0x57, 0xf3, 0x52, 0x72, 0x07, 0xf8, 0xb4,
+    0xcd, 0xb4, 0x39, 0xcf, 0xbf, 0x78, 0xcc, 0xb6, 0x87, 0xf9, 0xb7, 0x8b,
+    0x6a, 0xce, 0x9f, 0xc8,
+};
+
+static const char three_prime_key[] =
+    "\x30\x82\x04\xd7\x02\x01\x01\x02\x82\x01\x00\x62\x91\xe9\xea\xb3\x5d\x6c"
+    "\x29\xae\x21\x83\xbb\xb5\x82\xb1\x9e\xea\xe0\x64\x5b\x1e\x2f\x5e\x2c\x0a"
+    "\x80\x3d\x29\xd4\xfa\x9a\xe7\x44\xe6\x21\xbd\x98\xc0\x3d\xe0\x53\x59\xae"
+    "\xd3\x3e\xfe\xc4\xc2\xc4\x5a\x5a\x89\x07\xf4\x4f\xdc\xb0\x6a\xd4\x3e\x99"
+    "\x7d\x7a\x97\x26\x4e\xe1\x93\xca\x6e\xed\x07\xfc\xb4\xfa\x95\x1e\x73\x7b"
+    "\x86\x08\x6a\xb9\xd4\x29\xb0\x7e\x59\xb7\x9d\x7b\xeb\x67\x6e\xf0\xbb\x5e"
+    "\xcf\xb9\xcd\x58\x93\xf0\xe7\x88\x17\x6c\x0d\x76\x1e\xb9\x27\x9a\x4d\x02"
+    "\x16\xb6\x49\x6d\xa7\x83\x23\x4d\x02\x48\x0c\x0c\x1f\x0e\x85\x21\xe3\x06"
+    "\x76\x0a\x73\xe6\xc1\x21\xfa\x30\x18\x78\x29\x5c\x31\xd0\x29\xae\x6f\x7d"
+    "\x87\xd8\x2f\x16\xfa\xbc\x67\x8a\x94\x71\x59\x9b\xec\x22\x40\x55\x9f\xc2"
+    "\x94\xb5\xbd\x78\x01\xc9\xef\x18\xc8\x6d\x0d\xdc\x53\x42\xb2\x5c\xab\x65"
+    "\x05\xbd\x35\x08\x85\x1b\xf8\xe9\x47\xbc\xfe\xc5\xae\x47\x29\x63\x44\x8e"
+    "\x4d\xb7\x47\xab\x0d\xd8\x76\x68\x4f\xc7\x07\x02\xe4\x86\xb0\xcf\xd8\x19"
+    "\xad\xf4\x85\x76\x8b\x3b\x4e\x40\x8d\x29\x7a\x8a\x07\x36\xf3\x78\xae\x17"
+    "\xa6\x8f\x53\x58\x65\x4c\x86\x9e\xd7\x8b\xec\x38\x4f\x99\xc7\x02\x01\x03"
+    "\x02\x82\x01\x00\x41\xb6\x9b\xf1\xcc\xe8\xf2\xc6\x74\x16\x57\xd2\x79\x01"
+    "\xcb\xbf\x47\x40\x42\xe7\x69\x74\xe9\x72\xb1\xaa\xd3\x71\x38\xa7\x11\xef"
+    "\x83\x44\x16\x7e\x65\xd5\x7e\x95\x8c\xe6\x74\x8c\xd4\xa9\xd8\x81\xd8\x3c"
+    "\x3c\x5b\x5a\xa2\xdf\xe8\x75\x9c\x8d\x7f\x10\xfe\x51\xba\x19\x89\xeb\xb7"
+    "\xdc\x49\xf3\x5a\xa8\x78\xa7\x0e\x14\x4c\xfd\x04\x05\x9c\x7b\xe2\xc5\xa3"
+    "\x04\xee\xd9\x4c\xfd\x7d\x47\xb0\x0d\x9b\x3d\x70\x91\x81\x2c\xab\x2b\x87"
+    "\xad\x11\x68\x24\xfc\x2b\xd4\xee\x5e\x28\xeb\x6d\xab\xde\x0f\x77\x15\x58"
+    "\x76\x39\xc9\x59\x3a\x7f\x19\x9d\xc6\x7e\x86\xe4\xd5\x38\x70\x9e\xae\xb9"
+    "\xfb\x33\x33\xd1\x0c\x2d\xab\x01\x20\xe1\x8b\x29\x99\xd3\xeb\x87\x05\x72"
+    "\xaa\x43\x58\x64\x8e\x9e\x31\xdb\x45\x9b\x2b\xac\x58\x80\x5d\x33\xa2\x43"
+    "\x05\x96\xcc\xca\x2d\x04\x5f\xd6\xb7\x3d\x8b\x8f\x2d\xa3\xa5\xf8\x73\xf5"
+    "\xd7\xc0\x19\xff\x10\xe6\xee\x3a\x26\x2f\xe1\x64\x3d\x11\xcd\x2d\xe4\x0a"
+    "\x84\x27\xe3\xcb\x16\x62\x19\xe7\xe3\x0d\x13\xe8\x09\x5a\x53\xd0\x20\x56"
+    "\x15\xf5\xb3\x67\xac\xa1\xb5\x94\x6b\xab\xdc\x71\xc7\xbf\x0a\xde\x76\xf5"
+    "\x03\xa0\x30\xd8\x27\x9d\x00\x2b\x02\x57\x00\xf1\x4f\xc2\x86\x13\x06\x17"
+    "\xf7\x69\x7e\x37\xdf\x67\xc5\x32\xa0\x74\x1c\x32\x69\x0f\x9f\x08\x88\x24"
+    "\xb1\x51\xbc\xbc\x92\xba\x73\x1f\x9c\x75\xc2\x14\x6d\x4f\xc4\x5a\xcf\xda"
+    "\x44\x35\x00\x6b\x42\x3b\x9f\x14\xf1\x05\xb3\x51\x22\xb6\xbe\x9c\xe0\xc1"
+    "\x5c\x48\x61\xdf\x4e\x4c\x72\xb8\x05\x35\x7c\xac\xf1\xbb\xa0\x3b\x2a\xea"
+    "\xf7\x86\xe9\xd2\xff\x1e\x1d\x02\x56\x00\xca\xb1\x39\xf6\xa2\xc6\x3b\x65"
+    "\x45\x2f\x39\x00\xcd\x6e\xd6\x55\xf7\x71\x37\x89\xc2\xe7\x7a\xc0\x1a\xa6"
+    "\x2f\xea\x17\x7c\xaa\x2a\x91\x8f\xd4\xc7\x50\x8b\xab\x8e\x99\x3b\x33\x91"
+    "\xbc\x02\x10\x58\x4b\x58\x40\x9b\xc4\x8f\x48\x2b\xa7\x44\xfd\x07\x04\xf0"
+    "\x98\x67\x56\xea\x25\x92\x8b\x2e\x4b\x4a\xa1\xd3\xc2\xa4\xb4\x9b\x59\x70"
+    "\x32\xa6\xd8\x8b\xd9\x02\x57\x00\xa0\xdf\xd7\x04\x0c\xae\xba\xa4\xf0\xfe"
+    "\xcf\xea\x45\x2e\x21\xc0\x4d\x68\x21\x9b\x5f\xbf\x5b\x05\x6d\xcb\x8b\xd3"
+    "\x28\x61\xd1\xa2\x15\x12\xf9\x2c\x0d\x9e\x35\x2d\x91\xdf\xe6\xd8\x23\x55"
+    "\x9c\xd6\xd2\x6a\x0d\xf6\x03\xcc\xe0\xc1\xcf\x29\xbd\xeb\x2b\x92\xda\xeb"
+    "\xea\x34\x32\xf7\x25\x58\xce\x53\x1d\xf6\x7d\x15\x7c\xc7\x47\x4f\xaf\x46"
+    "\x8c\xaa\x14\x13\x02\x56\x00\x87\x20\xd1\x4f\x17\x2e\xd2\x43\x83\x74\xd0"
+    "\xab\x33\x9f\x39\x8e\xa4\xf6\x25\x06\x81\xef\xa7\x2a\xbc\x6e\xca\x9c\x0f"
+    "\xa8\x71\x71\xb6\x5f\xe3\x2f\x8b\x07\xc7\xb4\x66\x27\x77\xb6\x7d\x56\xb5"
+    "\x90\x32\x3a\xd5\xbd\x2d\xb4\xda\xc7\xc4\xd8\xa8\xaf\x58\xa0\x65\x9a\x39"
+    "\xf1\x6e\x61\xb2\x1e\xdc\xdc\x6b\xe2\x81\xc3\x23\x12\x3b\xa0\x21\xc4\x90"
+    "\x5d\x3b\x02\x57\x00\xe6\x8a\xaa\xb8\x6d\x2c\x81\x43\xb5\xd6\xa0\x2b\x42"
+    "\x49\xa9\x0a\x51\xfa\x18\xc8\x32\xea\x54\x18\xf3\x60\xc2\xb5\x4a\x43\x05"
+    "\x93\x9c\x01\xd9\x28\xed\x73\xfa\x82\xbc\x12\x64\xcb\xc4\x24\xa9\x3e\xae"
+    "\x7c\x4b\x8f\x94\x57\x7b\x14\x10\x41\xdc\x62\x12\x8c\xb2\x4a\x7c\xf6\x53"
+    "\xd4\xc6\xe4\xda\xd1\xa2\x00\x0e\x3d\x30\xf7\x05\x4f\x1d\x82\xbc\x52\xd9"
+    "\xb1\x30\x82\x01\x0a\x30\x82\x01\x06\x02\x56\x00\x84\x12\x4f\xf7\x3b\x65"
+    "\x53\x34\x6c\x6c\x4d\x77\xdf\xfd\x1f\xb6\x16\xe2\x25\x15\xca\xc9\xc1\x41"
+    "\x9a\x50\xda\xeb\x88\x4f\x3d\xb3\x01\x00\x44\xc4\xac\xe7\x14\x62\xa6\x56"
+    "\xde\xc5\xb7\xc3\x1d\x07\xbd\x7d\x64\xc5\x7e\x45\x25\x56\xed\x7a\xd2\x14"
+    "\xdb\x4e\x27\xd4\x1f\xf8\x94\xa7\xef\x07\xce\xdb\x24\xb7\xdd\x71\x5c\x63"
+    "\xc9\x33\xfe\xde\x40\x52\xeb\x02\x55\x58\x0c\x35\x4f\x7c\xee\x37\x78\x48"
+    "\x48\x33\xa5\x3f\xfe\x15\x24\x0f\x41\x6e\x0e\x87\x31\x2b\x81\x11\x8b\x3c"
+    "\x9d\x05\x8a\x29\x22\x00\xaa\xd8\x83\x1d\xef\x62\xec\x6e\xe4\x94\x83\xcf"
+    "\xd7\x68\xaf\xd3\xa8\xed\xd8\xfe\xd8\xc3\x8f\x48\xfc\x8c\x0d\xe7\x89\x6f"
+    "\xe2\xbf\xfb\x0d\xc5\x4a\x05\x34\x92\x18\x7a\x93\xa0\xe8\x42\x86\x22\xa9"
+    "\xe9\x80\x37\x47\x02\x55\x60\x76\xab\xde\x2b\xf5\xa2\x2c\xaa\x0c\x99\x81"
+    "\xee\x72\x2c\x7d\x22\x59\x2a\x35\xea\x50\x4e\x47\x6b\x92\x2d\x30\xa1\x01"
+    "\xa5\x9e\x26\x6e\x27\xca\xf5\xf2\x87\x5d\x31\xaf\xe9\x32\xcd\x10\xfd\x4d"
+    "\xdb\xf9\x86\x05\x12\x1b\x01\x84\x55\x97\x5f\xe2\x78\x27\xd9\xe4\x26\x7d"
+    "\xab\x0e\xe0\x1b\x6f\xcb\x4b\x14\xdd\xdc\xdc\x8b\xe8\x9f\xd0\x62\x96\xca"
+    "\xcf";
+
+static const uint8_t three_prime_encrypted_msg[] = {
+    0x58, 0xd9, 0xea, 0x8a, 0xf6, 0x3d, 0xb4, 0xd9, 0xf7, 0xbb, 0x02, 0xc5,
+    0x58, 0xd2, 0xa9, 0x46, 0x80, 0x70, 0x70, 0x16, 0x07, 0x64, 0x32, 0x4c,
+    0x4e, 0x92, 0x61, 0xb7, 0xff, 0x92, 0xdc, 0xfc, 0xf8, 0xf0, 0x2c, 0x84,
+    0x56, 0xbc, 0xe5, 0x93, 0x76, 0xe5, 0xa3, 0x72, 0x98, 0xf2, 0xdf, 0xef,
+    0x99, 0x53, 0xf6, 0xd8, 0x4b, 0x09, 0xac, 0xa9, 0xa3, 0xdb, 0x63, 0xa1,
+    0xb5, 0x09, 0x8e, 0x40, 0x84, 0x8f, 0x4d, 0xd5, 0x1d, 0xac, 0x6c, 0xaa,
+    0x6b, 0x15, 0xe7, 0xb1, 0x0c, 0x67, 0xd2, 0xb2, 0x81, 0x58, 0x30, 0x0e,
+    0x18, 0x27, 0xa1, 0x9b, 0x96, 0xad, 0xae, 0x76, 0x1a, 0x32, 0xf7, 0x10,
+    0x0b, 0x53, 0x85, 0x31, 0xd6, 0x2a, 0xf6, 0x1c, 0x9f, 0xc2, 0xc7, 0xb1,
+    0x05, 0x63, 0x0b, 0xa5, 0x07, 0x1f, 0x1c, 0x01, 0xf0, 0xe0, 0x06, 0xea,
+    0x20, 0x69, 0x41, 0x19, 0x57, 0x92, 0x17, 0xf7, 0x0c, 0x5c, 0x66, 0x75,
+    0x0e, 0xe5, 0xb3, 0xf1, 0x67, 0x3b, 0x27, 0x47, 0xb2, 0x8e, 0x1c, 0xb6,
+    0x3f, 0xdd, 0x76, 0x42, 0x31, 0x13, 0x68, 0x96, 0xdf, 0x3b, 0xd4, 0x87,
+    0xd9, 0x16, 0x44, 0x71, 0x52, 0x2e, 0x54, 0x3e, 0x09, 0xcd, 0x71, 0xc1,
+    0x1e, 0x5e, 0x96, 0x13, 0xc9, 0x1e, 0xa4, 0xe6, 0xe6, 0x97, 0x2c, 0x6b,
+    0xf2, 0xa9, 0x5c, 0xc6, 0x60, 0x2a, 0xbc, 0x82, 0xf8, 0xcb, 0xd4, 0xd7,
+    0xea, 0x8a, 0xa1, 0x8a, 0xd9, 0xa5, 0x14, 0x8b, 0x9e, 0xf9, 0x25, 0x02,
+    0xd2, 0xab, 0x0c, 0x42, 0xca, 0x2d, 0x45, 0xa3, 0x56, 0x5e, 0xa2, 0x2a,
+    0xc8, 0x60, 0xa5, 0x87, 0x5d, 0x85, 0x5c, 0xde, 0xc7, 0xa2, 0x47, 0xc3,
+    0x99, 0x29, 0x23, 0x79, 0x36, 0x88, 0xad, 0x40, 0x3e, 0x27, 0x7d, 0xf0,
+    0xb6, 0xfa, 0x95, 0x20, 0x3c, 0xec, 0xfc, 0x56, 0x3b, 0x20, 0x91, 0xee,
+    0x98, 0x10, 0x2c, 0x82,
+};
+
+static const char six_prime_key[] =
+    "\x30\x82\x05\x24\x02\x01\x01\x02\x82\x01\x00\x1c\x04\x39\x44\xb9\xb8\x71"
+    "\x1c\x1c\xf7\xdc\x11\x1b\x85\x3b\x2b\xe8\xa6\xeb\xeb\xe9\xb6\x86\x97\x73"
+    "\x5d\x75\x46\xd1\x35\x25\xf8\x30\x9a\xc3\x57\x44\x89\xa6\x44\x59\xe3\x3a"
+    "\x60\xb5\x33\x84\x72\xa4\x03\xc5\x1a\x20\x98\x70\xbd\xe8\x3b\xc1\x9b\x8a"
+    "\x3a\x24\x45\xb6\x6a\x73\xb4\xd0\x6c\x18\xc6\xa7\x94\xd3\x24\x70\xf0\x2d"
+    "\x0c\xa5\xb2\x3b\xc5\x33\x90\x9d\x56\x8d\x33\xf6\x93\x7d\xa7\x95\x88\x05"
+    "\xdf\xf5\x65\x58\xb9\x5b\xd3\x07\x9c\x16\x8e\x74\xfc\xb8\x76\xaf\x62\x99"
+    "\x6c\xd4\xc5\xb3\x69\xe5\x64\xdf\x38\x00\x25\x24\xe9\xb1\x4a\x85\xa6\xf4"
+    "\xb6\x23\x68\x67\x4a\x2c\xbd\x9d\x01\x3b\x04\x8c\x70\x94\x82\x76\x45\x0c"
+    "\x8b\x95\x8a\x07\x1c\x32\xe7\x09\x97\x3a\xfd\xca\x57\xe9\x57\x0c\xae\x2b"
+    "\xa3\x25\xd1\xf2\x0d\x34\xa1\xe6\x2f\x7b\x1b\x36\x53\x83\x95\xb9\x26\x6e"
+    "\x4f\x36\x26\xf8\x47\xae\xdf\xe8\x4d\xf6\xb2\xff\x03\x23\x74\xfa\xa5\x6d"
+    "\xcb\xcb\x80\x12\xc3\x77\xf0\x19\xb7\xf2\x6b\x19\x5c\xde\x0a\xd7\xee\x8c"
+    "\x48\x2f\x50\x24\xa5\x2e\xcc\x2a\xed\xc2\x35\xe0\x3d\x29\x31\x17\xd6\x8f"
+    "\x44\xaa\x5b\x33\xbd\xb4\x88\x87\xd9\x29\x3f\x94\xe7\x75\xe3\x02\x01\x03"
+    "\x02\x82\x01\x00\x12\xad\x7b\x83\x26\x7a\xf6\x12\xbd\xfa\x92\xb6\x12\x58"
+    "\xd2\x1d\x45\xc4\x9d\x47\xf1\x24\x59\xba\x4c\xe8\xf8\xd9\xe0\xce\x19\x50"
+    "\x20\x67\x2c\xe4\xd8\x5b\xc4\x2d\x91\x41\xeb\x05\x4f\xf4\xb4\x20\xc7\xbc"
+    "\xd6\xe2\x5c\xa0\x27\xcf\xb8\xb3\x3b\x5c\xeb\x5e\x96\xb7\x99\x4b\x8a\xc3"
+    "\x70\xaf\x7f\xd8\x5f\xeb\xcb\x1a\x79\x44\x68\x97\x84\xd8\x29\x87\x64\xba"
+    "\x18\x2e\x95\x66\x1a\x7d\xd9\x35\x3a\x5c\x92\x7a\x81\x1b\x6c\xa9\xf8\xfa"
+    "\x05\x23\x18\x5b\xb2\xf8\x77\x1c\xc5\x1b\x7d\x26\x5f\x48\x69\x1b\xc4\x34"
+    "\xef\x6e\xa1\x15\xd2\xb2\xac\xb8\xa8\xed\x1e\xee\xdc\xb5\xb9\x5c\x79\x25"
+    "\x48\xbb\xe5\x9d\xd8\xe5\xe2\x94\xdf\xd5\x32\x22\x84\xbf\xc2\xaa\xa4\x54"
+    "\xbb\x29\xdb\x13\x4a\x28\x3d\x83\x3a\xff\xa3\xae\x38\x08\xfc\x36\x84\x91"
+    "\x30\xd1\xfd\x82\x64\xf1\x0f\xae\xba\xd7\x9a\x43\x58\x03\x5e\x5f\x01\xcb"
+    "\x8b\x90\x8d\x77\x34\x6f\x37\x40\xb6\x6d\x22\x23\x90\xb2\xfd\x32\xb5\x96"
+    "\x45\xbf\xae\x8c\xc4\x62\x03\x6c\x68\x90\x59\x31\x1a\xcb\xfb\xa4\x0b\x94"
+    "\x15\x13\xda\x1a\x8d\xa7\x0b\x34\x62\x93\xea\xbe\x6e\x71\xc2\x1d\xc8\x9d"
+    "\xac\x66\xcc\x31\x87\xff\x99\xab\x02\x2c\x00\xa5\x57\x41\x66\x87\x68\x02"
+    "\x6a\xdf\x97\xb0\xfe\x6b\x34\xc4\x33\x88\x2b\xce\x82\xaf\x2d\x33\x5a\xad"
+    "\x75\x2d\xac\xa5\xd6\x3a\x2d\x65\x43\x68\xfb\x44\x9e\xb8\x25\x05\xed\x97"
+    "\x02\x2c\x00\xd2\x77\x34\x24\xac\x60\x9a\xc4\x68\x34\xe5\x6a\xa3\xdc\xe2"
+    "\xb0\x58\x5c\x35\x83\x5a\xc7\xa7\xc1\x0b\x7e\x9e\xa5\x85\x32\x47\x93\x22"
+    "\xee\xb6\x59\xe9\xe3\x61\x94\xd0\x0e\xcb\x02\x2b\x6e\x3a\x2b\x99\xaf\x9a"
+    "\xac\x47\x3f\xba\x75\xfe\xf2\x23\x2d\x77\xb0\x1d\x34\x57\x1f\x73\x77\x91"
+    "\xc8\xf8\xc9\x1d\xc3\xe4\x26\xc8\xee\x2c\xf0\xa7\x83\x14\x7a\xc3\x59\x49"
+    "\x0f\x02\x2c\x00\x8c\x4f\x78\x18\x72\xeb\x11\xd8\x45\x78\x98\xf1\xc2\x93"
+    "\x41\xca\xe5\x92\xce\x57\x91\xda\x6f\xd6\x07\xa9\xbf\x19\x03\x76\xda\x62"
+    "\x17\x49\xce\xe6\x9b\xec\xeb\xb8\x8a\xb4\x87\x02\x2c\x00\xa3\xc2\x29\xa6"
+    "\xa7\xe1\x3c\xe9\xcf\x0f\x50\x51\x1c\xcc\xc8\x5b\x08\x9c\x97\x24\x3a\x86"
+    "\x23\xa8\x0b\xbb\x54\xa6\xb9\x70\x3d\x1d\xd0\x1b\xa3\xac\xd9\xb2\x03\x80"
+    "\xd7\x67\xec\x30\x82\x02\x2d\x30\x82\x00\x88\x02\x2c\x00\x97\x5d\x3b\xf2"
+    "\xcc\xba\xd9\x77\x67\xaa\xd2\x22\xa7\xa3\x49\x08\xc7\xb8\x27\xa1\x59\x4b"
+    "\xa7\xa5\xd2\x74\x05\xe7\x5a\x35\xd7\x25\x79\x18\x20\x8a\x25\xec\x3b\x52"
+    "\xaf\xcb\xdb\x02\x2b\x64\xe8\xd2\xa1\xdd\xd1\xe6\x4f\x9a\x71\xe1\x6c\x6f"
+    "\xc2\x30\xb0\x85\x25\x6f\xc0\xe6\x32\x6f\xc3\xe1\xa2\xae\x9a\x3c\x23\xe4"
+    "\xc3\xa6\x10\x15\xb1\x6e\x9d\x7c\xe1\xca\x87\xe7\x02\x2b\x5e\xef\x25\x29"
+    "\xed\xf6\x52\x15\xd3\x60\xb6\x88\xcf\x0f\xe2\x24\xa4\x04\x97\x9c\x9d\x58"
+    "\x13\xbb\x00\x6d\x39\xf6\xad\x21\x7e\x56\x2c\x2e\x06\x06\xc4\x6d\x44\xac"
+    "\x79\x1f\xe5\x30\x82\x00\x89\x02\x2c\x00\xdb\xf1\x78\xf9\xa4\x94\xea\x39"
+    "\x8a\x3f\x23\x48\x2a\x23\x8f\xd2\x18\x97\xd2\xdf\x0f\xb8\x2b\x33\xa0\xe8"
+    "\x8f\xbc\x4e\x42\xfd\x54\xc7\x0f\xde\xba\x6d\xba\x96\xa7\xce\x67\x3d\x02"
+    "\x2c\x00\x92\xa0\xfb\x51\x18\x63\x46\xd1\x06\xd4\xc2\x30\x1c\x17\xb5\x36"
+    "\xbb\x0f\xe1\xea\x0a\x7a\xc7\x77\xc0\x9b\x0a\x7d\x89\x81\xfe\x38\x84\xb5"
+    "\x3f\x26\xf3\xd1\xb9\xc5\x34\x44\xd3\x02\x2b\x4c\xbd\x1d\x44\xc8\x19\x23"
+    "\xd8\xb3\x96\x66\x4b\x62\xcb\x3e\xe6\x6c\x11\xdf\xb2\x92\xd3\xc8\x34\xb9"
+    "\xa6\x5a\x2f\x19\xf4\x0b\xb2\xe6\x8e\xa6\xaf\xa3\xae\xa4\xb3\x92\xc4\x79"
+    "\x30\x82\x00\x85\x02\x2b\x00\x89\xab\x30\xfc\x7b\x37\x94\x11\x9f\x4d\x31"
+    "\x3b\xac\x09\x57\xe6\x64\xec\xa0\xc8\xf8\x04\x1a\xf9\x2a\xa4\x4b\x36\x18"
+    "\xbb\x5f\xdc\xcd\xf0\xc8\xcb\x97\xd1\xdf\x13\x12\x3f\x02\x2a\x5b\xc7\x75"
+    "\xfd\xa7\x7a\x62\xb6\x6a\x33\x76\x27\xc8\x06\x3a\x99\x98\x9d\xc0\x85\xfa"
+    "\xad\x67\x50\xc7\x18\x32\x24\x10\x7c\xea\x93\x33\xf5\xdb\x32\x65\x36\x94"
+    "\xb7\x61\x7f\x02\x2a\x16\x6c\x96\xa1\x50\x6f\x3a\x92\xc0\x75\x43\xb5\x6b"
+    "\x9c\x17\x09\xd3\xf0\x67\x69\x45\x92\xfb\x7b\x50\xa8\x42\x9b\x33\x92\xab"
+    "\xd5\xe6\x49\xb3\x26\x99\x55\x16\x3a\x39\x63\x30\x82\x00\x87\x02\x2b\x00"
+    "\xc1\x25\x19\x1d\x6e\x18\xcb\x2d\x64\xe2\xe6\xb6\x1c\xe4\xaa\x9c\xb9\xee"
+    "\x18\xd4\xf7\x5f\x66\x40\xf0\xe1\x31\x38\xf2\x53\x00\x8b\xcc\xe4\x0d\xb7"
+    "\x81\xb4\xe6\x1c\x19\xaf\x02\x2b\x00\x80\xc3\x66\x13\x9e\xbb\x32\x1e\x43"
+    "\x41\xef\x24\x13\x43\x1c\x68\x7b\xf4\x10\x8d\xfa\x3f\x99\x80\xa0\x96\x20"
+    "\xd0\xa1\x8c\xab\x07\xdd\xed\x5e\x7a\x56\x78\x99\x68\x11\x1f\x02\x2b\x00"
+    "\xb0\x59\xea\x67\x93\x42\xbf\x07\x54\x38\x41\xcb\x73\xa4\x0e\xc2\xae\x56"
+    "\x19\x41\xc9\x8a\xb2\x2f\xa8\x0a\xb1\x4e\x12\x39\x2e\xc0\x94\x9a\xc6\xa3"
+    "\xe4\xaf\x8a\x16\x06\xb8";
+
+static const uint8_t six_prime_encrypted_msg[] = {
+    0x0a, 0xcb, 0x6c, 0x02, 0x9d, 0x1a, 0x7c, 0xf3, 0x4e, 0xff, 0x16, 0x88,
+    0xee, 0x22, 0x1d, 0x8d, 0xd2, 0xfd, 0xde, 0x83, 0xb3, 0xd9, 0x35, 0x2c,
+    0x82, 0xe0, 0xff, 0xe6, 0x79, 0x6d, 0x06, 0x21, 0x74, 0xa8, 0x04, 0x0c,
+    0xe2, 0xd3, 0x98, 0x3f, 0xbf, 0xd0, 0xe9, 0x88, 0x24, 0xe2, 0x05, 0xa4,
+    0x45, 0x51, 0x87, 0x6b, 0x1c, 0xef, 0x5f, 0x2d, 0x61, 0xb6, 0xf1, 0x4c,
+    0x1f, 0x3d, 0xbf, 0x4b, 0xf2, 0xda, 0x09, 0x97, 0x81, 0xde, 0x91, 0xb7,
+    0x0d, 0xb4, 0xc2, 0xab, 0x41, 0x64, 0x9d, 0xd9, 0x39, 0x46, 0x79, 0x66,
+    0x43, 0xf1, 0x34, 0x21, 0x56, 0x2f, 0xc6, 0x68, 0x40, 0x4a, 0x2d, 0x73,
+    0x96, 0x50, 0xe1, 0xb0, 0xaf, 0x49, 0x39, 0xb4, 0xf0, 0x3a, 0x78, 0x38,
+    0x70, 0xa9, 0x91, 0x5d, 0x5e, 0x07, 0xf4, 0xec, 0xbb, 0xc4, 0xe5, 0x8a,
+    0xb8, 0x06, 0xba, 0xdf, 0xc6, 0x48, 0x78, 0x4b, 0xca, 0x2a, 0x8a, 0x92,
+    0x64, 0xe3, 0xa6, 0xae, 0x87, 0x97, 0x12, 0x16, 0x46, 0x67, 0x59, 0xdf,
+    0xf2, 0xf3, 0x89, 0x6f, 0xe8, 0xa9, 0x13, 0x57, 0x63, 0x4e, 0x07, 0x98,
+    0xcc, 0x73, 0xa0, 0x84, 0x9d, 0xe8, 0xb3, 0x50, 0x59, 0xb5, 0x51, 0xb3,
+    0x41, 0x7d, 0x55, 0xfe, 0xd9, 0xf0, 0xc6, 0xff, 0x6e, 0x96, 0x4f, 0x22,
+    0xb2, 0x0d, 0x6b, 0xc9, 0x83, 0x2d, 0x98, 0x98, 0xb2, 0xd1, 0xb7, 0xe4,
+    0x50, 0x83, 0x1a, 0xa9, 0x02, 0x9f, 0xaf, 0x54, 0x74, 0x2a, 0x2c, 0x63,
+    0x10, 0x79, 0x45, 0x5c, 0x95, 0x0d, 0xa1, 0x9b, 0x55, 0xf3, 0x1e, 0xb7,
+    0x56, 0x59, 0xf1, 0x59, 0x8d, 0xd6, 0x15, 0x89, 0xf6, 0xfe, 0xc0, 0x00,
+    0xdd, 0x1f, 0x2b, 0xf0, 0xf7, 0x5d, 0x64, 0x84, 0x76, 0xd3, 0xc2, 0x92,
+    0x35, 0xac, 0xb5, 0xf9, 0xf6, 0xa8, 0x05, 0x89, 0x4c, 0x95, 0x41, 0x4e,
+    0x34, 0x25, 0x11, 0x14,
+};
+
+static int test_multi_prime_key(int nprimes, const uint8_t *der,
+                                size_t der_size, const uint8_t *enc,
+                                size_t enc_size) {
+  RSA *rsa = d2i_RSAPrivateKey(NULL, &der, der_size);
+  if (!rsa) {
+    printf("%d-prime key failed to parse.\n", nprimes);
+    ERR_print_errors_fp(stderr);
+    return 0;
+  }
+
+  if (!RSA_check_key(rsa)) {
+    printf("RSA_check_key failed for %d-prime key.\n", nprimes);
+    ERR_print_errors_fp(stderr);
+    return 0;
+  }
+
+  uint8_t out[256];
+  size_t out_len;
+  if (!RSA_decrypt(rsa, &out_len, out, sizeof(out), enc, enc_size,
+                   RSA_PKCS1_PADDING) ||
+      out_len != 11 ||
+      memcmp(out, "hello world", 11) != 0) {
+    printf("%d-prime key failed to decrypt.\n", nprimes);
+    ERR_print_errors_fp(stderr);
+    return 0;
+  }
+
+  RSA_free(rsa);
+  return 1;
+}
+
+static int test_multi_prime_keygen() {
+  RSA *rsa = RSA_new();
+  BIGNUM e;
+
+  BN_init(&e);
+
+  static const char kMessage[] = "Hello world.";
+  static const size_t kBits = 1024;
+  uint8_t encrypted[kBits / 8], decrypted[kBits / 8];
+  size_t encrypted_len, decrypted_len;
+
+  if (rsa == NULL ||
+      !BN_set_word(&e, RSA_F4) ||
+      !RSA_generate_multi_prime_key(rsa, kBits, 3, &e, NULL) ||
+      !RSA_check_key(rsa) ||
+      !RSA_encrypt(rsa, &encrypted_len, encrypted, sizeof(encrypted),
+                   (const uint8_t *)kMessage, sizeof(kMessage),
+                   RSA_PKCS1_PADDING) ||
+      !RSA_decrypt(rsa, &decrypted_len, decrypted, sizeof(decrypted), encrypted,
+                   encrypted_len, RSA_PKCS1_PADDING) ||
+      decrypted_len != sizeof(kMessage) ||
+      memcmp(decrypted, kMessage, sizeof(kMessage)) != 0) {
+    ERR_print_errors_fp(stderr);
+    return 0;
+  }
+
+  BN_free(&e);
+  RSA_free(rsa);
+
+  return 1;
+}
+
 static int test_bad_key(void) {
   RSA *key = RSA_new();
   BIGNUM e;
@@ -500,7 +855,17 @@
   if (err != 0 ||
       !test_only_d_given() ||
       !test_recover_crt_params() ||
-      !test_bad_key()) {
+      !test_bad_key() ||
+      !test_multi_prime_key(2, (const uint8_t *)two_prime_key,
+                            sizeof(two_prime_key) - 1, two_prime_encrypted_msg,
+                            sizeof(two_prime_encrypted_msg)) ||
+      !test_multi_prime_key(
+          3, (const uint8_t *)three_prime_key, sizeof(three_prime_key) - 1,
+          three_prime_encrypted_msg, sizeof(three_prime_encrypted_msg)) ||
+      !test_multi_prime_key(6, (const uint8_t *)six_prime_key,
+                            sizeof(six_prime_key) - 1, six_prime_encrypted_msg,
+                            sizeof(six_prime_encrypted_msg)) ||
+      !test_multi_prime_keygen()) {
     err = 1;
   }
 
diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h
index 9b415d7..ff0a9a9 100644
--- a/include/openssl/rsa.h
+++ b/include/openssl/rsa.h
@@ -100,6 +100,12 @@
 OPENSSL_EXPORT int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e,
                                        BN_GENCB *cb);
 
+/* RSA_generate_multi_prime_key acts like |RSA_generate_key_ex| but can
+ * generate an RSA private key with more than two primes. */
+OPENSSL_EXPORT int RSA_generate_multi_prime_key(RSA *rsa, int bits,
+                                                int num_primes, BIGNUM *e,
+                                                BN_GENCB *cb);
+
 
 /* Encryption / Decryption */
 
@@ -450,6 +456,9 @@
 
   int (*keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
 
+  int (*multi_prime_keygen)(RSA *rsa, int bits, int num_primes, BIGNUM *e,
+                            BN_GENCB *cb);
+
   /* supports_digest returns one if |rsa| supports digests of type
    * |md|. If null, it is assumed that all digests are supported. */
   int (*supports_digest)(const RSA *rsa, const EVP_MD *md);
@@ -473,6 +482,9 @@
   BIGNUM *dmp1;
   BIGNUM *dmq1;
   BIGNUM *iqmp;
+
+  STACK_OF(RSA_additional_prime) *additional_primes;
+
   /* be careful using this if the RSA structure is shared */
   CRYPTO_EX_DATA ex_data;
   CRYPTO_refcount_t references;
@@ -530,6 +542,7 @@
 #define RSA_F_rsa_setup_blinding 125
 #define RSA_F_sign_raw 126
 #define RSA_F_verify_raw 127
+#define RSA_F_keygen_multiprime 128
 #define RSA_R_BAD_E_VALUE 100
 #define RSA_R_BAD_FIXED_HEADER_DECRYPT 101
 #define RSA_R_BAD_PAD_BYTE_COUNT 102
@@ -571,5 +584,7 @@
 #define RSA_R_UNKNOWN_PADDING_TYPE 138
 #define RSA_R_VALUE_MISSING 139
 #define RSA_R_WRONG_SIGNATURE_LENGTH 140
+#define RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES 141
+#define RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY 142
 
 #endif  /* OPENSSL_HEADER_RSA_H */
diff --git a/include/openssl/stack.h b/include/openssl/stack.h
index 350fa14..5f9b683 100644
--- a/include/openssl/stack.h
+++ b/include/openssl/stack.h
@@ -140,11 +140,12 @@
  * STACK_OF:GENERAL_NAMES
  * STACK_OF:GENERAL_SUBTREE
  * STACK_OF:MIME_HEADER
- * STACK_OF:PKCS7_SIGNER_INFO
  * STACK_OF:PKCS7_RECIP_INFO
+ * STACK_OF:PKCS7_SIGNER_INFO
  * STACK_OF:POLICYINFO
  * STACK_OF:POLICYQUALINFO
  * STACK_OF:POLICY_MAPPING
+ * STACK_OF:RSA_additional_prime
  * STACK_OF:SSL_COMP
  * STACK_OF:STACK_OF_X509_NAME_ENTRY
  * STACK_OF:SXNETID
diff --git a/include/openssl/stack_macros.h b/include/openssl/stack_macros.h
index dadcf6b..754909e 100644
--- a/include/openssl/stack_macros.h
+++ b/include/openssl/stack_macros.h
@@ -104,6 +104,7 @@
       CHECKED_CAST(void (*)(void *), void (*)(ACCESS_DESCRIPTION *),          \
                    free_func)))
 
+
 /* ASN1_ADB_TABLE */
 #define sk_ASN1_ADB_TABLE_new(comp)                 \
   ((STACK_OF(ASN1_ADB_TABLE) *)sk_new(CHECKED_CAST( \
@@ -189,6 +190,7 @@
                    copy_func),                                               \
       CHECKED_CAST(void (*)(void *), void (*)(ASN1_ADB_TABLE *), free_func)))
 
+
 /* ASN1_GENERALSTRING */
 #define sk_ASN1_GENERALSTRING_new(comp)                                    \
   ((STACK_OF(ASN1_GENERALSTRING) *)sk_new(CHECKED_CAST(                    \
@@ -277,6 +279,7 @@
       CHECKED_CAST(void (*)(void *), void (*)(ASN1_GENERALSTRING *),          \
                    free_func)))
 
+
 /* ASN1_INTEGER */
 #define sk_ASN1_INTEGER_new(comp)                                              \
   ((STACK_OF(ASN1_INTEGER) *)sk_new(CHECKED_CAST(                              \
@@ -360,6 +363,7 @@
                    copy_func),                                           \
       CHECKED_CAST(void (*)(void *), void (*)(ASN1_INTEGER *), free_func)))
 
+
 /* ASN1_OBJECT */
 #define sk_ASN1_OBJECT_new(comp)                                             \
   ((STACK_OF(ASN1_OBJECT) *)sk_new(CHECKED_CAST(                             \
@@ -441,6 +445,7 @@
                    copy_func),                                         \
       CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), free_func)))
 
+
 /* ASN1_STRING_TABLE */
 #define sk_ASN1_STRING_TABLE_new(comp)                                   \
   ((STACK_OF(ASN1_STRING_TABLE) *)sk_new(CHECKED_CAST(                   \
@@ -529,6 +534,7 @@
       CHECKED_CAST(void (*)(void *), void (*)(ASN1_STRING_TABLE *),          \
                    free_func)))
 
+
 /* ASN1_TYPE */
 #define sk_ASN1_TYPE_new(comp)     \
   ((STACK_OF(ASN1_TYPE) *)sk_new(  \
@@ -608,6 +614,7 @@
       CHECKED_CAST(void *(*)(void *), ASN1_TYPE *(*)(ASN1_TYPE *), copy_func), \
       CHECKED_CAST(void (*)(void *), void (*)(ASN1_TYPE *), free_func)))
 
+
 /* ASN1_VALUE */
 #define sk_ASN1_VALUE_new(comp)                                            \
   ((STACK_OF(ASN1_VALUE) *)sk_new(CHECKED_CAST(                            \
@@ -689,6 +696,7 @@
                    copy_func),                                        \
       CHECKED_CAST(void (*)(void *), void (*)(ASN1_VALUE *), free_func)))
 
+
 /* BIO */
 #define sk_BIO_new(comp)                 \
   ((STACK_OF(BIO) *)sk_new(CHECKED_CAST( \
@@ -758,6 +766,7 @@
       CHECKED_CAST(void *(*)(void *), BIO *(*)(BIO *), copy_func), \
       CHECKED_CAST(void (*)(void *), void (*)(BIO *), free_func)))
 
+
 /* BY_DIR_ENTRY */
 #define sk_BY_DIR_ENTRY_new(comp)                                              \
   ((STACK_OF(BY_DIR_ENTRY) *)sk_new(CHECKED_CAST(                              \
@@ -841,6 +850,7 @@
                    copy_func),                                           \
       CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_ENTRY *), free_func)))
 
+
 /* BY_DIR_HASH */
 #define sk_BY_DIR_HASH_new(comp)                                             \
   ((STACK_OF(BY_DIR_HASH) *)sk_new(CHECKED_CAST(                             \
@@ -922,6 +932,7 @@
                    copy_func),                                         \
       CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_HASH *), free_func)))
 
+
 /* CONF_VALUE */
 #define sk_CONF_VALUE_new(comp)                                            \
   ((STACK_OF(CONF_VALUE) *)sk_new(CHECKED_CAST(                            \
@@ -1003,6 +1014,7 @@
                    copy_func),                                        \
       CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func)))
 
+
 /* CRYPTO_EX_DATA_FUNCS */
 #define sk_CRYPTO_EX_DATA_FUNCS_new(comp)                                      \
   ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new(CHECKED_CAST(                      \
@@ -1096,6 +1108,7 @@
       CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_EX_DATA_FUNCS *),     \
                    free_func)))
 
+
 /* DIST_POINT */
 #define sk_DIST_POINT_new(comp)                                            \
   ((STACK_OF(DIST_POINT) *)sk_new(CHECKED_CAST(                            \
@@ -1177,6 +1190,7 @@
                    copy_func),                                        \
       CHECKED_CAST(void (*)(void *), void (*)(DIST_POINT *), free_func)))
 
+
 /* GENERAL_NAME */
 #define sk_GENERAL_NAME_new(comp)                                              \
   ((STACK_OF(GENERAL_NAME) *)sk_new(CHECKED_CAST(                              \
@@ -1260,6 +1274,7 @@
                    copy_func),                                           \
       CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAME *), free_func)))
 
+
 /* GENERAL_NAMES */
 #define sk_GENERAL_NAMES_new(comp)                 \
   ((STACK_OF(GENERAL_NAMES) *)sk_new(CHECKED_CAST( \
@@ -1344,6 +1359,7 @@
                    copy_func),                                             \
       CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAMES *), free_func)))
 
+
 /* GENERAL_SUBTREE */
 #define sk_GENERAL_SUBTREE_new(comp)                 \
   ((STACK_OF(GENERAL_SUBTREE) *)sk_new(CHECKED_CAST( \
@@ -1430,6 +1446,7 @@
                    copy_func),                                                 \
       CHECKED_CAST(void (*)(void *), void (*)(GENERAL_SUBTREE *), free_func)))
 
+
 /* MIME_HEADER */
 #define sk_MIME_HEADER_new(comp)                                             \
   ((STACK_OF(MIME_HEADER) *)sk_new(CHECKED_CAST(                             \
@@ -1511,6 +1528,95 @@
                    copy_func),                                         \
       CHECKED_CAST(void (*)(void *), void (*)(MIME_HEADER *), free_func)))
 
+
+/* PKCS7_RECIP_INFO */
+#define sk_PKCS7_RECIP_INFO_new(comp)                 \
+  ((STACK_OF(PKCS7_RECIP_INFO) *)sk_new(CHECKED_CAST( \
+      stack_cmp_func,                                 \
+      int (*)(const PKCS7_RECIP_INFO **a, const PKCS7_RECIP_INFO **b), comp)))
+
+#define sk_PKCS7_RECIP_INFO_new_null() \
+  ((STACK_OF(PKCS7_RECIP_INFO) *)sk_new_null())
+
+#define sk_PKCS7_RECIP_INFO_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))
+
+#define sk_PKCS7_RECIP_INFO_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk));
+
+#define sk_PKCS7_RECIP_INFO_value(sk, i) \
+  ((PKCS7_RECIP_INFO *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk), (i)))
+
+#define sk_PKCS7_RECIP_INFO_set(sk, i, p)                            \
+  ((PKCS7_RECIP_INFO *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), (i), \
+      CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p)))
+
+#define sk_PKCS7_RECIP_INFO_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))
+
+#define sk_PKCS7_RECIP_INFO_pop_free(sk, free_func)             \
+  sk_pop_free(                                                  \
+      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(PKCS7_RECIP_INFO *), free_func))
+
+#define sk_PKCS7_RECIP_INFO_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+            CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p), (where))
+
+#define sk_PKCS7_RECIP_INFO_delete(sk, where) \
+  ((PKCS7_RECIP_INFO *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), (where)))
+
+#define sk_PKCS7_RECIP_INFO_delete_ptr(sk, p)                   \
+  ((PKCS7_RECIP_INFO *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+      CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p)))
+
+#define sk_PKCS7_RECIP_INFO_find(sk, out_index, p)                  \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+          (out_index), CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p))
+
+#define sk_PKCS7_RECIP_INFO_shift(sk) \
+  ((PKCS7_RECIP_INFO *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)))
+
+#define sk_PKCS7_RECIP_INFO_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+          CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p))
+
+#define sk_PKCS7_RECIP_INFO_pop(sk) \
+  ((PKCS7_RECIP_INFO *)sk_pop(      \
+      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)))
+
+#define sk_PKCS7_RECIP_INFO_dup(sk)      \
+  ((STACK_OF(PKCS7_RECIP_INFO) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk)))
+
+#define sk_PKCS7_RECIP_INFO_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))
+
+#define sk_PKCS7_RECIP_INFO_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk))
+
+#define sk_PKCS7_RECIP_INFO_set_cmp_func(sk, comp)                           \
+  ((int (*)(const PKCS7_RECIP_INFO **a, const PKCS7_RECIP_INFO **b))         \
+       sk_set_cmp_func(                                                      \
+           CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk),         \
+           CHECKED_CAST(stack_cmp_func, int (*)(const PKCS7_RECIP_INFO **a,  \
+                                                const PKCS7_RECIP_INFO **b), \
+                        comp)))
+
+#define sk_PKCS7_RECIP_INFO_deep_copy(sk, copy_func, free_func)             \
+  ((STACK_OF(PKCS7_RECIP_INFO) *)sk_deep_copy(                              \
+      CHECKED_CAST(const _STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+      CHECKED_CAST(void *(*)(void *),                                       \
+                   PKCS7_RECIP_INFO *(*)(PKCS7_RECIP_INFO *), copy_func),   \
+      CHECKED_CAST(void (*)(void *), void (*)(PKCS7_RECIP_INFO *),          \
+                   free_func)))
+
+
 /* PKCS7_SIGNER_INFO */
 #define sk_PKCS7_SIGNER_INFO_new(comp)                                   \
   ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_new(CHECKED_CAST(                   \
@@ -1599,92 +1705,6 @@
       CHECKED_CAST(void (*)(void *), void (*)(PKCS7_SIGNER_INFO *),          \
                    free_func)))
 
-/* PKCS7_RECIP_INFO */
-#define sk_PKCS7_RECIP_INFO_new(comp)                 \
-  ((STACK_OF(PKCS7_RECIP_INFO) *)sk_new(CHECKED_CAST( \
-      stack_cmp_func,                                 \
-      int (*)(const PKCS7_RECIP_INFO **a, const PKCS7_RECIP_INFO **b), comp)))
-
-#define sk_PKCS7_RECIP_INFO_new_null() \
-  ((STACK_OF(PKCS7_RECIP_INFO) *)sk_new_null())
-
-#define sk_PKCS7_RECIP_INFO_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))
-
-#define sk_PKCS7_RECIP_INFO_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk));
-
-#define sk_PKCS7_RECIP_INFO_value(sk, i) \
-  ((PKCS7_RECIP_INFO *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk), (i)))
-
-#define sk_PKCS7_RECIP_INFO_set(sk, i, p)                            \
-  ((PKCS7_RECIP_INFO *)sk_set(                                       \
-      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), (i), \
-      CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p)))
-
-#define sk_PKCS7_RECIP_INFO_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))
-
-#define sk_PKCS7_RECIP_INFO_pop_free(sk, free_func)             \
-  sk_pop_free(                                                  \
-      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(PKCS7_RECIP_INFO *), free_func))
-
-#define sk_PKCS7_RECIP_INFO_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
-            CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p), (where))
-
-#define sk_PKCS7_RECIP_INFO_delete(sk, where) \
-  ((PKCS7_RECIP_INFO *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), (where)))
-
-#define sk_PKCS7_RECIP_INFO_delete_ptr(sk, p)                   \
-  ((PKCS7_RECIP_INFO *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
-      CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p)))
-
-#define sk_PKCS7_RECIP_INFO_find(sk, out_index, p)                  \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
-          (out_index), CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p))
-
-#define sk_PKCS7_RECIP_INFO_shift(sk) \
-  ((PKCS7_RECIP_INFO *)sk_shift(      \
-      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)))
-
-#define sk_PKCS7_RECIP_INFO_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
-          CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p))
-
-#define sk_PKCS7_RECIP_INFO_pop(sk) \
-  ((PKCS7_RECIP_INFO *)sk_pop(      \
-      CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)))
-
-#define sk_PKCS7_RECIP_INFO_dup(sk)      \
-  ((STACK_OF(PKCS7_RECIP_INFO) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk)))
-
-#define sk_PKCS7_RECIP_INFO_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))
-
-#define sk_PKCS7_RECIP_INFO_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk))
-
-#define sk_PKCS7_RECIP_INFO_set_cmp_func(sk, comp)                           \
-  ((int (*)(const PKCS7_RECIP_INFO **a, const PKCS7_RECIP_INFO **b))         \
-       sk_set_cmp_func(                                                      \
-           CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk),         \
-           CHECKED_CAST(stack_cmp_func, int (*)(const PKCS7_RECIP_INFO **a,  \
-                                                const PKCS7_RECIP_INFO **b), \
-                        comp)))
-
-#define sk_PKCS7_RECIP_INFO_deep_copy(sk, copy_func, free_func)             \
-  ((STACK_OF(PKCS7_RECIP_INFO) *)sk_deep_copy(                              \
-      CHECKED_CAST(const _STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk), \
-      CHECKED_CAST(void *(*)(void *),                                       \
-                   PKCS7_RECIP_INFO *(*)(PKCS7_RECIP_INFO *), copy_func),   \
-      CHECKED_CAST(void (*)(void *), void (*)(PKCS7_RECIP_INFO *),          \
-                   free_func)))
 
 /* POLICYINFO */
 #define sk_POLICYINFO_new(comp)                                            \
@@ -1767,90 +1787,6 @@
                    copy_func),                                        \
       CHECKED_CAST(void (*)(void *), void (*)(POLICYINFO *), free_func)))
 
-/* POLICYQUALINFO */
-#define sk_POLICYQUALINFO_new(comp)                 \
-  ((STACK_OF(POLICYQUALINFO) *)sk_new(CHECKED_CAST( \
-      stack_cmp_func,                               \
-      int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b), comp)))
-
-#define sk_POLICYQUALINFO_new_null() ((STACK_OF(POLICYQUALINFO) *)sk_new_null())
-
-#define sk_POLICYQUALINFO_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))
-
-#define sk_POLICYQUALINFO_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk));
-
-#define sk_POLICYQUALINFO_value(sk, i) \
-  ((POLICYQUALINFO *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk), (i)))
-
-#define sk_POLICYQUALINFO_set(sk, i, p)                            \
-  ((POLICYQUALINFO *)sk_set(                                       \
-      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (i), \
-      CHECKED_CAST(void *, POLICYQUALINFO *, p)))
-
-#define sk_POLICYQUALINFO_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))
-
-#define sk_POLICYQUALINFO_pop_free(sk, free_func)             \
-  sk_pop_free(                                                \
-      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func))
-
-#define sk_POLICYQUALINFO_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
-            CHECKED_CAST(void *, POLICYQUALINFO *, p), (where))
-
-#define sk_POLICYQUALINFO_delete(sk, where) \
-  ((POLICYQUALINFO *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (where)))
-
-#define sk_POLICYQUALINFO_delete_ptr(sk, p)                   \
-  ((POLICYQUALINFO *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
-      CHECKED_CAST(void *, POLICYQUALINFO *, p)))
-
-#define sk_POLICYQUALINFO_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (out_index), \
-          CHECKED_CAST(void *, POLICYQUALINFO *, p))
-
-#define sk_POLICYQUALINFO_shift(sk) \
-  ((POLICYQUALINFO *)sk_shift(      \
-      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)))
-
-#define sk_POLICYQUALINFO_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
-          CHECKED_CAST(void *, POLICYQUALINFO *, p))
-
-#define sk_POLICYQUALINFO_pop(sk) \
-  ((POLICYQUALINFO *)sk_pop(      \
-      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)))
-
-#define sk_POLICYQUALINFO_dup(sk)      \
-  ((STACK_OF(POLICYQUALINFO) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk)))
-
-#define sk_POLICYQUALINFO_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))
-
-#define sk_POLICYQUALINFO_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk))
-
-#define sk_POLICYQUALINFO_set_cmp_func(sk, comp)                           \
-  ((int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b))           \
-       sk_set_cmp_func(                                                    \
-           CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk),         \
-           CHECKED_CAST(stack_cmp_func, int (*)(const POLICYQUALINFO **a,  \
-                                                const POLICYQUALINFO **b), \
-                        comp)))
-
-#define sk_POLICYQUALINFO_deep_copy(sk, copy_func, free_func)                \
-  ((STACK_OF(POLICYQUALINFO) *)sk_deep_copy(                                 \
-      CHECKED_CAST(const _STACK *, const STACK_OF(POLICYQUALINFO) *, sk),    \
-      CHECKED_CAST(void *(*)(void *), POLICYQUALINFO *(*)(POLICYQUALINFO *), \
-                   copy_func),                                               \
-      CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func)))
 
 /* POLICY_MAPPING */
 #define sk_POLICY_MAPPING_new(comp)                 \
@@ -1937,6 +1873,187 @@
                    copy_func),                                               \
       CHECKED_CAST(void (*)(void *), void (*)(POLICY_MAPPING *), free_func)))
 
+
+/* POLICYQUALINFO */
+#define sk_POLICYQUALINFO_new(comp)                 \
+  ((STACK_OF(POLICYQUALINFO) *)sk_new(CHECKED_CAST( \
+      stack_cmp_func,                               \
+      int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b), comp)))
+
+#define sk_POLICYQUALINFO_new_null() ((STACK_OF(POLICYQUALINFO) *)sk_new_null())
+
+#define sk_POLICYQUALINFO_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))
+
+#define sk_POLICYQUALINFO_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk));
+
+#define sk_POLICYQUALINFO_value(sk, i) \
+  ((POLICYQUALINFO *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk), (i)))
+
+#define sk_POLICYQUALINFO_set(sk, i, p)                            \
+  ((POLICYQUALINFO *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (i), \
+      CHECKED_CAST(void *, POLICYQUALINFO *, p)))
+
+#define sk_POLICYQUALINFO_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))
+
+#define sk_POLICYQUALINFO_pop_free(sk, free_func)             \
+  sk_pop_free(                                                \
+      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func))
+
+#define sk_POLICYQUALINFO_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
+            CHECKED_CAST(void *, POLICYQUALINFO *, p), (where))
+
+#define sk_POLICYQUALINFO_delete(sk, where) \
+  ((POLICYQUALINFO *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (where)))
+
+#define sk_POLICYQUALINFO_delete_ptr(sk, p)                   \
+  ((POLICYQUALINFO *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
+      CHECKED_CAST(void *, POLICYQUALINFO *, p)))
+
+#define sk_POLICYQUALINFO_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (out_index), \
+          CHECKED_CAST(void *, POLICYQUALINFO *, p))
+
+#define sk_POLICYQUALINFO_shift(sk) \
+  ((POLICYQUALINFO *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)))
+
+#define sk_POLICYQUALINFO_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
+          CHECKED_CAST(void *, POLICYQUALINFO *, p))
+
+#define sk_POLICYQUALINFO_pop(sk) \
+  ((POLICYQUALINFO *)sk_pop(      \
+      CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)))
+
+#define sk_POLICYQUALINFO_dup(sk)      \
+  ((STACK_OF(POLICYQUALINFO) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk)))
+
+#define sk_POLICYQUALINFO_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))
+
+#define sk_POLICYQUALINFO_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk))
+
+#define sk_POLICYQUALINFO_set_cmp_func(sk, comp)                           \
+  ((int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b))           \
+       sk_set_cmp_func(                                                    \
+           CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk),         \
+           CHECKED_CAST(stack_cmp_func, int (*)(const POLICYQUALINFO **a,  \
+                                                const POLICYQUALINFO **b), \
+                        comp)))
+
+#define sk_POLICYQUALINFO_deep_copy(sk, copy_func, free_func)                \
+  ((STACK_OF(POLICYQUALINFO) *)sk_deep_copy(                                 \
+      CHECKED_CAST(const _STACK *, const STACK_OF(POLICYQUALINFO) *, sk),    \
+      CHECKED_CAST(void *(*)(void *), POLICYQUALINFO *(*)(POLICYQUALINFO *), \
+                   copy_func),                                               \
+      CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func)))
+
+
+/* RSA_additional_prime */
+#define sk_RSA_additional_prime_new(comp)                                      \
+  ((STACK_OF(RSA_additional_prime) *)sk_new(CHECKED_CAST(                      \
+      stack_cmp_func,                                                          \
+      int (*)(const RSA_additional_prime **a, const RSA_additional_prime **b), \
+      comp)))
+
+#define sk_RSA_additional_prime_new_null() \
+  ((STACK_OF(RSA_additional_prime) *)sk_new_null())
+
+#define sk_RSA_additional_prime_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk))
+
+#define sk_RSA_additional_prime_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk));
+
+#define sk_RSA_additional_prime_value(sk, i)                              \
+  ((RSA_additional_prime *)sk_value(                                      \
+      CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk), \
+      (i)))
+
+#define sk_RSA_additional_prime_set(sk, i, p)                            \
+  ((RSA_additional_prime *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), (i), \
+      CHECKED_CAST(void *, RSA_additional_prime *, p)))
+
+#define sk_RSA_additional_prime_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk))
+
+#define sk_RSA_additional_prime_pop_free(sk, free_func)                        \
+  sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk),    \
+              CHECKED_CAST(void (*)(void *), void (*)(RSA_additional_prime *), \
+                           free_func))
+
+#define sk_RSA_additional_prime_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \
+            CHECKED_CAST(void *, RSA_additional_prime *, p), (where))
+
+#define sk_RSA_additional_prime_delete(sk, where) \
+  ((RSA_additional_prime *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), (where)))
+
+#define sk_RSA_additional_prime_delete_ptr(sk, p)                   \
+  ((RSA_additional_prime *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \
+      CHECKED_CAST(void *, RSA_additional_prime *, p)))
+
+#define sk_RSA_additional_prime_find(sk, out_index, p)                  \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \
+          (out_index), CHECKED_CAST(void *, RSA_additional_prime *, p))
+
+#define sk_RSA_additional_prime_shift(sk) \
+  ((RSA_additional_prime *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)))
+
+#define sk_RSA_additional_prime_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \
+          CHECKED_CAST(void *, RSA_additional_prime *, p))
+
+#define sk_RSA_additional_prime_pop(sk) \
+  ((RSA_additional_prime *)sk_pop(      \
+      CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)))
+
+#define sk_RSA_additional_prime_dup(sk)      \
+  ((STACK_OF(RSA_additional_prime) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk)))
+
+#define sk_RSA_additional_prime_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk))
+
+#define sk_RSA_additional_prime_is_sorted(sk) \
+  sk_is_sorted(                               \
+      CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk))
+
+#define sk_RSA_additional_prime_set_cmp_func(sk, comp)                       \
+  ((int (*)(const RSA_additional_prime **a, const RSA_additional_prime **b)) \
+       sk_set_cmp_func(                                                      \
+           CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk),     \
+           CHECKED_CAST(stack_cmp_func,                                      \
+                        int (*)(const RSA_additional_prime **a,              \
+                                const RSA_additional_prime **b),             \
+                        comp)))
+
+#define sk_RSA_additional_prime_deep_copy(sk, copy_func, free_func)        \
+  ((STACK_OF(RSA_additional_prime) *)sk_deep_copy(                         \
+      CHECKED_CAST(const _STACK *, const STACK_OF(RSA_additional_prime) *, \
+                   sk),                                                    \
+      CHECKED_CAST(void *(*)(void *),                                      \
+                   RSA_additional_prime *(*)(RSA_additional_prime *),      \
+                   copy_func),                                             \
+      CHECKED_CAST(void (*)(void *), void (*)(RSA_additional_prime *),     \
+                   free_func)))
+
+
 /* SSL_COMP */
 #define sk_SSL_COMP_new(comp)                 \
   ((STACK_OF(SSL_COMP) *)sk_new(CHECKED_CAST( \
@@ -2013,6 +2130,7 @@
       CHECKED_CAST(void *(*)(void *), SSL_COMP *(*)(SSL_COMP *), copy_func), \
       CHECKED_CAST(void (*)(void *), void (*)(SSL_COMP *), free_func)))
 
+
 /* STACK_OF_X509_NAME_ENTRY */
 #define sk_STACK_OF_X509_NAME_ENTRY_new(comp)                      \
   ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new(CHECKED_CAST(      \
@@ -2109,6 +2227,7 @@
       CHECKED_CAST(void (*)(void *), void (*)(STACK_OF_X509_NAME_ENTRY *),     \
                    free_func)))
 
+
 /* SXNETID */
 #define sk_SXNETID_new(comp)                 \
   ((STACK_OF(SXNETID) *)sk_new(CHECKED_CAST( \
@@ -2185,6 +2304,77 @@
       CHECKED_CAST(void *(*)(void *), SXNETID *(*)(SXNETID *), copy_func), \
       CHECKED_CAST(void (*)(void *), void (*)(SXNETID *), free_func)))
 
+
+/* void */
+#define sk_void_new(comp)                \
+  ((STACK_OF(void)*)sk_new(CHECKED_CAST( \
+      stack_cmp_func, int (*)(const void **a, const void **b), comp)))
+
+#define sk_void_new_null() ((STACK_OF(void)*)sk_new_null())
+
+#define sk_void_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))
+
+#define sk_void_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk));
+
+#define sk_void_value(sk, i) \
+  ((void *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(void)*, sk), (i)))
+
+#define sk_void_set(sk, i, p)                                       \
+  ((void *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (i), \
+                  CHECKED_CAST(void *, void *, p)))
+
+#define sk_void_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))
+
+#define sk_void_pop_free(sk, free_func)                    \
+  sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
+              CHECKED_CAST(void (*)(void *), void (*)(void *), free_func))
+
+#define sk_void_insert(sk, p, where)                     \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
+            CHECKED_CAST(void *, void *, p), (where))
+
+#define sk_void_delete(sk, where) \
+  ((void *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (where)))
+
+#define sk_void_delete_ptr(sk, p)                                     \
+  ((void *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
+                         CHECKED_CAST(void *, void *, p)))
+
+#define sk_void_find(sk, out_index, p)                              \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (out_index), \
+          CHECKED_CAST(void *, void *, p))
+
+#define sk_void_shift(sk) \
+  ((void *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk)))
+
+#define sk_void_push(sk, p)                            \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
+          CHECKED_CAST(void *, void *, p))
+
+#define sk_void_pop(sk) \
+  ((void *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk)))
+
+#define sk_void_dup(sk) \
+  ((STACK_OF(void)*)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(void)*, sk)))
+
+#define sk_void_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))
+
+#define sk_void_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(void)*, sk))
+
+#define sk_void_set_cmp_func(sk, comp)                                      \
+  ((int (*)(const void **a, const void **b))sk_set_cmp_func(                \
+      CHECKED_CAST(_STACK *, STACK_OF(void)*, sk),                          \
+      CHECKED_CAST(stack_cmp_func, int (*)(const void **a, const void **b), \
+                   comp)))
+
+#define sk_void_deep_copy(sk, copy_func, free_func)                  \
+  ((STACK_OF(void)*)sk_deep_copy(                                    \
+      CHECKED_CAST(const _STACK *, const STACK_OF(void)*, sk),       \
+      CHECKED_CAST(void *(*)(void *), void *(*)(void *), copy_func), \
+      CHECKED_CAST(void (*)(void *), void (*)(void *), free_func)))
+
+
 /* X509 */
 #define sk_X509_new(comp)                 \
   ((STACK_OF(X509) *)sk_new(CHECKED_CAST( \
@@ -2254,6 +2444,1175 @@
       CHECKED_CAST(void *(*)(void *), X509 *(*)(X509 *), copy_func), \
       CHECKED_CAST(void (*)(void *), void (*)(X509 *), free_func)))
 
+
+/* X509_ALGOR */
+#define sk_X509_ALGOR_new(comp)                                            \
+  ((STACK_OF(X509_ALGOR) *)sk_new(CHECKED_CAST(                            \
+      stack_cmp_func, int (*)(const X509_ALGOR **a, const X509_ALGOR **b), \
+      comp)))
+
+#define sk_X509_ALGOR_new_null() ((STACK_OF(X509_ALGOR) *)sk_new_null())
+
+#define sk_X509_ALGOR_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))
+
+#define sk_X509_ALGOR_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk));
+
+#define sk_X509_ALGOR_value(sk, i) \
+  ((X509_ALGOR *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk), (i)))
+
+#define sk_X509_ALGOR_set(sk, i, p)                                         \
+  ((X509_ALGOR *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+                        (i), CHECKED_CAST(void *, X509_ALGOR *, p)))
+
+#define sk_X509_ALGOR_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))
+
+#define sk_X509_ALGOR_pop_free(sk, free_func)             \
+  sk_pop_free(                                            \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func))
+
+#define sk_X509_ALGOR_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+            CHECKED_CAST(void *, X509_ALGOR *, p), (where))
+
+#define sk_X509_ALGOR_delete(sk, where)                                        \
+  ((X509_ALGOR *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+                           (where)))
+
+#define sk_X509_ALGOR_delete_ptr(sk, p)                   \
+  ((X509_ALGOR *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+      CHECKED_CAST(void *, X509_ALGOR *, p)))
+
+#define sk_X509_ALGOR_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_ALGOR *, p))
+
+#define sk_X509_ALGOR_shift(sk) \
+  ((X509_ALGOR *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)))
+
+#define sk_X509_ALGOR_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+          CHECKED_CAST(void *, X509_ALGOR *, p))
+
+#define sk_X509_ALGOR_pop(sk) \
+  ((X509_ALGOR *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)))
+
+#define sk_X509_ALGOR_dup(sk)      \
+  ((STACK_OF(X509_ALGOR) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk)))
+
+#define sk_X509_ALGOR_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))
+
+#define sk_X509_ALGOR_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk))
+
+#define sk_X509_ALGOR_set_cmp_func(sk, comp)                             \
+  ((int (*)(const X509_ALGOR **a, const X509_ALGOR **b))sk_set_cmp_func( \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk),                \
+      CHECKED_CAST(stack_cmp_func,                                       \
+                   int (*)(const X509_ALGOR **a, const X509_ALGOR **b),  \
+                   comp)))
+
+#define sk_X509_ALGOR_deep_copy(sk, copy_func, free_func)             \
+  ((STACK_OF(X509_ALGOR) *)sk_deep_copy(                              \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_ALGOR) *, sk), \
+      CHECKED_CAST(void *(*)(void *), X509_ALGOR *(*)(X509_ALGOR *),  \
+                   copy_func),                                        \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func)))
+
+
+/* X509_ATTRIBUTE */
+#define sk_X509_ATTRIBUTE_new(comp)                 \
+  ((STACK_OF(X509_ATTRIBUTE) *)sk_new(CHECKED_CAST( \
+      stack_cmp_func,                               \
+      int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b), comp)))
+
+#define sk_X509_ATTRIBUTE_new_null() ((STACK_OF(X509_ATTRIBUTE) *)sk_new_null())
+
+#define sk_X509_ATTRIBUTE_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))
+
+#define sk_X509_ATTRIBUTE_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk));
+
+#define sk_X509_ATTRIBUTE_value(sk, i) \
+  ((X509_ATTRIBUTE *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), (i)))
+
+#define sk_X509_ATTRIBUTE_set(sk, i, p)                            \
+  ((X509_ATTRIBUTE *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (i), \
+      CHECKED_CAST(void *, X509_ATTRIBUTE *, p)))
+
+#define sk_X509_ATTRIBUTE_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))
+
+#define sk_X509_ATTRIBUTE_pop_free(sk, free_func)             \
+  sk_pop_free(                                                \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func))
+
+#define sk_X509_ATTRIBUTE_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
+            CHECKED_CAST(void *, X509_ATTRIBUTE *, p), (where))
+
+#define sk_X509_ATTRIBUTE_delete(sk, where) \
+  ((X509_ATTRIBUTE *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (where)))
+
+#define sk_X509_ATTRIBUTE_delete_ptr(sk, p)                   \
+  ((X509_ATTRIBUTE *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
+      CHECKED_CAST(void *, X509_ATTRIBUTE *, p)))
+
+#define sk_X509_ATTRIBUTE_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_ATTRIBUTE *, p))
+
+#define sk_X509_ATTRIBUTE_shift(sk) \
+  ((X509_ATTRIBUTE *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)))
+
+#define sk_X509_ATTRIBUTE_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
+          CHECKED_CAST(void *, X509_ATTRIBUTE *, p))
+
+#define sk_X509_ATTRIBUTE_pop(sk) \
+  ((X509_ATTRIBUTE *)sk_pop(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)))
+
+#define sk_X509_ATTRIBUTE_dup(sk)      \
+  ((STACK_OF(X509_ATTRIBUTE) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk)))
+
+#define sk_X509_ATTRIBUTE_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))
+
+#define sk_X509_ATTRIBUTE_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk))
+
+#define sk_X509_ATTRIBUTE_set_cmp_func(sk, comp)                           \
+  ((int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b))           \
+       sk_set_cmp_func(                                                    \
+           CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk),         \
+           CHECKED_CAST(stack_cmp_func, int (*)(const X509_ATTRIBUTE **a,  \
+                                                const X509_ATTRIBUTE **b), \
+                        comp)))
+
+#define sk_X509_ATTRIBUTE_deep_copy(sk, copy_func, free_func)                \
+  ((STACK_OF(X509_ATTRIBUTE) *)sk_deep_copy(                                 \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk),    \
+      CHECKED_CAST(void *(*)(void *), X509_ATTRIBUTE *(*)(X509_ATTRIBUTE *), \
+                   copy_func),                                               \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func)))
+
+
+/* X509_CRL */
+#define sk_X509_CRL_new(comp)                 \
+  ((STACK_OF(X509_CRL) *)sk_new(CHECKED_CAST( \
+      stack_cmp_func, int (*)(const X509_CRL **a, const X509_CRL **b), comp)))
+
+#define sk_X509_CRL_new_null() ((STACK_OF(X509_CRL) *)sk_new_null())
+
+#define sk_X509_CRL_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))
+
+#define sk_X509_CRL_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk));
+
+#define sk_X509_CRL_value(sk, i) \
+  ((X509_CRL *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk), (i)))
+
+#define sk_X509_CRL_set(sk, i, p)                                            \
+  ((X509_CRL *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (i), \
+                      CHECKED_CAST(void *, X509_CRL *, p)))
+
+#define sk_X509_CRL_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))
+
+#define sk_X509_CRL_pop_free(sk, free_func)                     \
+  sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+              CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func))
+
+#define sk_X509_CRL_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+            CHECKED_CAST(void *, X509_CRL *, p), (where))
+
+#define sk_X509_CRL_delete(sk, where)                                      \
+  ((X509_CRL *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+                         (where)))
+
+#define sk_X509_CRL_delete_ptr(sk, p)                                          \
+  ((X509_CRL *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+                             CHECKED_CAST(void *, X509_CRL *, p)))
+
+#define sk_X509_CRL_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_CRL *, p))
+
+#define sk_X509_CRL_shift(sk) \
+  ((X509_CRL *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)))
+
+#define sk_X509_CRL_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+          CHECKED_CAST(void *, X509_CRL *, p))
+
+#define sk_X509_CRL_pop(sk) \
+  ((X509_CRL *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)))
+
+#define sk_X509_CRL_dup(sk)      \
+  ((STACK_OF(X509_CRL) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk)))
+
+#define sk_X509_CRL_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))
+
+#define sk_X509_CRL_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk))
+
+#define sk_X509_CRL_set_cmp_func(sk, comp)                           \
+  ((int (*)(const X509_CRL **a, const X509_CRL **b))sk_set_cmp_func( \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk),              \
+      CHECKED_CAST(stack_cmp_func,                                   \
+                   int (*)(const X509_CRL **a, const X509_CRL **b), comp)))
+
+#define sk_X509_CRL_deep_copy(sk, copy_func, free_func)                      \
+  ((STACK_OF(X509_CRL) *)sk_deep_copy(                                       \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_CRL) *, sk),          \
+      CHECKED_CAST(void *(*)(void *), X509_CRL *(*)(X509_CRL *), copy_func), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func)))
+
+
+/* X509_EXTENSION */
+#define sk_X509_EXTENSION_new(comp)                 \
+  ((STACK_OF(X509_EXTENSION) *)sk_new(CHECKED_CAST( \
+      stack_cmp_func,                               \
+      int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b), comp)))
+
+#define sk_X509_EXTENSION_new_null() ((STACK_OF(X509_EXTENSION) *)sk_new_null())
+
+#define sk_X509_EXTENSION_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))
+
+#define sk_X509_EXTENSION_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk));
+
+#define sk_X509_EXTENSION_value(sk, i) \
+  ((X509_EXTENSION *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk), (i)))
+
+#define sk_X509_EXTENSION_set(sk, i, p)                            \
+  ((X509_EXTENSION *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (i), \
+      CHECKED_CAST(void *, X509_EXTENSION *, p)))
+
+#define sk_X509_EXTENSION_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))
+
+#define sk_X509_EXTENSION_pop_free(sk, free_func)             \
+  sk_pop_free(                                                \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func))
+
+#define sk_X509_EXTENSION_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
+            CHECKED_CAST(void *, X509_EXTENSION *, p), (where))
+
+#define sk_X509_EXTENSION_delete(sk, where) \
+  ((X509_EXTENSION *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (where)))
+
+#define sk_X509_EXTENSION_delete_ptr(sk, p)                   \
+  ((X509_EXTENSION *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
+      CHECKED_CAST(void *, X509_EXTENSION *, p)))
+
+#define sk_X509_EXTENSION_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_EXTENSION *, p))
+
+#define sk_X509_EXTENSION_shift(sk) \
+  ((X509_EXTENSION *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)))
+
+#define sk_X509_EXTENSION_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
+          CHECKED_CAST(void *, X509_EXTENSION *, p))
+
+#define sk_X509_EXTENSION_pop(sk) \
+  ((X509_EXTENSION *)sk_pop(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)))
+
+#define sk_X509_EXTENSION_dup(sk)      \
+  ((STACK_OF(X509_EXTENSION) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk)))
+
+#define sk_X509_EXTENSION_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))
+
+#define sk_X509_EXTENSION_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk))
+
+#define sk_X509_EXTENSION_set_cmp_func(sk, comp)                           \
+  ((int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b))           \
+       sk_set_cmp_func(                                                    \
+           CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk),         \
+           CHECKED_CAST(stack_cmp_func, int (*)(const X509_EXTENSION **a,  \
+                                                const X509_EXTENSION **b), \
+                        comp)))
+
+#define sk_X509_EXTENSION_deep_copy(sk, copy_func, free_func)                \
+  ((STACK_OF(X509_EXTENSION) *)sk_deep_copy(                                 \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_EXTENSION) *, sk),    \
+      CHECKED_CAST(void *(*)(void *), X509_EXTENSION *(*)(X509_EXTENSION *), \
+                   copy_func),                                               \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func)))
+
+
+/* X509_INFO */
+#define sk_X509_INFO_new(comp)     \
+  ((STACK_OF(X509_INFO) *)sk_new(  \
+      CHECKED_CAST(stack_cmp_func, \
+                   int (*)(const X509_INFO **a, const X509_INFO **b), comp)))
+
+#define sk_X509_INFO_new_null() ((STACK_OF(X509_INFO) *)sk_new_null())
+
+#define sk_X509_INFO_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))
+
+#define sk_X509_INFO_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk));
+
+#define sk_X509_INFO_value(sk, i) \
+  ((X509_INFO *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk), (i)))
+
+#define sk_X509_INFO_set(sk, i, p)                                             \
+  ((X509_INFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (i), \
+                       CHECKED_CAST(void *, X509_INFO *, p)))
+
+#define sk_X509_INFO_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))
+
+#define sk_X509_INFO_pop_free(sk, free_func)             \
+  sk_pop_free(                                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func))
+
+#define sk_X509_INFO_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+            CHECKED_CAST(void *, X509_INFO *, p), (where))
+
+#define sk_X509_INFO_delete(sk, where)                                       \
+  ((X509_INFO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+                          (where)))
+
+#define sk_X509_INFO_delete_ptr(sk, p)                   \
+  ((X509_INFO *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+      CHECKED_CAST(void *, X509_INFO *, p)))
+
+#define sk_X509_INFO_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_INFO *, p))
+
+#define sk_X509_INFO_shift(sk) \
+  ((X509_INFO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)))
+
+#define sk_X509_INFO_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+          CHECKED_CAST(void *, X509_INFO *, p))
+
+#define sk_X509_INFO_pop(sk) \
+  ((X509_INFO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)))
+
+#define sk_X509_INFO_dup(sk)      \
+  ((STACK_OF(X509_INFO) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk)))
+
+#define sk_X509_INFO_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))
+
+#define sk_X509_INFO_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk))
+
+#define sk_X509_INFO_set_cmp_func(sk, comp)                            \
+  ((int (*)(const X509_INFO **a, const X509_INFO **b))sk_set_cmp_func( \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk),               \
+      CHECKED_CAST(stack_cmp_func,                                     \
+                   int (*)(const X509_INFO **a, const X509_INFO **b), comp)))
+
+#define sk_X509_INFO_deep_copy(sk, copy_func, free_func)                       \
+  ((STACK_OF(X509_INFO) *)sk_deep_copy(                                        \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_INFO) *, sk),           \
+      CHECKED_CAST(void *(*)(void *), X509_INFO *(*)(X509_INFO *), copy_func), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func)))
+
+
+/* X509_LOOKUP */
+#define sk_X509_LOOKUP_new(comp)                                             \
+  ((STACK_OF(X509_LOOKUP) *)sk_new(CHECKED_CAST(                             \
+      stack_cmp_func, int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b), \
+      comp)))
+
+#define sk_X509_LOOKUP_new_null() ((STACK_OF(X509_LOOKUP) *)sk_new_null())
+
+#define sk_X509_LOOKUP_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))
+
+#define sk_X509_LOOKUP_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk));
+
+#define sk_X509_LOOKUP_value(sk, i) \
+  ((X509_LOOKUP *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk), (i)))
+
+#define sk_X509_LOOKUP_set(sk, i, p)                                          \
+  ((X509_LOOKUP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+                         (i), CHECKED_CAST(void *, X509_LOOKUP *, p)))
+
+#define sk_X509_LOOKUP_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))
+
+#define sk_X509_LOOKUP_pop_free(sk, free_func)             \
+  sk_pop_free(                                             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func))
+
+#define sk_X509_LOOKUP_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+            CHECKED_CAST(void *, X509_LOOKUP *, p), (where))
+
+#define sk_X509_LOOKUP_delete(sk, where) \
+  ((X509_LOOKUP *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (where)))
+
+#define sk_X509_LOOKUP_delete_ptr(sk, p)                   \
+  ((X509_LOOKUP *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+      CHECKED_CAST(void *, X509_LOOKUP *, p)))
+
+#define sk_X509_LOOKUP_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_LOOKUP *, p))
+
+#define sk_X509_LOOKUP_shift(sk) \
+  ((X509_LOOKUP *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)))
+
+#define sk_X509_LOOKUP_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+          CHECKED_CAST(void *, X509_LOOKUP *, p))
+
+#define sk_X509_LOOKUP_pop(sk) \
+  ((X509_LOOKUP *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)))
+
+#define sk_X509_LOOKUP_dup(sk)      \
+  ((STACK_OF(X509_LOOKUP) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk)))
+
+#define sk_X509_LOOKUP_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))
+
+#define sk_X509_LOOKUP_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk))
+
+#define sk_X509_LOOKUP_set_cmp_func(sk, comp)                              \
+  ((int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b))sk_set_cmp_func( \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk),                 \
+      CHECKED_CAST(stack_cmp_func,                                         \
+                   int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b),  \
+                   comp)))
+
+#define sk_X509_LOOKUP_deep_copy(sk, copy_func, free_func)             \
+  ((STACK_OF(X509_LOOKUP) *)sk_deep_copy(                              \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_LOOKUP) *, sk), \
+      CHECKED_CAST(void *(*)(void *), X509_LOOKUP *(*)(X509_LOOKUP *), \
+                   copy_func),                                         \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func)))
+
+
+/* X509_NAME */
+#define sk_X509_NAME_new(comp)     \
+  ((STACK_OF(X509_NAME) *)sk_new(  \
+      CHECKED_CAST(stack_cmp_func, \
+                   int (*)(const X509_NAME **a, const X509_NAME **b), comp)))
+
+#define sk_X509_NAME_new_null() ((STACK_OF(X509_NAME) *)sk_new_null())
+
+#define sk_X509_NAME_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))
+
+#define sk_X509_NAME_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk));
+
+#define sk_X509_NAME_value(sk, i) \
+  ((X509_NAME *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk), (i)))
+
+#define sk_X509_NAME_set(sk, i, p)                                             \
+  ((X509_NAME *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (i), \
+                       CHECKED_CAST(void *, X509_NAME *, p)))
+
+#define sk_X509_NAME_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))
+
+#define sk_X509_NAME_pop_free(sk, free_func)             \
+  sk_pop_free(                                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func))
+
+#define sk_X509_NAME_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+            CHECKED_CAST(void *, X509_NAME *, p), (where))
+
+#define sk_X509_NAME_delete(sk, where)                                       \
+  ((X509_NAME *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+                          (where)))
+
+#define sk_X509_NAME_delete_ptr(sk, p)                   \
+  ((X509_NAME *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+      CHECKED_CAST(void *, X509_NAME *, p)))
+
+#define sk_X509_NAME_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_NAME *, p))
+
+#define sk_X509_NAME_shift(sk) \
+  ((X509_NAME *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)))
+
+#define sk_X509_NAME_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+          CHECKED_CAST(void *, X509_NAME *, p))
+
+#define sk_X509_NAME_pop(sk) \
+  ((X509_NAME *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)))
+
+#define sk_X509_NAME_dup(sk)      \
+  ((STACK_OF(X509_NAME) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk)))
+
+#define sk_X509_NAME_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))
+
+#define sk_X509_NAME_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk))
+
+#define sk_X509_NAME_set_cmp_func(sk, comp)                            \
+  ((int (*)(const X509_NAME **a, const X509_NAME **b))sk_set_cmp_func( \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk),               \
+      CHECKED_CAST(stack_cmp_func,                                     \
+                   int (*)(const X509_NAME **a, const X509_NAME **b), comp)))
+
+#define sk_X509_NAME_deep_copy(sk, copy_func, free_func)                       \
+  ((STACK_OF(X509_NAME) *)sk_deep_copy(                                        \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME) *, sk),           \
+      CHECKED_CAST(void *(*)(void *), X509_NAME *(*)(X509_NAME *), copy_func), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func)))
+
+
+/* X509_NAME_ENTRY */
+#define sk_X509_NAME_ENTRY_new(comp)                 \
+  ((STACK_OF(X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \
+      stack_cmp_func,                                \
+      int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b), comp)))
+
+#define sk_X509_NAME_ENTRY_new_null() \
+  ((STACK_OF(X509_NAME_ENTRY) *)sk_new_null())
+
+#define sk_X509_NAME_ENTRY_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk));
+
+#define sk_X509_NAME_ENTRY_value(sk, i) \
+  ((X509_NAME_ENTRY *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), (i)))
+
+#define sk_X509_NAME_ENTRY_set(sk, i, p)                            \
+  ((X509_NAME_ENTRY *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (i), \
+      CHECKED_CAST(void *, X509_NAME_ENTRY *, p)))
+
+#define sk_X509_NAME_ENTRY_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_pop_free(sk, free_func)             \
+  sk_pop_free(                                                 \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func))
+
+#define sk_X509_NAME_ENTRY_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+            CHECKED_CAST(void *, X509_NAME_ENTRY *, p), (where))
+
+#define sk_X509_NAME_ENTRY_delete(sk, where) \
+  ((X509_NAME_ENTRY *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (where)))
+
+#define sk_X509_NAME_ENTRY_delete_ptr(sk, p)                   \
+  ((X509_NAME_ENTRY *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+      CHECKED_CAST(void *, X509_NAME_ENTRY *, p)))
+
+#define sk_X509_NAME_ENTRY_find(sk, out_index, p)                  \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+          (out_index), CHECKED_CAST(void *, X509_NAME_ENTRY *, p))
+
+#define sk_X509_NAME_ENTRY_shift(sk) \
+  ((X509_NAME_ENTRY *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)))
+
+#define sk_X509_NAME_ENTRY_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+          CHECKED_CAST(void *, X509_NAME_ENTRY *, p))
+
+#define sk_X509_NAME_ENTRY_pop(sk) \
+  ((X509_NAME_ENTRY *)sk_pop(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)))
+
+#define sk_X509_NAME_ENTRY_dup(sk)      \
+  ((STACK_OF(X509_NAME_ENTRY) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk)))
+
+#define sk_X509_NAME_ENTRY_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_set_cmp_func(sk, comp)                           \
+  ((int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b))          \
+       sk_set_cmp_func(                                                     \
+           CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk),         \
+           CHECKED_CAST(stack_cmp_func, int (*)(const X509_NAME_ENTRY **a,  \
+                                                const X509_NAME_ENTRY **b), \
+                        comp)))
+
+#define sk_X509_NAME_ENTRY_deep_copy(sk, copy_func, free_func)                 \
+  ((STACK_OF(X509_NAME_ENTRY) *)sk_deep_copy(                                  \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk),     \
+      CHECKED_CAST(void *(*)(void *), X509_NAME_ENTRY *(*)(X509_NAME_ENTRY *), \
+                   copy_func),                                                 \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func)))
+
+
+/* X509_OBJECT */
+#define sk_X509_OBJECT_new(comp)                                             \
+  ((STACK_OF(X509_OBJECT) *)sk_new(CHECKED_CAST(                             \
+      stack_cmp_func, int (*)(const X509_OBJECT **a, const X509_OBJECT **b), \
+      comp)))
+
+#define sk_X509_OBJECT_new_null() ((STACK_OF(X509_OBJECT) *)sk_new_null())
+
+#define sk_X509_OBJECT_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))
+
+#define sk_X509_OBJECT_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk));
+
+#define sk_X509_OBJECT_value(sk, i) \
+  ((X509_OBJECT *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk), (i)))
+
+#define sk_X509_OBJECT_set(sk, i, p)                                          \
+  ((X509_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+                         (i), CHECKED_CAST(void *, X509_OBJECT *, p)))
+
+#define sk_X509_OBJECT_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))
+
+#define sk_X509_OBJECT_pop_free(sk, free_func)             \
+  sk_pop_free(                                             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func))
+
+#define sk_X509_OBJECT_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+            CHECKED_CAST(void *, X509_OBJECT *, p), (where))
+
+#define sk_X509_OBJECT_delete(sk, where) \
+  ((X509_OBJECT *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (where)))
+
+#define sk_X509_OBJECT_delete_ptr(sk, p)                   \
+  ((X509_OBJECT *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+      CHECKED_CAST(void *, X509_OBJECT *, p)))
+
+#define sk_X509_OBJECT_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_OBJECT *, p))
+
+#define sk_X509_OBJECT_shift(sk) \
+  ((X509_OBJECT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)))
+
+#define sk_X509_OBJECT_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+          CHECKED_CAST(void *, X509_OBJECT *, p))
+
+#define sk_X509_OBJECT_pop(sk) \
+  ((X509_OBJECT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)))
+
+#define sk_X509_OBJECT_dup(sk)      \
+  ((STACK_OF(X509_OBJECT) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk)))
+
+#define sk_X509_OBJECT_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))
+
+#define sk_X509_OBJECT_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk))
+
+#define sk_X509_OBJECT_set_cmp_func(sk, comp)                              \
+  ((int (*)(const X509_OBJECT **a, const X509_OBJECT **b))sk_set_cmp_func( \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk),                 \
+      CHECKED_CAST(stack_cmp_func,                                         \
+                   int (*)(const X509_OBJECT **a, const X509_OBJECT **b),  \
+                   comp)))
+
+#define sk_X509_OBJECT_deep_copy(sk, copy_func, free_func)             \
+  ((STACK_OF(X509_OBJECT) *)sk_deep_copy(                              \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_OBJECT) *, sk), \
+      CHECKED_CAST(void *(*)(void *), X509_OBJECT *(*)(X509_OBJECT *), \
+                   copy_func),                                         \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func)))
+
+
+/* X509_POLICY_DATA */
+#define sk_X509_POLICY_DATA_new(comp)                 \
+  ((STACK_OF(X509_POLICY_DATA) *)sk_new(CHECKED_CAST( \
+      stack_cmp_func,                                 \
+      int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b), comp)))
+
+#define sk_X509_POLICY_DATA_new_null() \
+  ((STACK_OF(X509_POLICY_DATA) *)sk_new_null())
+
+#define sk_X509_POLICY_DATA_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))
+
+#define sk_X509_POLICY_DATA_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk));
+
+#define sk_X509_POLICY_DATA_value(sk, i) \
+  ((X509_POLICY_DATA *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), (i)))
+
+#define sk_X509_POLICY_DATA_set(sk, i, p)                            \
+  ((X509_POLICY_DATA *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (i), \
+      CHECKED_CAST(void *, X509_POLICY_DATA *, p)))
+
+#define sk_X509_POLICY_DATA_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))
+
+#define sk_X509_POLICY_DATA_pop_free(sk, free_func)             \
+  sk_pop_free(                                                  \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *), free_func))
+
+#define sk_X509_POLICY_DATA_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+            CHECKED_CAST(void *, X509_POLICY_DATA *, p), (where))
+
+#define sk_X509_POLICY_DATA_delete(sk, where) \
+  ((X509_POLICY_DATA *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (where)))
+
+#define sk_X509_POLICY_DATA_delete_ptr(sk, p)                   \
+  ((X509_POLICY_DATA *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+      CHECKED_CAST(void *, X509_POLICY_DATA *, p)))
+
+#define sk_X509_POLICY_DATA_find(sk, out_index, p)                  \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+          (out_index), CHECKED_CAST(void *, X509_POLICY_DATA *, p))
+
+#define sk_X509_POLICY_DATA_shift(sk) \
+  ((X509_POLICY_DATA *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)))
+
+#define sk_X509_POLICY_DATA_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+          CHECKED_CAST(void *, X509_POLICY_DATA *, p))
+
+#define sk_X509_POLICY_DATA_pop(sk) \
+  ((X509_POLICY_DATA *)sk_pop(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)))
+
+#define sk_X509_POLICY_DATA_dup(sk)      \
+  ((STACK_OF(X509_POLICY_DATA) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk)))
+
+#define sk_X509_POLICY_DATA_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))
+
+#define sk_X509_POLICY_DATA_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk))
+
+#define sk_X509_POLICY_DATA_set_cmp_func(sk, comp)                           \
+  ((int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b))         \
+       sk_set_cmp_func(                                                      \
+           CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk),         \
+           CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_DATA **a,  \
+                                                const X509_POLICY_DATA **b), \
+                        comp)))
+
+#define sk_X509_POLICY_DATA_deep_copy(sk, copy_func, free_func)             \
+  ((STACK_OF(X509_POLICY_DATA) *)sk_deep_copy(                              \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), \
+      CHECKED_CAST(void *(*)(void *),                                       \
+                   X509_POLICY_DATA *(*)(X509_POLICY_DATA *), copy_func),   \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *),          \
+                   free_func)))
+
+
+/* X509_POLICY_NODE */
+#define sk_X509_POLICY_NODE_new(comp)                 \
+  ((STACK_OF(X509_POLICY_NODE) *)sk_new(CHECKED_CAST( \
+      stack_cmp_func,                                 \
+      int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b), comp)))
+
+#define sk_X509_POLICY_NODE_new_null() \
+  ((STACK_OF(X509_POLICY_NODE) *)sk_new_null())
+
+#define sk_X509_POLICY_NODE_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))
+
+#define sk_X509_POLICY_NODE_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk));
+
+#define sk_X509_POLICY_NODE_value(sk, i) \
+  ((X509_POLICY_NODE *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), (i)))
+
+#define sk_X509_POLICY_NODE_set(sk, i, p)                            \
+  ((X509_POLICY_NODE *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (i), \
+      CHECKED_CAST(void *, X509_POLICY_NODE *, p)))
+
+#define sk_X509_POLICY_NODE_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))
+
+#define sk_X509_POLICY_NODE_pop_free(sk, free_func)             \
+  sk_pop_free(                                                  \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *), free_func))
+
+#define sk_X509_POLICY_NODE_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+            CHECKED_CAST(void *, X509_POLICY_NODE *, p), (where))
+
+#define sk_X509_POLICY_NODE_delete(sk, where) \
+  ((X509_POLICY_NODE *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (where)))
+
+#define sk_X509_POLICY_NODE_delete_ptr(sk, p)                   \
+  ((X509_POLICY_NODE *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+      CHECKED_CAST(void *, X509_POLICY_NODE *, p)))
+
+#define sk_X509_POLICY_NODE_find(sk, out_index, p)                  \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+          (out_index), CHECKED_CAST(void *, X509_POLICY_NODE *, p))
+
+#define sk_X509_POLICY_NODE_shift(sk) \
+  ((X509_POLICY_NODE *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)))
+
+#define sk_X509_POLICY_NODE_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+          CHECKED_CAST(void *, X509_POLICY_NODE *, p))
+
+#define sk_X509_POLICY_NODE_pop(sk) \
+  ((X509_POLICY_NODE *)sk_pop(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)))
+
+#define sk_X509_POLICY_NODE_dup(sk)      \
+  ((STACK_OF(X509_POLICY_NODE) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk)))
+
+#define sk_X509_POLICY_NODE_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))
+
+#define sk_X509_POLICY_NODE_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk))
+
+#define sk_X509_POLICY_NODE_set_cmp_func(sk, comp)                           \
+  ((int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b))         \
+       sk_set_cmp_func(                                                      \
+           CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk),         \
+           CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_NODE **a,  \
+                                                const X509_POLICY_NODE **b), \
+                        comp)))
+
+#define sk_X509_POLICY_NODE_deep_copy(sk, copy_func, free_func)             \
+  ((STACK_OF(X509_POLICY_NODE) *)sk_deep_copy(                              \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), \
+      CHECKED_CAST(void *(*)(void *),                                       \
+                   X509_POLICY_NODE *(*)(X509_POLICY_NODE *), copy_func),   \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *),          \
+                   free_func)))
+
+
+/* X509_PURPOSE */
+#define sk_X509_PURPOSE_new(comp)                                              \
+  ((STACK_OF(X509_PURPOSE) *)sk_new(CHECKED_CAST(                              \
+      stack_cmp_func, int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b), \
+      comp)))
+
+#define sk_X509_PURPOSE_new_null() ((STACK_OF(X509_PURPOSE) *)sk_new_null())
+
+#define sk_X509_PURPOSE_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))
+
+#define sk_X509_PURPOSE_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk));
+
+#define sk_X509_PURPOSE_value(sk, i) \
+  ((X509_PURPOSE *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk), (i)))
+
+#define sk_X509_PURPOSE_set(sk, i, p)                            \
+  ((X509_PURPOSE *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (i), \
+      CHECKED_CAST(void *, X509_PURPOSE *, p)))
+
+#define sk_X509_PURPOSE_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))
+
+#define sk_X509_PURPOSE_pop_free(sk, free_func)             \
+  sk_pop_free(                                              \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func))
+
+#define sk_X509_PURPOSE_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
+            CHECKED_CAST(void *, X509_PURPOSE *, p), (where))
+
+#define sk_X509_PURPOSE_delete(sk, where) \
+  ((X509_PURPOSE *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (where)))
+
+#define sk_X509_PURPOSE_delete_ptr(sk, p)                   \
+  ((X509_PURPOSE *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
+      CHECKED_CAST(void *, X509_PURPOSE *, p)))
+
+#define sk_X509_PURPOSE_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_PURPOSE *, p))
+
+#define sk_X509_PURPOSE_shift(sk) \
+  ((X509_PURPOSE *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)))
+
+#define sk_X509_PURPOSE_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
+          CHECKED_CAST(void *, X509_PURPOSE *, p))
+
+#define sk_X509_PURPOSE_pop(sk) \
+  ((X509_PURPOSE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)))
+
+#define sk_X509_PURPOSE_dup(sk)      \
+  ((STACK_OF(X509_PURPOSE) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk)))
+
+#define sk_X509_PURPOSE_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))
+
+#define sk_X509_PURPOSE_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk))
+
+#define sk_X509_PURPOSE_set_cmp_func(sk, comp)                               \
+  ((int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b))sk_set_cmp_func( \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk),                  \
+      CHECKED_CAST(stack_cmp_func,                                           \
+                   int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b),  \
+                   comp)))
+
+#define sk_X509_PURPOSE_deep_copy(sk, copy_func, free_func)              \
+  ((STACK_OF(X509_PURPOSE) *)sk_deep_copy(                               \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_PURPOSE) *, sk),  \
+      CHECKED_CAST(void *(*)(void *), X509_PURPOSE *(*)(X509_PURPOSE *), \
+                   copy_func),                                           \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func)))
+
+
+/* X509_REVOKED */
+#define sk_X509_REVOKED_new(comp)                                              \
+  ((STACK_OF(X509_REVOKED) *)sk_new(CHECKED_CAST(                              \
+      stack_cmp_func, int (*)(const X509_REVOKED **a, const X509_REVOKED **b), \
+      comp)))
+
+#define sk_X509_REVOKED_new_null() ((STACK_OF(X509_REVOKED) *)sk_new_null())
+
+#define sk_X509_REVOKED_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))
+
+#define sk_X509_REVOKED_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk));
+
+#define sk_X509_REVOKED_value(sk, i) \
+  ((X509_REVOKED *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk), (i)))
+
+#define sk_X509_REVOKED_set(sk, i, p)                            \
+  ((X509_REVOKED *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (i), \
+      CHECKED_CAST(void *, X509_REVOKED *, p)))
+
+#define sk_X509_REVOKED_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))
+
+#define sk_X509_REVOKED_pop_free(sk, free_func)             \
+  sk_pop_free(                                              \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func))
+
+#define sk_X509_REVOKED_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
+            CHECKED_CAST(void *, X509_REVOKED *, p), (where))
+
+#define sk_X509_REVOKED_delete(sk, where) \
+  ((X509_REVOKED *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (where)))
+
+#define sk_X509_REVOKED_delete_ptr(sk, p)                   \
+  ((X509_REVOKED *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
+      CHECKED_CAST(void *, X509_REVOKED *, p)))
+
+#define sk_X509_REVOKED_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_REVOKED *, p))
+
+#define sk_X509_REVOKED_shift(sk) \
+  ((X509_REVOKED *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)))
+
+#define sk_X509_REVOKED_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
+          CHECKED_CAST(void *, X509_REVOKED *, p))
+
+#define sk_X509_REVOKED_pop(sk) \
+  ((X509_REVOKED *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)))
+
+#define sk_X509_REVOKED_dup(sk)      \
+  ((STACK_OF(X509_REVOKED) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk)))
+
+#define sk_X509_REVOKED_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))
+
+#define sk_X509_REVOKED_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk))
+
+#define sk_X509_REVOKED_set_cmp_func(sk, comp)                               \
+  ((int (*)(const X509_REVOKED **a, const X509_REVOKED **b))sk_set_cmp_func( \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk),                  \
+      CHECKED_CAST(stack_cmp_func,                                           \
+                   int (*)(const X509_REVOKED **a, const X509_REVOKED **b),  \
+                   comp)))
+
+#define sk_X509_REVOKED_deep_copy(sk, copy_func, free_func)              \
+  ((STACK_OF(X509_REVOKED) *)sk_deep_copy(                               \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_REVOKED) *, sk),  \
+      CHECKED_CAST(void *(*)(void *), X509_REVOKED *(*)(X509_REVOKED *), \
+                   copy_func),                                           \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func)))
+
+
+/* X509_TRUST */
+#define sk_X509_TRUST_new(comp)                                            \
+  ((STACK_OF(X509_TRUST) *)sk_new(CHECKED_CAST(                            \
+      stack_cmp_func, int (*)(const X509_TRUST **a, const X509_TRUST **b), \
+      comp)))
+
+#define sk_X509_TRUST_new_null() ((STACK_OF(X509_TRUST) *)sk_new_null())
+
+#define sk_X509_TRUST_num(sk) \
+  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))
+
+#define sk_X509_TRUST_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk));
+
+#define sk_X509_TRUST_value(sk, i) \
+  ((X509_TRUST *)sk_value(         \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk), (i)))
+
+#define sk_X509_TRUST_set(sk, i, p)                                         \
+  ((X509_TRUST *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+                        (i), CHECKED_CAST(void *, X509_TRUST *, p)))
+
+#define sk_X509_TRUST_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))
+
+#define sk_X509_TRUST_pop_free(sk, free_func)             \
+  sk_pop_free(                                            \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func))
+
+#define sk_X509_TRUST_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+            CHECKED_CAST(void *, X509_TRUST *, p), (where))
+
+#define sk_X509_TRUST_delete(sk, where)                                        \
+  ((X509_TRUST *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+                           (where)))
+
+#define sk_X509_TRUST_delete_ptr(sk, p)                   \
+  ((X509_TRUST *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+      CHECKED_CAST(void *, X509_TRUST *, p)))
+
+#define sk_X509_TRUST_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), (out_index), \
+          CHECKED_CAST(void *, X509_TRUST *, p))
+
+#define sk_X509_TRUST_shift(sk) \
+  ((X509_TRUST *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)))
+
+#define sk_X509_TRUST_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+          CHECKED_CAST(void *, X509_TRUST *, p))
+
+#define sk_X509_TRUST_pop(sk) \
+  ((X509_TRUST *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)))
+
+#define sk_X509_TRUST_dup(sk)      \
+  ((STACK_OF(X509_TRUST) *)sk_dup( \
+      CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk)))
+
+#define sk_X509_TRUST_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))
+
+#define sk_X509_TRUST_is_sorted(sk) \
+  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk))
+
+#define sk_X509_TRUST_set_cmp_func(sk, comp)                             \
+  ((int (*)(const X509_TRUST **a, const X509_TRUST **b))sk_set_cmp_func( \
+      CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk),                \
+      CHECKED_CAST(stack_cmp_func,                                       \
+                   int (*)(const X509_TRUST **a, const X509_TRUST **b),  \
+                   comp)))
+
+#define sk_X509_TRUST_deep_copy(sk, copy_func, free_func)             \
+  ((STACK_OF(X509_TRUST) *)sk_deep_copy(                              \
+      CHECKED_CAST(const _STACK *, const STACK_OF(X509_TRUST) *, sk), \
+      CHECKED_CAST(void *(*)(void *), X509_TRUST *(*)(X509_TRUST *),  \
+                   copy_func),                                        \
+      CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func)))
+
+
 /* X509V3_EXT_METHOD */
 #define sk_X509V3_EXT_METHOD_new(comp)                                   \
   ((STACK_OF(X509V3_EXT_METHOD) *)sk_new(CHECKED_CAST(                   \
@@ -2342,1159 +3701,6 @@
       CHECKED_CAST(void (*)(void *), void (*)(X509V3_EXT_METHOD *),          \
                    free_func)))
 
-/* X509_ALGOR */
-#define sk_X509_ALGOR_new(comp)                                            \
-  ((STACK_OF(X509_ALGOR) *)sk_new(CHECKED_CAST(                            \
-      stack_cmp_func, int (*)(const X509_ALGOR **a, const X509_ALGOR **b), \
-      comp)))
-
-#define sk_X509_ALGOR_new_null() ((STACK_OF(X509_ALGOR) *)sk_new_null())
-
-#define sk_X509_ALGOR_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))
-
-#define sk_X509_ALGOR_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk));
-
-#define sk_X509_ALGOR_value(sk, i) \
-  ((X509_ALGOR *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk), (i)))
-
-#define sk_X509_ALGOR_set(sk, i, p)                                         \
-  ((X509_ALGOR *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
-                        (i), CHECKED_CAST(void *, X509_ALGOR *, p)))
-
-#define sk_X509_ALGOR_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))
-
-#define sk_X509_ALGOR_pop_free(sk, free_func)             \
-  sk_pop_free(                                            \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func))
-
-#define sk_X509_ALGOR_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
-            CHECKED_CAST(void *, X509_ALGOR *, p), (where))
-
-#define sk_X509_ALGOR_delete(sk, where)                                        \
-  ((X509_ALGOR *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
-                           (where)))
-
-#define sk_X509_ALGOR_delete_ptr(sk, p)                   \
-  ((X509_ALGOR *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
-      CHECKED_CAST(void *, X509_ALGOR *, p)))
-
-#define sk_X509_ALGOR_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_ALGOR *, p))
-
-#define sk_X509_ALGOR_shift(sk) \
-  ((X509_ALGOR *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)))
-
-#define sk_X509_ALGOR_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
-          CHECKED_CAST(void *, X509_ALGOR *, p))
-
-#define sk_X509_ALGOR_pop(sk) \
-  ((X509_ALGOR *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)))
-
-#define sk_X509_ALGOR_dup(sk)      \
-  ((STACK_OF(X509_ALGOR) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk)))
-
-#define sk_X509_ALGOR_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))
-
-#define sk_X509_ALGOR_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk))
-
-#define sk_X509_ALGOR_set_cmp_func(sk, comp)                             \
-  ((int (*)(const X509_ALGOR **a, const X509_ALGOR **b))sk_set_cmp_func( \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk),                \
-      CHECKED_CAST(stack_cmp_func,                                       \
-                   int (*)(const X509_ALGOR **a, const X509_ALGOR **b),  \
-                   comp)))
-
-#define sk_X509_ALGOR_deep_copy(sk, copy_func, free_func)             \
-  ((STACK_OF(X509_ALGOR) *)sk_deep_copy(                              \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_ALGOR) *, sk), \
-      CHECKED_CAST(void *(*)(void *), X509_ALGOR *(*)(X509_ALGOR *),  \
-                   copy_func),                                        \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func)))
-
-/* X509_ATTRIBUTE */
-#define sk_X509_ATTRIBUTE_new(comp)                 \
-  ((STACK_OF(X509_ATTRIBUTE) *)sk_new(CHECKED_CAST( \
-      stack_cmp_func,                               \
-      int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b), comp)))
-
-#define sk_X509_ATTRIBUTE_new_null() ((STACK_OF(X509_ATTRIBUTE) *)sk_new_null())
-
-#define sk_X509_ATTRIBUTE_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))
-
-#define sk_X509_ATTRIBUTE_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk));
-
-#define sk_X509_ATTRIBUTE_value(sk, i) \
-  ((X509_ATTRIBUTE *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), (i)))
-
-#define sk_X509_ATTRIBUTE_set(sk, i, p)                            \
-  ((X509_ATTRIBUTE *)sk_set(                                       \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (i), \
-      CHECKED_CAST(void *, X509_ATTRIBUTE *, p)))
-
-#define sk_X509_ATTRIBUTE_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))
-
-#define sk_X509_ATTRIBUTE_pop_free(sk, free_func)             \
-  sk_pop_free(                                                \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func))
-
-#define sk_X509_ATTRIBUTE_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
-            CHECKED_CAST(void *, X509_ATTRIBUTE *, p), (where))
-
-#define sk_X509_ATTRIBUTE_delete(sk, where) \
-  ((X509_ATTRIBUTE *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (where)))
-
-#define sk_X509_ATTRIBUTE_delete_ptr(sk, p)                   \
-  ((X509_ATTRIBUTE *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
-      CHECKED_CAST(void *, X509_ATTRIBUTE *, p)))
-
-#define sk_X509_ATTRIBUTE_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_ATTRIBUTE *, p))
-
-#define sk_X509_ATTRIBUTE_shift(sk) \
-  ((X509_ATTRIBUTE *)sk_shift(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)))
-
-#define sk_X509_ATTRIBUTE_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
-          CHECKED_CAST(void *, X509_ATTRIBUTE *, p))
-
-#define sk_X509_ATTRIBUTE_pop(sk) \
-  ((X509_ATTRIBUTE *)sk_pop(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)))
-
-#define sk_X509_ATTRIBUTE_dup(sk)      \
-  ((STACK_OF(X509_ATTRIBUTE) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk)))
-
-#define sk_X509_ATTRIBUTE_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))
-
-#define sk_X509_ATTRIBUTE_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk))
-
-#define sk_X509_ATTRIBUTE_set_cmp_func(sk, comp)                           \
-  ((int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b))           \
-       sk_set_cmp_func(                                                    \
-           CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk),         \
-           CHECKED_CAST(stack_cmp_func, int (*)(const X509_ATTRIBUTE **a,  \
-                                                const X509_ATTRIBUTE **b), \
-                        comp)))
-
-#define sk_X509_ATTRIBUTE_deep_copy(sk, copy_func, free_func)                \
-  ((STACK_OF(X509_ATTRIBUTE) *)sk_deep_copy(                                 \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk),    \
-      CHECKED_CAST(void *(*)(void *), X509_ATTRIBUTE *(*)(X509_ATTRIBUTE *), \
-                   copy_func),                                               \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func)))
-
-/* X509_CRL */
-#define sk_X509_CRL_new(comp)                 \
-  ((STACK_OF(X509_CRL) *)sk_new(CHECKED_CAST( \
-      stack_cmp_func, int (*)(const X509_CRL **a, const X509_CRL **b), comp)))
-
-#define sk_X509_CRL_new_null() ((STACK_OF(X509_CRL) *)sk_new_null())
-
-#define sk_X509_CRL_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))
-
-#define sk_X509_CRL_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk));
-
-#define sk_X509_CRL_value(sk, i) \
-  ((X509_CRL *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk), (i)))
-
-#define sk_X509_CRL_set(sk, i, p)                                            \
-  ((X509_CRL *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (i), \
-                      CHECKED_CAST(void *, X509_CRL *, p)))
-
-#define sk_X509_CRL_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))
-
-#define sk_X509_CRL_pop_free(sk, free_func)                     \
-  sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
-              CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func))
-
-#define sk_X509_CRL_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
-            CHECKED_CAST(void *, X509_CRL *, p), (where))
-
-#define sk_X509_CRL_delete(sk, where)                                      \
-  ((X509_CRL *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
-                         (where)))
-
-#define sk_X509_CRL_delete_ptr(sk, p)                                          \
-  ((X509_CRL *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
-                             CHECKED_CAST(void *, X509_CRL *, p)))
-
-#define sk_X509_CRL_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_CRL *, p))
-
-#define sk_X509_CRL_shift(sk) \
-  ((X509_CRL *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)))
-
-#define sk_X509_CRL_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
-          CHECKED_CAST(void *, X509_CRL *, p))
-
-#define sk_X509_CRL_pop(sk) \
-  ((X509_CRL *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)))
-
-#define sk_X509_CRL_dup(sk)      \
-  ((STACK_OF(X509_CRL) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk)))
-
-#define sk_X509_CRL_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))
-
-#define sk_X509_CRL_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk))
-
-#define sk_X509_CRL_set_cmp_func(sk, comp)                           \
-  ((int (*)(const X509_CRL **a, const X509_CRL **b))sk_set_cmp_func( \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk),              \
-      CHECKED_CAST(stack_cmp_func,                                   \
-                   int (*)(const X509_CRL **a, const X509_CRL **b), comp)))
-
-#define sk_X509_CRL_deep_copy(sk, copy_func, free_func)                      \
-  ((STACK_OF(X509_CRL) *)sk_deep_copy(                                       \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_CRL) *, sk),          \
-      CHECKED_CAST(void *(*)(void *), X509_CRL *(*)(X509_CRL *), copy_func), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func)))
-
-/* X509_EXTENSION */
-#define sk_X509_EXTENSION_new(comp)                 \
-  ((STACK_OF(X509_EXTENSION) *)sk_new(CHECKED_CAST( \
-      stack_cmp_func,                               \
-      int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b), comp)))
-
-#define sk_X509_EXTENSION_new_null() ((STACK_OF(X509_EXTENSION) *)sk_new_null())
-
-#define sk_X509_EXTENSION_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))
-
-#define sk_X509_EXTENSION_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk));
-
-#define sk_X509_EXTENSION_value(sk, i) \
-  ((X509_EXTENSION *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk), (i)))
-
-#define sk_X509_EXTENSION_set(sk, i, p)                            \
-  ((X509_EXTENSION *)sk_set(                                       \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (i), \
-      CHECKED_CAST(void *, X509_EXTENSION *, p)))
-
-#define sk_X509_EXTENSION_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))
-
-#define sk_X509_EXTENSION_pop_free(sk, free_func)             \
-  sk_pop_free(                                                \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func))
-
-#define sk_X509_EXTENSION_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
-            CHECKED_CAST(void *, X509_EXTENSION *, p), (where))
-
-#define sk_X509_EXTENSION_delete(sk, where) \
-  ((X509_EXTENSION *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (where)))
-
-#define sk_X509_EXTENSION_delete_ptr(sk, p)                   \
-  ((X509_EXTENSION *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
-      CHECKED_CAST(void *, X509_EXTENSION *, p)))
-
-#define sk_X509_EXTENSION_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_EXTENSION *, p))
-
-#define sk_X509_EXTENSION_shift(sk) \
-  ((X509_EXTENSION *)sk_shift(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)))
-
-#define sk_X509_EXTENSION_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
-          CHECKED_CAST(void *, X509_EXTENSION *, p))
-
-#define sk_X509_EXTENSION_pop(sk) \
-  ((X509_EXTENSION *)sk_pop(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)))
-
-#define sk_X509_EXTENSION_dup(sk)      \
-  ((STACK_OF(X509_EXTENSION) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk)))
-
-#define sk_X509_EXTENSION_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))
-
-#define sk_X509_EXTENSION_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk))
-
-#define sk_X509_EXTENSION_set_cmp_func(sk, comp)                           \
-  ((int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b))           \
-       sk_set_cmp_func(                                                    \
-           CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk),         \
-           CHECKED_CAST(stack_cmp_func, int (*)(const X509_EXTENSION **a,  \
-                                                const X509_EXTENSION **b), \
-                        comp)))
-
-#define sk_X509_EXTENSION_deep_copy(sk, copy_func, free_func)                \
-  ((STACK_OF(X509_EXTENSION) *)sk_deep_copy(                                 \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_EXTENSION) *, sk),    \
-      CHECKED_CAST(void *(*)(void *), X509_EXTENSION *(*)(X509_EXTENSION *), \
-                   copy_func),                                               \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func)))
-
-/* X509_INFO */
-#define sk_X509_INFO_new(comp)     \
-  ((STACK_OF(X509_INFO) *)sk_new(  \
-      CHECKED_CAST(stack_cmp_func, \
-                   int (*)(const X509_INFO **a, const X509_INFO **b), comp)))
-
-#define sk_X509_INFO_new_null() ((STACK_OF(X509_INFO) *)sk_new_null())
-
-#define sk_X509_INFO_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))
-
-#define sk_X509_INFO_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk));
-
-#define sk_X509_INFO_value(sk, i) \
-  ((X509_INFO *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk), (i)))
-
-#define sk_X509_INFO_set(sk, i, p)                                             \
-  ((X509_INFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (i), \
-                       CHECKED_CAST(void *, X509_INFO *, p)))
-
-#define sk_X509_INFO_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))
-
-#define sk_X509_INFO_pop_free(sk, free_func)             \
-  sk_pop_free(                                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func))
-
-#define sk_X509_INFO_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
-            CHECKED_CAST(void *, X509_INFO *, p), (where))
-
-#define sk_X509_INFO_delete(sk, where)                                       \
-  ((X509_INFO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
-                          (where)))
-
-#define sk_X509_INFO_delete_ptr(sk, p)                   \
-  ((X509_INFO *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
-      CHECKED_CAST(void *, X509_INFO *, p)))
-
-#define sk_X509_INFO_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_INFO *, p))
-
-#define sk_X509_INFO_shift(sk) \
-  ((X509_INFO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)))
-
-#define sk_X509_INFO_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
-          CHECKED_CAST(void *, X509_INFO *, p))
-
-#define sk_X509_INFO_pop(sk) \
-  ((X509_INFO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)))
-
-#define sk_X509_INFO_dup(sk)      \
-  ((STACK_OF(X509_INFO) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk)))
-
-#define sk_X509_INFO_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))
-
-#define sk_X509_INFO_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk))
-
-#define sk_X509_INFO_set_cmp_func(sk, comp)                            \
-  ((int (*)(const X509_INFO **a, const X509_INFO **b))sk_set_cmp_func( \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk),               \
-      CHECKED_CAST(stack_cmp_func,                                     \
-                   int (*)(const X509_INFO **a, const X509_INFO **b), comp)))
-
-#define sk_X509_INFO_deep_copy(sk, copy_func, free_func)                       \
-  ((STACK_OF(X509_INFO) *)sk_deep_copy(                                        \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_INFO) *, sk),           \
-      CHECKED_CAST(void *(*)(void *), X509_INFO *(*)(X509_INFO *), copy_func), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func)))
-
-/* X509_LOOKUP */
-#define sk_X509_LOOKUP_new(comp)                                             \
-  ((STACK_OF(X509_LOOKUP) *)sk_new(CHECKED_CAST(                             \
-      stack_cmp_func, int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b), \
-      comp)))
-
-#define sk_X509_LOOKUP_new_null() ((STACK_OF(X509_LOOKUP) *)sk_new_null())
-
-#define sk_X509_LOOKUP_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))
-
-#define sk_X509_LOOKUP_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk));
-
-#define sk_X509_LOOKUP_value(sk, i) \
-  ((X509_LOOKUP *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk), (i)))
-
-#define sk_X509_LOOKUP_set(sk, i, p)                                          \
-  ((X509_LOOKUP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
-                         (i), CHECKED_CAST(void *, X509_LOOKUP *, p)))
-
-#define sk_X509_LOOKUP_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))
-
-#define sk_X509_LOOKUP_pop_free(sk, free_func)             \
-  sk_pop_free(                                             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func))
-
-#define sk_X509_LOOKUP_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
-            CHECKED_CAST(void *, X509_LOOKUP *, p), (where))
-
-#define sk_X509_LOOKUP_delete(sk, where) \
-  ((X509_LOOKUP *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (where)))
-
-#define sk_X509_LOOKUP_delete_ptr(sk, p)                   \
-  ((X509_LOOKUP *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
-      CHECKED_CAST(void *, X509_LOOKUP *, p)))
-
-#define sk_X509_LOOKUP_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_LOOKUP *, p))
-
-#define sk_X509_LOOKUP_shift(sk) \
-  ((X509_LOOKUP *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)))
-
-#define sk_X509_LOOKUP_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
-          CHECKED_CAST(void *, X509_LOOKUP *, p))
-
-#define sk_X509_LOOKUP_pop(sk) \
-  ((X509_LOOKUP *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)))
-
-#define sk_X509_LOOKUP_dup(sk)      \
-  ((STACK_OF(X509_LOOKUP) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk)))
-
-#define sk_X509_LOOKUP_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))
-
-#define sk_X509_LOOKUP_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk))
-
-#define sk_X509_LOOKUP_set_cmp_func(sk, comp)                              \
-  ((int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b))sk_set_cmp_func( \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk),                 \
-      CHECKED_CAST(stack_cmp_func,                                         \
-                   int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b),  \
-                   comp)))
-
-#define sk_X509_LOOKUP_deep_copy(sk, copy_func, free_func)             \
-  ((STACK_OF(X509_LOOKUP) *)sk_deep_copy(                              \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_LOOKUP) *, sk), \
-      CHECKED_CAST(void *(*)(void *), X509_LOOKUP *(*)(X509_LOOKUP *), \
-                   copy_func),                                         \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func)))
-
-/* X509_NAME */
-#define sk_X509_NAME_new(comp)     \
-  ((STACK_OF(X509_NAME) *)sk_new(  \
-      CHECKED_CAST(stack_cmp_func, \
-                   int (*)(const X509_NAME **a, const X509_NAME **b), comp)))
-
-#define sk_X509_NAME_new_null() ((STACK_OF(X509_NAME) *)sk_new_null())
-
-#define sk_X509_NAME_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))
-
-#define sk_X509_NAME_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk));
-
-#define sk_X509_NAME_value(sk, i) \
-  ((X509_NAME *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk), (i)))
-
-#define sk_X509_NAME_set(sk, i, p)                                             \
-  ((X509_NAME *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (i), \
-                       CHECKED_CAST(void *, X509_NAME *, p)))
-
-#define sk_X509_NAME_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))
-
-#define sk_X509_NAME_pop_free(sk, free_func)             \
-  sk_pop_free(                                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func))
-
-#define sk_X509_NAME_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
-            CHECKED_CAST(void *, X509_NAME *, p), (where))
-
-#define sk_X509_NAME_delete(sk, where)                                       \
-  ((X509_NAME *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
-                          (where)))
-
-#define sk_X509_NAME_delete_ptr(sk, p)                   \
-  ((X509_NAME *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
-      CHECKED_CAST(void *, X509_NAME *, p)))
-
-#define sk_X509_NAME_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_NAME *, p))
-
-#define sk_X509_NAME_shift(sk) \
-  ((X509_NAME *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)))
-
-#define sk_X509_NAME_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
-          CHECKED_CAST(void *, X509_NAME *, p))
-
-#define sk_X509_NAME_pop(sk) \
-  ((X509_NAME *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)))
-
-#define sk_X509_NAME_dup(sk)      \
-  ((STACK_OF(X509_NAME) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk)))
-
-#define sk_X509_NAME_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))
-
-#define sk_X509_NAME_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk))
-
-#define sk_X509_NAME_set_cmp_func(sk, comp)                            \
-  ((int (*)(const X509_NAME **a, const X509_NAME **b))sk_set_cmp_func( \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk),               \
-      CHECKED_CAST(stack_cmp_func,                                     \
-                   int (*)(const X509_NAME **a, const X509_NAME **b), comp)))
-
-#define sk_X509_NAME_deep_copy(sk, copy_func, free_func)                       \
-  ((STACK_OF(X509_NAME) *)sk_deep_copy(                                        \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME) *, sk),           \
-      CHECKED_CAST(void *(*)(void *), X509_NAME *(*)(X509_NAME *), copy_func), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func)))
-
-/* X509_NAME_ENTRY */
-#define sk_X509_NAME_ENTRY_new(comp)                 \
-  ((STACK_OF(X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \
-      stack_cmp_func,                                \
-      int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b), comp)))
-
-#define sk_X509_NAME_ENTRY_new_null() \
-  ((STACK_OF(X509_NAME_ENTRY) *)sk_new_null())
-
-#define sk_X509_NAME_ENTRY_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
-
-#define sk_X509_NAME_ENTRY_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk));
-
-#define sk_X509_NAME_ENTRY_value(sk, i) \
-  ((X509_NAME_ENTRY *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), (i)))
-
-#define sk_X509_NAME_ENTRY_set(sk, i, p)                            \
-  ((X509_NAME_ENTRY *)sk_set(                                       \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (i), \
-      CHECKED_CAST(void *, X509_NAME_ENTRY *, p)))
-
-#define sk_X509_NAME_ENTRY_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
-
-#define sk_X509_NAME_ENTRY_pop_free(sk, free_func)             \
-  sk_pop_free(                                                 \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func))
-
-#define sk_X509_NAME_ENTRY_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
-            CHECKED_CAST(void *, X509_NAME_ENTRY *, p), (where))
-
-#define sk_X509_NAME_ENTRY_delete(sk, where) \
-  ((X509_NAME_ENTRY *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (where)))
-
-#define sk_X509_NAME_ENTRY_delete_ptr(sk, p)                   \
-  ((X509_NAME_ENTRY *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
-      CHECKED_CAST(void *, X509_NAME_ENTRY *, p)))
-
-#define sk_X509_NAME_ENTRY_find(sk, out_index, p)                  \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
-          (out_index), CHECKED_CAST(void *, X509_NAME_ENTRY *, p))
-
-#define sk_X509_NAME_ENTRY_shift(sk) \
-  ((X509_NAME_ENTRY *)sk_shift(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)))
-
-#define sk_X509_NAME_ENTRY_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
-          CHECKED_CAST(void *, X509_NAME_ENTRY *, p))
-
-#define sk_X509_NAME_ENTRY_pop(sk) \
-  ((X509_NAME_ENTRY *)sk_pop(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)))
-
-#define sk_X509_NAME_ENTRY_dup(sk)      \
-  ((STACK_OF(X509_NAME_ENTRY) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk)))
-
-#define sk_X509_NAME_ENTRY_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
-
-#define sk_X509_NAME_ENTRY_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk))
-
-#define sk_X509_NAME_ENTRY_set_cmp_func(sk, comp)                           \
-  ((int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b))          \
-       sk_set_cmp_func(                                                     \
-           CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk),         \
-           CHECKED_CAST(stack_cmp_func, int (*)(const X509_NAME_ENTRY **a,  \
-                                                const X509_NAME_ENTRY **b), \
-                        comp)))
-
-#define sk_X509_NAME_ENTRY_deep_copy(sk, copy_func, free_func)                 \
-  ((STACK_OF(X509_NAME_ENTRY) *)sk_deep_copy(                                  \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk),     \
-      CHECKED_CAST(void *(*)(void *), X509_NAME_ENTRY *(*)(X509_NAME_ENTRY *), \
-                   copy_func),                                                 \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func)))
-
-/* X509_OBJECT */
-#define sk_X509_OBJECT_new(comp)                                             \
-  ((STACK_OF(X509_OBJECT) *)sk_new(CHECKED_CAST(                             \
-      stack_cmp_func, int (*)(const X509_OBJECT **a, const X509_OBJECT **b), \
-      comp)))
-
-#define sk_X509_OBJECT_new_null() ((STACK_OF(X509_OBJECT) *)sk_new_null())
-
-#define sk_X509_OBJECT_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))
-
-#define sk_X509_OBJECT_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk));
-
-#define sk_X509_OBJECT_value(sk, i) \
-  ((X509_OBJECT *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk), (i)))
-
-#define sk_X509_OBJECT_set(sk, i, p)                                          \
-  ((X509_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
-                         (i), CHECKED_CAST(void *, X509_OBJECT *, p)))
-
-#define sk_X509_OBJECT_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))
-
-#define sk_X509_OBJECT_pop_free(sk, free_func)             \
-  sk_pop_free(                                             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func))
-
-#define sk_X509_OBJECT_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
-            CHECKED_CAST(void *, X509_OBJECT *, p), (where))
-
-#define sk_X509_OBJECT_delete(sk, where) \
-  ((X509_OBJECT *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (where)))
-
-#define sk_X509_OBJECT_delete_ptr(sk, p)                   \
-  ((X509_OBJECT *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
-      CHECKED_CAST(void *, X509_OBJECT *, p)))
-
-#define sk_X509_OBJECT_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_OBJECT *, p))
-
-#define sk_X509_OBJECT_shift(sk) \
-  ((X509_OBJECT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)))
-
-#define sk_X509_OBJECT_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
-          CHECKED_CAST(void *, X509_OBJECT *, p))
-
-#define sk_X509_OBJECT_pop(sk) \
-  ((X509_OBJECT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)))
-
-#define sk_X509_OBJECT_dup(sk)      \
-  ((STACK_OF(X509_OBJECT) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk)))
-
-#define sk_X509_OBJECT_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))
-
-#define sk_X509_OBJECT_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk))
-
-#define sk_X509_OBJECT_set_cmp_func(sk, comp)                              \
-  ((int (*)(const X509_OBJECT **a, const X509_OBJECT **b))sk_set_cmp_func( \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk),                 \
-      CHECKED_CAST(stack_cmp_func,                                         \
-                   int (*)(const X509_OBJECT **a, const X509_OBJECT **b),  \
-                   comp)))
-
-#define sk_X509_OBJECT_deep_copy(sk, copy_func, free_func)             \
-  ((STACK_OF(X509_OBJECT) *)sk_deep_copy(                              \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_OBJECT) *, sk), \
-      CHECKED_CAST(void *(*)(void *), X509_OBJECT *(*)(X509_OBJECT *), \
-                   copy_func),                                         \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func)))
-
-/* X509_POLICY_DATA */
-#define sk_X509_POLICY_DATA_new(comp)                 \
-  ((STACK_OF(X509_POLICY_DATA) *)sk_new(CHECKED_CAST( \
-      stack_cmp_func,                                 \
-      int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b), comp)))
-
-#define sk_X509_POLICY_DATA_new_null() \
-  ((STACK_OF(X509_POLICY_DATA) *)sk_new_null())
-
-#define sk_X509_POLICY_DATA_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))
-
-#define sk_X509_POLICY_DATA_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk));
-
-#define sk_X509_POLICY_DATA_value(sk, i) \
-  ((X509_POLICY_DATA *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), (i)))
-
-#define sk_X509_POLICY_DATA_set(sk, i, p)                            \
-  ((X509_POLICY_DATA *)sk_set(                                       \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (i), \
-      CHECKED_CAST(void *, X509_POLICY_DATA *, p)))
-
-#define sk_X509_POLICY_DATA_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))
-
-#define sk_X509_POLICY_DATA_pop_free(sk, free_func)             \
-  sk_pop_free(                                                  \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *), free_func))
-
-#define sk_X509_POLICY_DATA_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
-            CHECKED_CAST(void *, X509_POLICY_DATA *, p), (where))
-
-#define sk_X509_POLICY_DATA_delete(sk, where) \
-  ((X509_POLICY_DATA *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (where)))
-
-#define sk_X509_POLICY_DATA_delete_ptr(sk, p)                   \
-  ((X509_POLICY_DATA *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
-      CHECKED_CAST(void *, X509_POLICY_DATA *, p)))
-
-#define sk_X509_POLICY_DATA_find(sk, out_index, p)                  \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
-          (out_index), CHECKED_CAST(void *, X509_POLICY_DATA *, p))
-
-#define sk_X509_POLICY_DATA_shift(sk) \
-  ((X509_POLICY_DATA *)sk_shift(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)))
-
-#define sk_X509_POLICY_DATA_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
-          CHECKED_CAST(void *, X509_POLICY_DATA *, p))
-
-#define sk_X509_POLICY_DATA_pop(sk) \
-  ((X509_POLICY_DATA *)sk_pop(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)))
-
-#define sk_X509_POLICY_DATA_dup(sk)      \
-  ((STACK_OF(X509_POLICY_DATA) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk)))
-
-#define sk_X509_POLICY_DATA_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))
-
-#define sk_X509_POLICY_DATA_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk))
-
-#define sk_X509_POLICY_DATA_set_cmp_func(sk, comp)                           \
-  ((int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b))         \
-       sk_set_cmp_func(                                                      \
-           CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk),         \
-           CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_DATA **a,  \
-                                                const X509_POLICY_DATA **b), \
-                        comp)))
-
-#define sk_X509_POLICY_DATA_deep_copy(sk, copy_func, free_func)             \
-  ((STACK_OF(X509_POLICY_DATA) *)sk_deep_copy(                              \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), \
-      CHECKED_CAST(void *(*)(void *),                                       \
-                   X509_POLICY_DATA *(*)(X509_POLICY_DATA *), copy_func),   \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *),          \
-                   free_func)))
-
-/* X509_POLICY_NODE */
-#define sk_X509_POLICY_NODE_new(comp)                 \
-  ((STACK_OF(X509_POLICY_NODE) *)sk_new(CHECKED_CAST( \
-      stack_cmp_func,                                 \
-      int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b), comp)))
-
-#define sk_X509_POLICY_NODE_new_null() \
-  ((STACK_OF(X509_POLICY_NODE) *)sk_new_null())
-
-#define sk_X509_POLICY_NODE_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))
-
-#define sk_X509_POLICY_NODE_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk));
-
-#define sk_X509_POLICY_NODE_value(sk, i) \
-  ((X509_POLICY_NODE *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), (i)))
-
-#define sk_X509_POLICY_NODE_set(sk, i, p)                            \
-  ((X509_POLICY_NODE *)sk_set(                                       \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (i), \
-      CHECKED_CAST(void *, X509_POLICY_NODE *, p)))
-
-#define sk_X509_POLICY_NODE_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))
-
-#define sk_X509_POLICY_NODE_pop_free(sk, free_func)             \
-  sk_pop_free(                                                  \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *), free_func))
-
-#define sk_X509_POLICY_NODE_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
-            CHECKED_CAST(void *, X509_POLICY_NODE *, p), (where))
-
-#define sk_X509_POLICY_NODE_delete(sk, where) \
-  ((X509_POLICY_NODE *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (where)))
-
-#define sk_X509_POLICY_NODE_delete_ptr(sk, p)                   \
-  ((X509_POLICY_NODE *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
-      CHECKED_CAST(void *, X509_POLICY_NODE *, p)))
-
-#define sk_X509_POLICY_NODE_find(sk, out_index, p)                  \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
-          (out_index), CHECKED_CAST(void *, X509_POLICY_NODE *, p))
-
-#define sk_X509_POLICY_NODE_shift(sk) \
-  ((X509_POLICY_NODE *)sk_shift(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)))
-
-#define sk_X509_POLICY_NODE_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
-          CHECKED_CAST(void *, X509_POLICY_NODE *, p))
-
-#define sk_X509_POLICY_NODE_pop(sk) \
-  ((X509_POLICY_NODE *)sk_pop(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)))
-
-#define sk_X509_POLICY_NODE_dup(sk)      \
-  ((STACK_OF(X509_POLICY_NODE) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk)))
-
-#define sk_X509_POLICY_NODE_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))
-
-#define sk_X509_POLICY_NODE_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk))
-
-#define sk_X509_POLICY_NODE_set_cmp_func(sk, comp)                           \
-  ((int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b))         \
-       sk_set_cmp_func(                                                      \
-           CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk),         \
-           CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_NODE **a,  \
-                                                const X509_POLICY_NODE **b), \
-                        comp)))
-
-#define sk_X509_POLICY_NODE_deep_copy(sk, copy_func, free_func)             \
-  ((STACK_OF(X509_POLICY_NODE) *)sk_deep_copy(                              \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), \
-      CHECKED_CAST(void *(*)(void *),                                       \
-                   X509_POLICY_NODE *(*)(X509_POLICY_NODE *), copy_func),   \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *),          \
-                   free_func)))
-
-/* X509_PURPOSE */
-#define sk_X509_PURPOSE_new(comp)                                              \
-  ((STACK_OF(X509_PURPOSE) *)sk_new(CHECKED_CAST(                              \
-      stack_cmp_func, int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b), \
-      comp)))
-
-#define sk_X509_PURPOSE_new_null() ((STACK_OF(X509_PURPOSE) *)sk_new_null())
-
-#define sk_X509_PURPOSE_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))
-
-#define sk_X509_PURPOSE_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk));
-
-#define sk_X509_PURPOSE_value(sk, i) \
-  ((X509_PURPOSE *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk), (i)))
-
-#define sk_X509_PURPOSE_set(sk, i, p)                            \
-  ((X509_PURPOSE *)sk_set(                                       \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (i), \
-      CHECKED_CAST(void *, X509_PURPOSE *, p)))
-
-#define sk_X509_PURPOSE_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))
-
-#define sk_X509_PURPOSE_pop_free(sk, free_func)             \
-  sk_pop_free(                                              \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func))
-
-#define sk_X509_PURPOSE_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
-            CHECKED_CAST(void *, X509_PURPOSE *, p), (where))
-
-#define sk_X509_PURPOSE_delete(sk, where) \
-  ((X509_PURPOSE *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (where)))
-
-#define sk_X509_PURPOSE_delete_ptr(sk, p)                   \
-  ((X509_PURPOSE *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
-      CHECKED_CAST(void *, X509_PURPOSE *, p)))
-
-#define sk_X509_PURPOSE_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_PURPOSE *, p))
-
-#define sk_X509_PURPOSE_shift(sk) \
-  ((X509_PURPOSE *)sk_shift(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)))
-
-#define sk_X509_PURPOSE_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
-          CHECKED_CAST(void *, X509_PURPOSE *, p))
-
-#define sk_X509_PURPOSE_pop(sk) \
-  ((X509_PURPOSE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)))
-
-#define sk_X509_PURPOSE_dup(sk)      \
-  ((STACK_OF(X509_PURPOSE) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk)))
-
-#define sk_X509_PURPOSE_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))
-
-#define sk_X509_PURPOSE_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk))
-
-#define sk_X509_PURPOSE_set_cmp_func(sk, comp)                               \
-  ((int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b))sk_set_cmp_func( \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk),                  \
-      CHECKED_CAST(stack_cmp_func,                                           \
-                   int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b),  \
-                   comp)))
-
-#define sk_X509_PURPOSE_deep_copy(sk, copy_func, free_func)              \
-  ((STACK_OF(X509_PURPOSE) *)sk_deep_copy(                               \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_PURPOSE) *, sk),  \
-      CHECKED_CAST(void *(*)(void *), X509_PURPOSE *(*)(X509_PURPOSE *), \
-                   copy_func),                                           \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func)))
-
-/* X509_REVOKED */
-#define sk_X509_REVOKED_new(comp)                                              \
-  ((STACK_OF(X509_REVOKED) *)sk_new(CHECKED_CAST(                              \
-      stack_cmp_func, int (*)(const X509_REVOKED **a, const X509_REVOKED **b), \
-      comp)))
-
-#define sk_X509_REVOKED_new_null() ((STACK_OF(X509_REVOKED) *)sk_new_null())
-
-#define sk_X509_REVOKED_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))
-
-#define sk_X509_REVOKED_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk));
-
-#define sk_X509_REVOKED_value(sk, i) \
-  ((X509_REVOKED *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk), (i)))
-
-#define sk_X509_REVOKED_set(sk, i, p)                            \
-  ((X509_REVOKED *)sk_set(                                       \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (i), \
-      CHECKED_CAST(void *, X509_REVOKED *, p)))
-
-#define sk_X509_REVOKED_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))
-
-#define sk_X509_REVOKED_pop_free(sk, free_func)             \
-  sk_pop_free(                                              \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func))
-
-#define sk_X509_REVOKED_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
-            CHECKED_CAST(void *, X509_REVOKED *, p), (where))
-
-#define sk_X509_REVOKED_delete(sk, where) \
-  ((X509_REVOKED *)sk_delete(             \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (where)))
-
-#define sk_X509_REVOKED_delete_ptr(sk, p)                   \
-  ((X509_REVOKED *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
-      CHECKED_CAST(void *, X509_REVOKED *, p)))
-
-#define sk_X509_REVOKED_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_REVOKED *, p))
-
-#define sk_X509_REVOKED_shift(sk) \
-  ((X509_REVOKED *)sk_shift(      \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)))
-
-#define sk_X509_REVOKED_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
-          CHECKED_CAST(void *, X509_REVOKED *, p))
-
-#define sk_X509_REVOKED_pop(sk) \
-  ((X509_REVOKED *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)))
-
-#define sk_X509_REVOKED_dup(sk)      \
-  ((STACK_OF(X509_REVOKED) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk)))
-
-#define sk_X509_REVOKED_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))
-
-#define sk_X509_REVOKED_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk))
-
-#define sk_X509_REVOKED_set_cmp_func(sk, comp)                               \
-  ((int (*)(const X509_REVOKED **a, const X509_REVOKED **b))sk_set_cmp_func( \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk),                  \
-      CHECKED_CAST(stack_cmp_func,                                           \
-                   int (*)(const X509_REVOKED **a, const X509_REVOKED **b),  \
-                   comp)))
-
-#define sk_X509_REVOKED_deep_copy(sk, copy_func, free_func)              \
-  ((STACK_OF(X509_REVOKED) *)sk_deep_copy(                               \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_REVOKED) *, sk),  \
-      CHECKED_CAST(void *(*)(void *), X509_REVOKED *(*)(X509_REVOKED *), \
-                   copy_func),                                           \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func)))
-
-/* X509_TRUST */
-#define sk_X509_TRUST_new(comp)                                            \
-  ((STACK_OF(X509_TRUST) *)sk_new(CHECKED_CAST(                            \
-      stack_cmp_func, int (*)(const X509_TRUST **a, const X509_TRUST **b), \
-      comp)))
-
-#define sk_X509_TRUST_new_null() ((STACK_OF(X509_TRUST) *)sk_new_null())
-
-#define sk_X509_TRUST_num(sk) \
-  sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))
-
-#define sk_X509_TRUST_zero(sk) \
-  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk));
-
-#define sk_X509_TRUST_value(sk, i) \
-  ((X509_TRUST *)sk_value(         \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk), (i)))
-
-#define sk_X509_TRUST_set(sk, i, p)                                         \
-  ((X509_TRUST *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
-                        (i), CHECKED_CAST(void *, X509_TRUST *, p)))
-
-#define sk_X509_TRUST_free(sk) \
-  sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))
-
-#define sk_X509_TRUST_pop_free(sk, free_func)             \
-  sk_pop_free(                                            \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func))
-
-#define sk_X509_TRUST_insert(sk, p, where)                      \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
-            CHECKED_CAST(void *, X509_TRUST *, p), (where))
-
-#define sk_X509_TRUST_delete(sk, where)                                        \
-  ((X509_TRUST *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
-                           (where)))
-
-#define sk_X509_TRUST_delete_ptr(sk, p)                   \
-  ((X509_TRUST *)sk_delete_ptr(                           \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
-      CHECKED_CAST(void *, X509_TRUST *, p)))
-
-#define sk_X509_TRUST_find(sk, out_index, p)                               \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), (out_index), \
-          CHECKED_CAST(void *, X509_TRUST *, p))
-
-#define sk_X509_TRUST_shift(sk) \
-  ((X509_TRUST *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)))
-
-#define sk_X509_TRUST_push(sk, p)                             \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
-          CHECKED_CAST(void *, X509_TRUST *, p))
-
-#define sk_X509_TRUST_pop(sk) \
-  ((X509_TRUST *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)))
-
-#define sk_X509_TRUST_dup(sk)      \
-  ((STACK_OF(X509_TRUST) *)sk_dup( \
-      CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk)))
-
-#define sk_X509_TRUST_sort(sk) \
-  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))
-
-#define sk_X509_TRUST_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk))
-
-#define sk_X509_TRUST_set_cmp_func(sk, comp)                             \
-  ((int (*)(const X509_TRUST **a, const X509_TRUST **b))sk_set_cmp_func( \
-      CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk),                \
-      CHECKED_CAST(stack_cmp_func,                                       \
-                   int (*)(const X509_TRUST **a, const X509_TRUST **b),  \
-                   comp)))
-
-#define sk_X509_TRUST_deep_copy(sk, copy_func, free_func)             \
-  ((STACK_OF(X509_TRUST) *)sk_deep_copy(                              \
-      CHECKED_CAST(const _STACK *, const STACK_OF(X509_TRUST) *, sk), \
-      CHECKED_CAST(void *(*)(void *), X509_TRUST *(*)(X509_TRUST *),  \
-                   copy_func),                                        \
-      CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func)))
 
 /* X509_VERIFY_PARAM */
 #define sk_X509_VERIFY_PARAM_new(comp)                                   \
@@ -3584,74 +3790,6 @@
       CHECKED_CAST(void (*)(void *), void (*)(X509_VERIFY_PARAM *),          \
                    free_func)))
 
-/* void */
-#define sk_void_new(comp)                \
-  ((STACK_OF(void)*)sk_new(CHECKED_CAST( \
-      stack_cmp_func, int (*)(const void **a, const void **b), comp)))
-
-#define sk_void_new_null() ((STACK_OF(void)*)sk_new_null())
-
-#define sk_void_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))
-
-#define sk_void_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk));
-
-#define sk_void_value(sk, i) \
-  ((void *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(void)*, sk), (i)))
-
-#define sk_void_set(sk, i, p)                                       \
-  ((void *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (i), \
-                  CHECKED_CAST(void *, void *, p)))
-
-#define sk_void_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))
-
-#define sk_void_pop_free(sk, free_func)                    \
-  sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
-              CHECKED_CAST(void (*)(void *), void (*)(void *), free_func))
-
-#define sk_void_insert(sk, p, where)                     \
-  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
-            CHECKED_CAST(void *, void *, p), (where))
-
-#define sk_void_delete(sk, where) \
-  ((void *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (where)))
-
-#define sk_void_delete_ptr(sk, p)                                     \
-  ((void *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
-                         CHECKED_CAST(void *, void *, p)))
-
-#define sk_void_find(sk, out_index, p)                              \
-  sk_find(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (out_index), \
-          CHECKED_CAST(void *, void *, p))
-
-#define sk_void_shift(sk) \
-  ((void *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk)))
-
-#define sk_void_push(sk, p)                            \
-  sk_push(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
-          CHECKED_CAST(void *, void *, p))
-
-#define sk_void_pop(sk) \
-  ((void *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk)))
-
-#define sk_void_dup(sk) \
-  ((STACK_OF(void)*)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(void)*, sk)))
-
-#define sk_void_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))
-
-#define sk_void_is_sorted(sk) \
-  sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(void)*, sk))
-
-#define sk_void_set_cmp_func(sk, comp)                                      \
-  ((int (*)(const void **a, const void **b))sk_set_cmp_func(                \
-      CHECKED_CAST(_STACK *, STACK_OF(void)*, sk),                          \
-      CHECKED_CAST(stack_cmp_func, int (*)(const void **a, const void **b), \
-                   comp)))
-
-#define sk_void_deep_copy(sk, copy_func, free_func)                  \
-  ((STACK_OF(void)*)sk_deep_copy(                                    \
-      CHECKED_CAST(const _STACK *, const STACK_OF(void)*, sk),       \
-      CHECKED_CAST(void *(*)(void *), void *(*)(void *), copy_func), \
-      CHECKED_CAST(void (*)(void *), void (*)(void *), free_func)))
 
 /* SRTP_PROTECTION_PROFILE */
 #define sk_SRTP_PROTECTION_PROFILE_new(comp)                            \
@@ -3750,6 +3888,7 @@
       CHECKED_CAST(void (*)(void *),                                          \
                    void (*)(const SRTP_PROTECTION_PROFILE *), free_func)))
 
+
 /* SSL_CIPHER */
 #define sk_SSL_CIPHER_new(comp)                 \
   ((STACK_OF(SSL_CIPHER) *)sk_new(CHECKED_CAST( \
@@ -3835,6 +3974,7 @@
       CHECKED_CAST(void (*)(void *), void (*)(const SSL_CIPHER *),        \
                    free_func)))
 
+
 /* OPENSSL_STRING */
 #define sk_OPENSSL_STRING_new(comp)                 \
   ((STACK_OF(OPENSSL_STRING) *)sk_new(CHECKED_CAST( \
@@ -3920,6 +4060,7 @@
                    copy_func),                                            \
       CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_STRING), free_func)))
 
+
 /* OPENSSL_BLOCK */
 #define sk_OPENSSL_BLOCK_new(comp)                                             \
   ((STACK_OF(OPENSSL_BLOCK) *)sk_new(CHECKED_CAST(                             \
diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt
index 74c1ac8..7907745 100644
--- a/tool/CMakeLists.txt
+++ b/tool/CMakeLists.txt
@@ -7,6 +7,7 @@
   client.cc
   const.cc
   digest.cc
+  genrsa.cc
   pkcs12.cc
   rand.cc
   server.cc
diff --git a/tool/args.cc b/tool/args.cc
index a164476..850d9d8 100644
--- a/tool/args.cc
+++ b/tool/args.cc
@@ -15,6 +15,7 @@
 #include <string>
 #include <vector>
 
+#include <limits.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -75,3 +76,28 @@
     fprintf(stderr, "%s\t%s\n", templ->name, templ->description);
   }
 }
+
+bool GetUnsigned(unsigned *out, const std::string &arg_name,
+                 unsigned default_value,
+                 const std::map<std::string, std::string> &args) {
+  const auto &it = args.find(arg_name);
+  if (it == args.end()) {
+    *out = default_value;
+    return true;
+  }
+
+  const std::string &value = it->second;
+  if (value.empty()) {
+    return false;
+  }
+
+  char *endptr;
+  unsigned long int num = strtoul(value.c_str(), &endptr, 10);
+  if (*endptr ||
+      num > UINT_MAX) {
+    return false;
+  }
+
+  *out = num;
+  return true;
+}
diff --git a/tool/const.cc b/tool/const.cc
index 5222667..b364cd4 100644
--- a/tool/const.cc
+++ b/tool/const.cc
@@ -323,4 +323,113 @@
 
 size_t kDERRSAPrivate4096Len = sizeof(kDERRSAPrivate4096);
 
-}
+uint8_t kDERRSAPrivate3Prime2048[] = {
+    0x30, 0x82, 0x04, 0xd7, 0x02, 0x01, 0x01, 0x02, 0x82, 0x01, 0x00, 0x62,
+    0x91, 0xe9, 0xea, 0xb3, 0x5d, 0x6c, 0x29, 0xae, 0x21, 0x83, 0xbb, 0xb5,
+    0x82, 0xb1, 0x9e, 0xea, 0xe0, 0x64, 0x5b, 0x1e, 0x2f, 0x5e, 0x2c, 0x0a,
+    0x80, 0x3d, 0x29, 0xd4, 0xfa, 0x9a, 0xe7, 0x44, 0xe6, 0x21, 0xbd, 0x98,
+    0xc0, 0x3d, 0xe0, 0x53, 0x59, 0xae, 0xd3, 0x3e, 0xfe, 0xc4, 0xc2, 0xc4,
+    0x5a, 0x5a, 0x89, 0x07, 0xf4, 0x4f, 0xdc, 0xb0, 0x6a, 0xd4, 0x3e, 0x99,
+    0x7d, 0x7a, 0x97, 0x26, 0x4e, 0xe1, 0x93, 0xca, 0x6e, 0xed, 0x07, 0xfc,
+    0xb4, 0xfa, 0x95, 0x1e, 0x73, 0x7b, 0x86, 0x08, 0x6a, 0xb9, 0xd4, 0x29,
+    0xb0, 0x7e, 0x59, 0xb7, 0x9d, 0x7b, 0xeb, 0x67, 0x6e, 0xf0, 0xbb, 0x5e,
+    0xcf, 0xb9, 0xcd, 0x58, 0x93, 0xf0, 0xe7, 0x88, 0x17, 0x6c, 0x0d, 0x76,
+    0x1e, 0xb9, 0x27, 0x9a, 0x4d, 0x02, 0x16, 0xb6, 0x49, 0x6d, 0xa7, 0x83,
+    0x23, 0x4d, 0x02, 0x48, 0x0c, 0x0c, 0x1f, 0x0e, 0x85, 0x21, 0xe3, 0x06,
+    0x76, 0x0a, 0x73, 0xe6, 0xc1, 0x21, 0xfa, 0x30, 0x18, 0x78, 0x29, 0x5c,
+    0x31, 0xd0, 0x29, 0xae, 0x6f, 0x7d, 0x87, 0xd8, 0x2f, 0x16, 0xfa, 0xbc,
+    0x67, 0x8a, 0x94, 0x71, 0x59, 0x9b, 0xec, 0x22, 0x40, 0x55, 0x9f, 0xc2,
+    0x94, 0xb5, 0xbd, 0x78, 0x01, 0xc9, 0xef, 0x18, 0xc8, 0x6d, 0x0d, 0xdc,
+    0x53, 0x42, 0xb2, 0x5c, 0xab, 0x65, 0x05, 0xbd, 0x35, 0x08, 0x85, 0x1b,
+    0xf8, 0xe9, 0x47, 0xbc, 0xfe, 0xc5, 0xae, 0x47, 0x29, 0x63, 0x44, 0x8e,
+    0x4d, 0xb7, 0x47, 0xab, 0x0d, 0xd8, 0x76, 0x68, 0x4f, 0xc7, 0x07, 0x02,
+    0xe4, 0x86, 0xb0, 0xcf, 0xd8, 0x19, 0xad, 0xf4, 0x85, 0x76, 0x8b, 0x3b,
+    0x4e, 0x40, 0x8d, 0x29, 0x7a, 0x8a, 0x07, 0x36, 0xf3, 0x78, 0xae, 0x17,
+    0xa6, 0x8f, 0x53, 0x58, 0x65, 0x4c, 0x86, 0x9e, 0xd7, 0x8b, 0xec, 0x38,
+    0x4f, 0x99, 0xc7, 0x02, 0x01, 0x03, 0x02, 0x82, 0x01, 0x00, 0x41, 0xb6,
+    0x9b, 0xf1, 0xcc, 0xe8, 0xf2, 0xc6, 0x74, 0x16, 0x57, 0xd2, 0x79, 0x01,
+    0xcb, 0xbf, 0x47, 0x40, 0x42, 0xe7, 0x69, 0x74, 0xe9, 0x72, 0xb1, 0xaa,
+    0xd3, 0x71, 0x38, 0xa7, 0x11, 0xef, 0x83, 0x44, 0x16, 0x7e, 0x65, 0xd5,
+    0x7e, 0x95, 0x8c, 0xe6, 0x74, 0x8c, 0xd4, 0xa9, 0xd8, 0x81, 0xd8, 0x3c,
+    0x3c, 0x5b, 0x5a, 0xa2, 0xdf, 0xe8, 0x75, 0x9c, 0x8d, 0x7f, 0x10, 0xfe,
+    0x51, 0xba, 0x19, 0x89, 0xeb, 0xb7, 0xdc, 0x49, 0xf3, 0x5a, 0xa8, 0x78,
+    0xa7, 0x0e, 0x14, 0x4c, 0xfd, 0x04, 0x05, 0x9c, 0x7b, 0xe2, 0xc5, 0xa3,
+    0x04, 0xee, 0xd9, 0x4c, 0xfd, 0x7d, 0x47, 0xb0, 0x0d, 0x9b, 0x3d, 0x70,
+    0x91, 0x81, 0x2c, 0xab, 0x2b, 0x87, 0xad, 0x11, 0x68, 0x24, 0xfc, 0x2b,
+    0xd4, 0xee, 0x5e, 0x28, 0xeb, 0x6d, 0xab, 0xde, 0x0f, 0x77, 0x15, 0x58,
+    0x76, 0x39, 0xc9, 0x59, 0x3a, 0x7f, 0x19, 0x9d, 0xc6, 0x7e, 0x86, 0xe4,
+    0xd5, 0x38, 0x70, 0x9e, 0xae, 0xb9, 0xfb, 0x33, 0x33, 0xd1, 0x0c, 0x2d,
+    0xab, 0x01, 0x20, 0xe1, 0x8b, 0x29, 0x99, 0xd3, 0xeb, 0x87, 0x05, 0x72,
+    0xaa, 0x43, 0x58, 0x64, 0x8e, 0x9e, 0x31, 0xdb, 0x45, 0x9b, 0x2b, 0xac,
+    0x58, 0x80, 0x5d, 0x33, 0xa2, 0x43, 0x05, 0x96, 0xcc, 0xca, 0x2d, 0x04,
+    0x5f, 0xd6, 0xb7, 0x3d, 0x8b, 0x8f, 0x2d, 0xa3, 0xa5, 0xf8, 0x73, 0xf5,
+    0xd7, 0xc0, 0x19, 0xff, 0x10, 0xe6, 0xee, 0x3a, 0x26, 0x2f, 0xe1, 0x64,
+    0x3d, 0x11, 0xcd, 0x2d, 0xe4, 0x0a, 0x84, 0x27, 0xe3, 0xcb, 0x16, 0x62,
+    0x19, 0xe7, 0xe3, 0x0d, 0x13, 0xe8, 0x09, 0x5a, 0x53, 0xd0, 0x20, 0x56,
+    0x15, 0xf5, 0xb3, 0x67, 0xac, 0xa1, 0xb5, 0x94, 0x6b, 0xab, 0xdc, 0x71,
+    0xc7, 0xbf, 0x0a, 0xde, 0x76, 0xf5, 0x03, 0xa0, 0x30, 0xd8, 0x27, 0x9d,
+    0x00, 0x2b, 0x02, 0x57, 0x00, 0xf1, 0x4f, 0xc2, 0x86, 0x13, 0x06, 0x17,
+    0xf7, 0x69, 0x7e, 0x37, 0xdf, 0x67, 0xc5, 0x32, 0xa0, 0x74, 0x1c, 0x32,
+    0x69, 0x0f, 0x9f, 0x08, 0x88, 0x24, 0xb1, 0x51, 0xbc, 0xbc, 0x92, 0xba,
+    0x73, 0x1f, 0x9c, 0x75, 0xc2, 0x14, 0x6d, 0x4f, 0xc4, 0x5a, 0xcf, 0xda,
+    0x44, 0x35, 0x00, 0x6b, 0x42, 0x3b, 0x9f, 0x14, 0xf1, 0x05, 0xb3, 0x51,
+    0x22, 0xb6, 0xbe, 0x9c, 0xe0, 0xc1, 0x5c, 0x48, 0x61, 0xdf, 0x4e, 0x4c,
+    0x72, 0xb8, 0x05, 0x35, 0x7c, 0xac, 0xf1, 0xbb, 0xa0, 0x3b, 0x2a, 0xea,
+    0xf7, 0x86, 0xe9, 0xd2, 0xff, 0x1e, 0x1d, 0x02, 0x56, 0x00, 0xca, 0xb1,
+    0x39, 0xf6, 0xa2, 0xc6, 0x3b, 0x65, 0x45, 0x2f, 0x39, 0x00, 0xcd, 0x6e,
+    0xd6, 0x55, 0xf7, 0x71, 0x37, 0x89, 0xc2, 0xe7, 0x7a, 0xc0, 0x1a, 0xa6,
+    0x2f, 0xea, 0x17, 0x7c, 0xaa, 0x2a, 0x91, 0x8f, 0xd4, 0xc7, 0x50, 0x8b,
+    0xab, 0x8e, 0x99, 0x3b, 0x33, 0x91, 0xbc, 0x02, 0x10, 0x58, 0x4b, 0x58,
+    0x40, 0x9b, 0xc4, 0x8f, 0x48, 0x2b, 0xa7, 0x44, 0xfd, 0x07, 0x04, 0xf0,
+    0x98, 0x67, 0x56, 0xea, 0x25, 0x92, 0x8b, 0x2e, 0x4b, 0x4a, 0xa1, 0xd3,
+    0xc2, 0xa4, 0xb4, 0x9b, 0x59, 0x70, 0x32, 0xa6, 0xd8, 0x8b, 0xd9, 0x02,
+    0x57, 0x00, 0xa0, 0xdf, 0xd7, 0x04, 0x0c, 0xae, 0xba, 0xa4, 0xf0, 0xfe,
+    0xcf, 0xea, 0x45, 0x2e, 0x21, 0xc0, 0x4d, 0x68, 0x21, 0x9b, 0x5f, 0xbf,
+    0x5b, 0x05, 0x6d, 0xcb, 0x8b, 0xd3, 0x28, 0x61, 0xd1, 0xa2, 0x15, 0x12,
+    0xf9, 0x2c, 0x0d, 0x9e, 0x35, 0x2d, 0x91, 0xdf, 0xe6, 0xd8, 0x23, 0x55,
+    0x9c, 0xd6, 0xd2, 0x6a, 0x0d, 0xf6, 0x03, 0xcc, 0xe0, 0xc1, 0xcf, 0x29,
+    0xbd, 0xeb, 0x2b, 0x92, 0xda, 0xeb, 0xea, 0x34, 0x32, 0xf7, 0x25, 0x58,
+    0xce, 0x53, 0x1d, 0xf6, 0x7d, 0x15, 0x7c, 0xc7, 0x47, 0x4f, 0xaf, 0x46,
+    0x8c, 0xaa, 0x14, 0x13, 0x02, 0x56, 0x00, 0x87, 0x20, 0xd1, 0x4f, 0x17,
+    0x2e, 0xd2, 0x43, 0x83, 0x74, 0xd0, 0xab, 0x33, 0x9f, 0x39, 0x8e, 0xa4,
+    0xf6, 0x25, 0x06, 0x81, 0xef, 0xa7, 0x2a, 0xbc, 0x6e, 0xca, 0x9c, 0x0f,
+    0xa8, 0x71, 0x71, 0xb6, 0x5f, 0xe3, 0x2f, 0x8b, 0x07, 0xc7, 0xb4, 0x66,
+    0x27, 0x77, 0xb6, 0x7d, 0x56, 0xb5, 0x90, 0x32, 0x3a, 0xd5, 0xbd, 0x2d,
+    0xb4, 0xda, 0xc7, 0xc4, 0xd8, 0xa8, 0xaf, 0x58, 0xa0, 0x65, 0x9a, 0x39,
+    0xf1, 0x6e, 0x61, 0xb2, 0x1e, 0xdc, 0xdc, 0x6b, 0xe2, 0x81, 0xc3, 0x23,
+    0x12, 0x3b, 0xa0, 0x21, 0xc4, 0x90, 0x5d, 0x3b, 0x02, 0x57, 0x00, 0xe6,
+    0x8a, 0xaa, 0xb8, 0x6d, 0x2c, 0x81, 0x43, 0xb5, 0xd6, 0xa0, 0x2b, 0x42,
+    0x49, 0xa9, 0x0a, 0x51, 0xfa, 0x18, 0xc8, 0x32, 0xea, 0x54, 0x18, 0xf3,
+    0x60, 0xc2, 0xb5, 0x4a, 0x43, 0x05, 0x93, 0x9c, 0x01, 0xd9, 0x28, 0xed,
+    0x73, 0xfa, 0x82, 0xbc, 0x12, 0x64, 0xcb, 0xc4, 0x24, 0xa9, 0x3e, 0xae,
+    0x7c, 0x4b, 0x8f, 0x94, 0x57, 0x7b, 0x14, 0x10, 0x41, 0xdc, 0x62, 0x12,
+    0x8c, 0xb2, 0x4a, 0x7c, 0xf6, 0x53, 0xd4, 0xc6, 0xe4, 0xda, 0xd1, 0xa2,
+    0x00, 0x0e, 0x3d, 0x30, 0xf7, 0x05, 0x4f, 0x1d, 0x82, 0xbc, 0x52, 0xd9,
+    0xb1, 0x30, 0x82, 0x01, 0x0a, 0x30, 0x82, 0x01, 0x06, 0x02, 0x56, 0x00,
+    0x84, 0x12, 0x4f, 0xf7, 0x3b, 0x65, 0x53, 0x34, 0x6c, 0x6c, 0x4d, 0x77,
+    0xdf, 0xfd, 0x1f, 0xb6, 0x16, 0xe2, 0x25, 0x15, 0xca, 0xc9, 0xc1, 0x41,
+    0x9a, 0x50, 0xda, 0xeb, 0x88, 0x4f, 0x3d, 0xb3, 0x01, 0x00, 0x44, 0xc4,
+    0xac, 0xe7, 0x14, 0x62, 0xa6, 0x56, 0xde, 0xc5, 0xb7, 0xc3, 0x1d, 0x07,
+    0xbd, 0x7d, 0x64, 0xc5, 0x7e, 0x45, 0x25, 0x56, 0xed, 0x7a, 0xd2, 0x14,
+    0xdb, 0x4e, 0x27, 0xd4, 0x1f, 0xf8, 0x94, 0xa7, 0xef, 0x07, 0xce, 0xdb,
+    0x24, 0xb7, 0xdd, 0x71, 0x5c, 0x63, 0xc9, 0x33, 0xfe, 0xde, 0x40, 0x52,
+    0xeb, 0x02, 0x55, 0x58, 0x0c, 0x35, 0x4f, 0x7c, 0xee, 0x37, 0x78, 0x48,
+    0x48, 0x33, 0xa5, 0x3f, 0xfe, 0x15, 0x24, 0x0f, 0x41, 0x6e, 0x0e, 0x87,
+    0x31, 0x2b, 0x81, 0x11, 0x8b, 0x3c, 0x9d, 0x05, 0x8a, 0x29, 0x22, 0x00,
+    0xaa, 0xd8, 0x83, 0x1d, 0xef, 0x62, 0xec, 0x6e, 0xe4, 0x94, 0x83, 0xcf,
+    0xd7, 0x68, 0xaf, 0xd3, 0xa8, 0xed, 0xd8, 0xfe, 0xd8, 0xc3, 0x8f, 0x48,
+    0xfc, 0x8c, 0x0d, 0xe7, 0x89, 0x6f, 0xe2, 0xbf, 0xfb, 0x0d, 0xc5, 0x4a,
+    0x05, 0x34, 0x92, 0x18, 0x7a, 0x93, 0xa0, 0xe8, 0x42, 0x86, 0x22, 0xa9,
+    0xe9, 0x80, 0x37, 0x47, 0x02, 0x55, 0x60, 0x76, 0xab, 0xde, 0x2b, 0xf5,
+    0xa2, 0x2c, 0xaa, 0x0c, 0x99, 0x81, 0xee, 0x72, 0x2c, 0x7d, 0x22, 0x59,
+    0x2a, 0x35, 0xea, 0x50, 0x4e, 0x47, 0x6b, 0x92, 0x2d, 0x30, 0xa1, 0x01,
+    0xa5, 0x9e, 0x26, 0x6e, 0x27, 0xca, 0xf5, 0xf2, 0x87, 0x5d, 0x31, 0xaf,
+    0xe9, 0x32, 0xcd, 0x10, 0xfd, 0x4d, 0xdb, 0xf9, 0x86, 0x05, 0x12, 0x1b,
+    0x01, 0x84, 0x55, 0x97, 0x5f, 0xe2, 0x78, 0x27, 0xd9, 0xe4, 0x26, 0x7d,
+    0xab, 0x0e, 0xe0, 0x1b, 0x6f, 0xcb, 0x4b, 0x14, 0xdd, 0xdc, 0xdc, 0x8b,
+    0xe8, 0x9f, 0xd0, 0x62, 0x96, 0xca, 0xcf,
+};
+
+size_t kDERRSAPrivate3Prime2048Len = sizeof(kDERRSAPrivate3Prime2048);
+
+}  /* extern "C" */
diff --git a/tool/genrsa.cc b/tool/genrsa.cc
new file mode 100644
index 0000000..f5296ce
--- /dev/null
+++ b/tool/genrsa.cc
@@ -0,0 +1,69 @@
+/* Copyright (c) 2015, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+
+#include "../crypto/test/scoped_types.h"
+#include "internal.h"
+
+
+static const struct argument kArguments[] = {
+    {
+     "-nprimes", kOptionalArgument,
+     "The number of primes to generate (default: 2)",
+    },
+    {
+     "-bits", kOptionalArgument,
+     "The number of bits in the modulus (default: 2048)",
+    },
+    {
+     "", kOptionalArgument, "",
+    },
+};
+
+bool GenerateRSAKey(const std::vector<std::string> &args) {
+  std::map<std::string, std::string> args_map;
+
+  if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
+    PrintUsage(kArguments);
+    return false;
+  }
+
+  unsigned bits, nprimes;
+  if (!GetUnsigned(&bits, "-bits", 2048, args_map) ||
+      !GetUnsigned(&nprimes, "-nprimes", 2, args_map)) {
+    PrintUsage(kArguments);
+    return false;
+  }
+
+  ScopedRSA rsa(RSA_new());
+  ScopedBIGNUM e(BN_new());
+  ScopedBIO bio(BIO_new_fp(stdout, BIO_NOCLOSE));
+
+  if (!BN_set_word(e.get(), RSA_F4) ||
+      !RSA_generate_multi_prime_key(rsa.get(), bits, nprimes, e.get(), NULL) ||
+      !PEM_write_bio_RSAPrivateKey(bio.get(), rsa.get(), NULL /* cipher */,
+                                   NULL /* key */, 0 /* key len */,
+                                   NULL /* password callback */,
+                                   NULL /* callback arg */)) {
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  return true;
+}
diff --git a/tool/internal.h b/tool/internal.h
index 277d099..95030ca 100644
--- a/tool/internal.h
+++ b/tool/internal.h
@@ -49,5 +49,9 @@
 
 void PrintUsage(const struct argument *templates);
 
+bool GetUnsigned(unsigned *out, const std::string &arg_name,
+                 unsigned default_value,
+                 const std::map<std::string, std::string> &args);
+
 
 #endif /* !OPENSSL_HEADER_TOOL_INTERNAL_H */
diff --git a/tool/speed.cc b/tool/speed.cc
index ab17c2f..151dc2b 100644
--- a/tool/speed.cc
+++ b/tool/speed.cc
@@ -44,6 +44,8 @@
 extern size_t kDERRSAPrivate2048Len;
 extern const uint8_t kDERRSAPrivate4096[];
 extern size_t kDERRSAPrivate4096Len;
+extern const uint8_t kDERRSAPrivate3Prime2048[];
+extern size_t kDERRSAPrivate3Prime2048Len;
 }
 
 // TimeResults represents the results of benchmarking a function.
@@ -429,6 +431,20 @@
   RSA_free(key);
   key = NULL;
 
+  inp = kDERRSAPrivate3Prime2048;
+  if (NULL == d2i_RSAPrivateKey(&key, &inp, kDERRSAPrivate3Prime2048Len)) {
+    fprintf(stderr, "Failed to parse RSA key.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  if (!SpeedRSA("RSA 2048 (3 prime, e=3)", key, selected)) {
+    return false;
+  }
+
+  RSA_free(key);
+  key = NULL;
+
   inp = kDERRSAPrivate4096;
   if (NULL == d2i_RSAPrivateKey(&key, &inp, kDERRSAPrivate4096Len)) {
     fprintf(stderr, "Failed to parse 4096-bit RSA key.\n");
diff --git a/tool/tool.cc b/tool/tool.cc
index 4bd7d1a..e4d5201 100644
--- a/tool/tool.cc
+++ b/tool/tool.cc
@@ -27,16 +27,17 @@
 
 
 bool Client(const std::vector<std::string> &args);
-bool Server(const std::vector<std::string> &args);
+bool DoPKCS12(const std::vector<std::string> &args);
+bool GenerateRSAKey(const std::vector<std::string> &args);
 bool MD5Sum(const std::vector<std::string> &args);
+bool Rand(const std::vector<std::string> &args);
 bool SHA1Sum(const std::vector<std::string> &args);
 bool SHA224Sum(const std::vector<std::string> &args);
 bool SHA256Sum(const std::vector<std::string> &args);
 bool SHA384Sum(const std::vector<std::string> &args);
 bool SHA512Sum(const std::vector<std::string> &args);
-bool DoPKCS12(const std::vector<std::string> &args);
+bool Server(const std::vector<std::string> &args);
 bool Speed(const std::vector<std::string> &args);
-bool Rand(const std::vector<std::string> &args);
 
 typedef bool (*tool_func_t)(const std::vector<std::string> &args);
 
@@ -46,19 +47,20 @@
 };
 
 static const Tool kTools[] = {
-  { "speed", Speed },
-  { "pkcs12", DoPKCS12 },
   { "client", Client },
-  { "s_client", Client },
-  { "server", Server },
-  { "s_server", Server },
+  { "genrsa", GenerateRSAKey },
   { "md5sum", MD5Sum },
+  { "pkcs12", DoPKCS12 },
+  { "rand", Rand },
+  { "s_client", Client },
+  { "s_server", Server },
+  { "server", Server },
   { "sha1sum", SHA1Sum },
   { "sha224sum", SHA224Sum },
   { "sha256sum", SHA256Sum },
   { "sha384sum", SHA384Sum },
   { "sha512sum", SHA512Sum },
-  { "rand", Rand },
+  { "speed", Speed },
   { "", nullptr },
 };