Replace the union inside EVP_PKEY with void*.

The union isn't actually providing type-safety: nothing checks that we
access the correct arm of the union, and it has a void* arm anyway.
Instead, it's just adding some strict aliasing risk by relying on
type-punning: we usually write to the pointer as void*, via
EVP_PKEY_assign, but then we read from it as the underlying type.

This is allowed in C, but not in C++. And even in C, while that is
allowed, if we ever wrote &pkey->pkey.rsa, it would suddenly be a strict
aliasing violation. Just use a void*, which means we don't type-pun
pointer types against each other.

While I'm here, I made the free callbacks for EVP_PKEYs also NULL the
pointer. The one caller also NULLs it, so its fine, but some did and
some didn't do it, and this seems prudent.

Bug: 301
Change-Id: I74c76ed3984527df66f64bb2d397af44f63920bd
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/57106
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c
index 39e40fd..8383d2e 100644
--- a/crypto/evp/evp.c
+++ b/crypto/evp/evp.c
@@ -98,7 +98,7 @@
 static void free_it(EVP_PKEY *pkey) {
   if (pkey->ameth && pkey->ameth->pkey_free) {
     pkey->ameth->pkey_free(pkey);
-    pkey->pkey.ptr = NULL;
+    pkey->pkey = NULL;
     pkey->type = EVP_PKEY_NONE;
   }
 }
@@ -254,7 +254,7 @@
     OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_RSA_KEY);
     return NULL;
   }
-  return pkey->pkey.rsa;
+  return pkey->pkey;
 }
 
 RSA *EVP_PKEY_get1_RSA(const EVP_PKEY *pkey) {
@@ -282,7 +282,7 @@
     OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DSA_KEY);
     return NULL;
   }
-  return pkey->pkey.dsa;
+  return pkey->pkey;
 }
 
 DSA *EVP_PKEY_get1_DSA(const EVP_PKEY *pkey) {
@@ -310,7 +310,7 @@
     OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_EC_KEY_KEY);
     return NULL;
   }
-  return pkey->pkey.ec;
+  return pkey->pkey;
 }
 
 EC_KEY *EVP_PKEY_get1_EC_KEY(const EVP_PKEY *pkey) {
@@ -328,14 +328,14 @@
   if (!EVP_PKEY_set_type(pkey, type)) {
     return 0;
   }
-  pkey->pkey.ptr = key;
+  pkey->pkey = key;
   return key != NULL;
 }
 
 int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) {
   const EVP_PKEY_ASN1_METHOD *ameth;
 
-  if (pkey && pkey->pkey.ptr) {
+  if (pkey && pkey->pkey) {
     free_it(pkey);
   }
 
@@ -447,7 +447,7 @@
 void *EVP_PKEY_get0(const EVP_PKEY *pkey) {
   // Node references, but never calls this function, so for now we return NULL.
   // If other projects require complete support, call |EVP_PKEY_get0_RSA|, etc.,
-  // rather than reading |pkey->pkey.ptr| directly. This avoids problems if our
+  // rather than reading |pkey->pkey| directly. This avoids problems if our
   // internal representation does not match the type the caller expects from
   // OpenSSL.
   return NULL;
diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c
index da09981..f270c3e 100644
--- a/crypto/evp/evp_asn1.c
+++ b/crypto/evp/evp_asn1.c
@@ -336,11 +336,11 @@
 int i2d_PublicKey(const EVP_PKEY *key, uint8_t **outp) {
   switch (key->type) {
     case EVP_PKEY_RSA:
-      return i2d_RSAPublicKey(key->pkey.rsa, outp);
+      return i2d_RSAPublicKey(EVP_PKEY_get0_RSA(key), outp);
     case EVP_PKEY_DSA:
-      return i2d_DSAPublicKey(key->pkey.dsa, outp);
+      return i2d_DSAPublicKey(EVP_PKEY_get0_DSA(key), outp);
     case EVP_PKEY_EC:
-      return i2o_ECPublicKey(key->pkey.ec, outp);
+      return i2o_ECPublicKey(EVP_PKEY_get0_EC_KEY(key), outp);
     default:
       OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
       return -1;
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index 09f15ae..71f0f95 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -132,16 +132,11 @@
   CRYPTO_refcount_t references;
 
   // type contains one of the EVP_PKEY_* values or NID_undef and determines
-  // which element (if any) of the |pkey| union is valid.
+  // the type of |pkey|.
   int type;
 
-  union {
-    void *ptr;
-    RSA *rsa;
-    DSA *dsa;
-    DH *dh;
-    EC_KEY *ec;
-  } pkey;
+  // pkey contains a pointer to a structure dependent on |type|.
+  void *pkey;
 
   // ameth contains a pointer to a method table that contains many ASN.1
   // methods for the key type.
diff --git a/crypto/evp/p_dsa_asn1.c b/crypto/evp/p_dsa_asn1.c
index cd787dd..8486e28 100644
--- a/crypto/evp/p_dsa_asn1.c
+++ b/crypto/evp/p_dsa_asn1.c
@@ -102,7 +102,7 @@
 }
 
 static int dsa_pub_encode(CBB *out, const EVP_PKEY *key) {
-  const DSA *dsa = key->pkey.dsa;
+  const DSA *dsa = key->pkey;
   const int has_params = dsa->p != NULL && dsa->q != NULL && dsa->g != NULL;
 
   // See RFC 5480, section 2.
@@ -171,7 +171,7 @@
 }
 
 static int dsa_priv_encode(CBB *out, const EVP_PKEY *key) {
-  const DSA *dsa = key->pkey.dsa;
+  const DSA *dsa = key->pkey;
   if (dsa == NULL || dsa->priv_key == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
     return 0;
@@ -196,17 +196,19 @@
 }
 
 static int int_dsa_size(const EVP_PKEY *pkey) {
-  return DSA_size(pkey->pkey.dsa);
+  const DSA *dsa = pkey->pkey;
+  return DSA_size(dsa);
 }
 
 static int dsa_bits(const EVP_PKEY *pkey) {
-  return BN_num_bits(pkey->pkey.dsa->p);
+  const DSA *dsa = pkey->pkey;
+  return BN_num_bits(DSA_get0_p(dsa));
 }
 
 static int dsa_missing_parameters(const EVP_PKEY *pkey) {
-  DSA *dsa;
-  dsa = pkey->pkey.dsa;
-  if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) {
+  const DSA *dsa = pkey->pkey;
+  if (DSA_get0_p(dsa) == NULL || DSA_get0_q(dsa) == NULL ||
+      DSA_get0_g(dsa) == NULL) {
     return 1;
   }
   return 0;
@@ -226,9 +228,11 @@
 }
 
 static int dsa_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
-  if (!dup_bn_into(&to->pkey.dsa->p, from->pkey.dsa->p) ||
-      !dup_bn_into(&to->pkey.dsa->q, from->pkey.dsa->q) ||
-      !dup_bn_into(&to->pkey.dsa->g, from->pkey.dsa->g)) {
+  DSA *to_dsa = to->pkey;
+  const DSA *from_dsa = from->pkey;
+  if (!dup_bn_into(&to_dsa->p, from_dsa->p) ||
+      !dup_bn_into(&to_dsa->q, from_dsa->q) ||
+      !dup_bn_into(&to_dsa->g, from_dsa->g)) {
     return 0;
   }
 
@@ -236,16 +240,23 @@
 }
 
 static int dsa_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
-  return BN_cmp(a->pkey.dsa->p, b->pkey.dsa->p) == 0 &&
-         BN_cmp(a->pkey.dsa->q, b->pkey.dsa->q) == 0 &&
-         BN_cmp(a->pkey.dsa->g, b->pkey.dsa->g) == 0;
+  const DSA *a_dsa = a->pkey;
+  const DSA *b_dsa = b->pkey;
+  return BN_cmp(DSA_get0_p(a_dsa), DSA_get0_p(b_dsa)) == 0 &&
+         BN_cmp(DSA_get0_q(a_dsa), DSA_get0_q(b_dsa)) == 0 &&
+         BN_cmp(DSA_get0_g(a_dsa), DSA_get0_g(b_dsa)) == 0;
 }
 
 static int dsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
-  return BN_cmp(b->pkey.dsa->pub_key, a->pkey.dsa->pub_key) == 0;
+  const DSA *a_dsa = a->pkey;
+  const DSA *b_dsa = b->pkey;
+  return BN_cmp(DSA_get0_pub_key(b_dsa), DSA_get0_pub_key(a_dsa)) == 0;
 }
 
-static void int_dsa_free(EVP_PKEY *pkey) { DSA_free(pkey->pkey.dsa); }
+static void int_dsa_free(EVP_PKEY *pkey) {
+  DSA_free(pkey->pkey);
+  pkey->pkey = NULL;
+}
 
 const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = {
     EVP_PKEY_DSA,
diff --git a/crypto/evp/p_ec.c b/crypto/evp/p_ec.c
index ddb64a4..c9f26cb 100644
--- a/crypto/evp/p_ec.c
+++ b/crypto/evp/p_ec.c
@@ -117,9 +117,7 @@
 
 static int pkey_ec_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
                         const uint8_t *tbs, size_t tbslen) {
-  unsigned int sltmp;
-  EC_KEY *ec = ctx->pkey->pkey.ec;
-
+  const EC_KEY *ec = ctx->pkey->pkey;
   if (!sig) {
     *siglen = ECDSA_size(ec);
     return 1;
@@ -128,6 +126,7 @@
     return 0;
   }
 
+  unsigned int sltmp;
   if (!ECDSA_sign(0, tbs, tbslen, sig, &sltmp, ec)) {
     return 0;
   }
@@ -137,37 +136,32 @@
 
 static int pkey_ec_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen,
                           const uint8_t *tbs, size_t tbslen) {
-  return ECDSA_verify(0, tbs, tbslen, sig, siglen, ctx->pkey->pkey.ec);
+  const EC_KEY *ec_key = ctx->pkey->pkey;
+  return ECDSA_verify(0, tbs, tbslen, sig, siglen, ec_key);
 }
 
 static int pkey_ec_derive(EVP_PKEY_CTX *ctx, uint8_t *key,
                           size_t *keylen) {
-  int ret;
-  size_t outlen;
-  const EC_POINT *pubkey = NULL;
-  EC_KEY *eckey;
-
   if (!ctx->pkey || !ctx->peerkey) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
     return 0;
   }
 
-  eckey = ctx->pkey->pkey.ec;
-
+  const EC_KEY *eckey = ctx->pkey->pkey;
   if (!key) {
     const EC_GROUP *group;
     group = EC_KEY_get0_group(eckey);
     *keylen = (EC_GROUP_get_degree(group) + 7) / 8;
     return 1;
   }
-  pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec);
+
+  const EC_KEY *eckey_peer = ctx->peerkey->pkey;
+  const EC_POINT *pubkey = EC_KEY_get0_public_key(eckey_peer);
 
   // NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is
   // not an error, the result is truncated.
-
-  outlen = *keylen;
-
-  ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0);
+  size_t outlen = *keylen;
+  int ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0);
   if (ret < 0) {
     return 0;
   }
@@ -224,7 +218,7 @@
       OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
       return 0;
     }
-    group = EC_KEY_get0_group(ctx->pkey->pkey.ec);
+    group = EC_KEY_get0_group(ctx->pkey->pkey);
   }
   EC_KEY *ec = EC_KEY_new();
   if (ec == NULL ||
diff --git a/crypto/evp/p_ec_asn1.c b/crypto/evp/p_ec_asn1.c
index be51277..2659100 100644
--- a/crypto/evp/p_ec_asn1.c
+++ b/crypto/evp/p_ec_asn1.c
@@ -66,7 +66,7 @@
 
 
 static int eckey_pub_encode(CBB *out, const EVP_PKEY *key) {
-  const EC_KEY *ec_key = key->pkey.ec;
+  const EC_KEY *ec_key = key->pkey;
   const EC_GROUP *group = EC_KEY_get0_group(ec_key);
   const EC_POINT *public_key = EC_KEY_get0_public_key(ec_key);
 
@@ -118,11 +118,12 @@
 }
 
 static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
-  int r;
-  const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec);
-  const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec),
-                 *pb = EC_KEY_get0_public_key(b->pkey.ec);
-  r = EC_POINT_cmp(group, pa, pb, NULL);
+  const EC_KEY *a_ec = a->pkey;
+  const EC_KEY *b_ec = b->pkey;
+  const EC_GROUP *group = EC_KEY_get0_group(b_ec);
+  const EC_POINT *pa = EC_KEY_get0_public_key(a_ec),
+                 *pb = EC_KEY_get0_public_key(b_ec);
+  int r = EC_POINT_cmp(group, pa, pb, NULL);
   if (r == 0) {
     return 1;
   } else if (r == 1) {
@@ -154,7 +155,7 @@
 }
 
 static int eckey_priv_encode(CBB *out, const EVP_PKEY *key) {
-  const EC_KEY *ec_key = key->pkey.ec;
+  const EC_KEY *ec_key = key->pkey;
 
   // Omit the redundant copy of the curve name. This contradicts RFC 5915 but
   // aligns with PKCS #11. SEC 1 only says they may be omitted if known by other
@@ -182,7 +183,7 @@
 
 static int eckey_set1_tls_encodedpoint(EVP_PKEY *pkey, const uint8_t *in,
                                        size_t len) {
-  EC_KEY *ec_key = pkey->pkey.ec;
+  EC_KEY *ec_key = pkey->pkey;
   if (ec_key == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
     return 0;
@@ -193,7 +194,7 @@
 
 static size_t eckey_get1_tls_encodedpoint(const EVP_PKEY *pkey,
                                           uint8_t **out_ptr) {
-  const EC_KEY *ec_key = pkey->pkey.ec;
+  const EC_KEY *ec_key = pkey->pkey;
   if (ec_key == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
     return 0;
@@ -203,11 +204,13 @@
 }
 
 static int int_ec_size(const EVP_PKEY *pkey) {
-  return ECDSA_size(pkey->pkey.ec);
+  const EC_KEY *ec_key = pkey->pkey;
+  return ECDSA_size(ec_key);
 }
 
 static int ec_bits(const EVP_PKEY *pkey) {
-  const EC_GROUP *group = EC_KEY_get0_group(pkey->pkey.ec);
+  const EC_KEY *ec_key = pkey->pkey;
+  const EC_GROUP *group = EC_KEY_get0_group(ec_key);
   if (group == NULL) {
     ERR_clear_error();
     return 0;
@@ -216,34 +219,38 @@
 }
 
 static int ec_missing_parameters(const EVP_PKEY *pkey) {
-  return pkey->pkey.ec == NULL || EC_KEY_get0_group(pkey->pkey.ec) == NULL;
+  const EC_KEY *ec_key = pkey->pkey;
+  return ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL;
 }
 
 static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
-  if (from->pkey.ec == NULL) {
+  const EC_KEY *from_key = from->pkey;
+  if (from_key == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
     return 0;
   }
-  const EC_GROUP *group = EC_KEY_get0_group(from->pkey.ec);
+  const EC_GROUP *group = EC_KEY_get0_group(from_key);
   if (group == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
     return 0;
   }
-  if (to->pkey.ec == NULL) {
-    to->pkey.ec = EC_KEY_new();
-    if (to->pkey.ec == NULL) {
+  if (to->pkey == NULL) {
+    to->pkey = EC_KEY_new();
+    if (to->pkey == NULL) {
       return 0;
     }
   }
-  return EC_KEY_set_group(to->pkey.ec, group);
+  return EC_KEY_set_group(to->pkey, group);
 }
 
 static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
-  if (a->pkey.ec == NULL || b->pkey.ec == NULL) {
+  const EC_KEY *a_ec = a->pkey;
+  const EC_KEY *b_ec = b->pkey;
+  if (a_ec == NULL || b_ec == NULL) {
     return -2;
   }
-  const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec),
-                 *group_b = EC_KEY_get0_group(b->pkey.ec);
+  const EC_GROUP *group_a = EC_KEY_get0_group(a_ec),
+                 *group_b = EC_KEY_get0_group(b_ec);
   if (group_a == NULL || group_b == NULL) {
     return -2;
   }
@@ -254,10 +261,14 @@
   return 1;
 }
 
-static void int_ec_free(EVP_PKEY *pkey) { EC_KEY_free(pkey->pkey.ec); }
+static void int_ec_free(EVP_PKEY *pkey) {
+  EC_KEY_free(pkey->pkey);
+  pkey->pkey = NULL;
+}
 
 static int eckey_opaque(const EVP_PKEY *pkey) {
-  return EC_KEY_is_opaque(pkey->pkey.ec);
+  const EC_KEY *ec_key = pkey->pkey;
+  return EC_KEY_is_opaque(ec_key);
 }
 
 const EVP_PKEY_ASN1_METHOD ec_asn1_meth = {
diff --git a/crypto/evp/p_ed25519.c b/crypto/evp/p_ed25519.c
index cd787a1..647ea05 100644
--- a/crypto/evp/p_ed25519.c
+++ b/crypto/evp/p_ed25519.c
@@ -39,15 +39,15 @@
   ED25519_keypair(pubkey_unused, key->key);
   key->has_private = 1;
 
-  OPENSSL_free(pkey->pkey.ptr);
-  pkey->pkey.ptr = key;
+  OPENSSL_free(pkey->pkey);
+  pkey->pkey = key;
   return 1;
 }
 
 static int pkey_ed25519_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig,
                                      size_t *siglen, const uint8_t *tbs,
                                      size_t tbslen) {
-  ED25519_KEY *key = ctx->pkey->pkey.ptr;
+  const ED25519_KEY *key = ctx->pkey->pkey;
   if (!key->has_private) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
     return 0;
@@ -74,7 +74,7 @@
 static int pkey_ed25519_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig,
                                        size_t siglen, const uint8_t *tbs,
                                        size_t tbslen) {
-  ED25519_KEY *key = ctx->pkey->pkey.ptr;
+  const ED25519_KEY *key = ctx->pkey->pkey;
   if (siglen != 64 ||
       !ED25519_verify(tbs, tbslen, sig, key->key + ED25519_PUBLIC_KEY_OFFSET)) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE);
diff --git a/crypto/evp/p_ed25519_asn1.c b/crypto/evp/p_ed25519_asn1.c
index c3f8885..3b8f27f 100644
--- a/crypto/evp/p_ed25519_asn1.c
+++ b/crypto/evp/p_ed25519_asn1.c
@@ -24,8 +24,8 @@
 
 
 static void ed25519_free(EVP_PKEY *pkey) {
-  OPENSSL_free(pkey->pkey.ptr);
-  pkey->pkey.ptr = NULL;
+  OPENSSL_free(pkey->pkey);
+  pkey->pkey = NULL;
 }
 
 static int ed25519_set_priv_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) {
@@ -46,7 +46,7 @@
   key->has_private = 1;
 
   ed25519_free(pkey);
-  pkey->pkey.ptr = key;
+  pkey->pkey = key;
   return 1;
 }
 
@@ -65,13 +65,13 @@
   key->has_private = 0;
 
   ed25519_free(pkey);
-  pkey->pkey.ptr = key;
+  pkey->pkey = key;
   return 1;
 }
 
 static int ed25519_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out,
                                 size_t *out_len) {
-  const ED25519_KEY *key = pkey->pkey.ptr;
+  const ED25519_KEY *key = pkey->pkey;
   if (!key->has_private) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
     return 0;
@@ -95,7 +95,7 @@
 
 static int ed25519_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out,
                                size_t *out_len) {
-  const ED25519_KEY *key = pkey->pkey.ptr;
+  const ED25519_KEY *key = pkey->pkey;
   if (out == NULL) {
     *out_len = 32;
     return 1;
@@ -124,7 +124,7 @@
 }
 
 static int ed25519_pub_encode(CBB *out, const EVP_PKEY *pkey) {
-  const ED25519_KEY *key = pkey->pkey.ptr;
+  const ED25519_KEY *key = pkey->pkey;
 
   // See RFC 8410, section 4.
   CBB spki, algorithm, oid, key_bitstring;
@@ -145,8 +145,8 @@
 }
 
 static int ed25519_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
-  const ED25519_KEY *a_key = a->pkey.ptr;
-  const ED25519_KEY *b_key = b->pkey.ptr;
+  const ED25519_KEY *a_key = a->pkey;
+  const ED25519_KEY *b_key = b->pkey;
   return OPENSSL_memcmp(a_key->key + ED25519_PUBLIC_KEY_OFFSET,
                         b_key->key + ED25519_PUBLIC_KEY_OFFSET, 32) == 0;
 }
@@ -168,7 +168,7 @@
 }
 
 static int ed25519_priv_encode(CBB *out, const EVP_PKEY *pkey) {
-  ED25519_KEY *key = pkey->pkey.ptr;
+  const ED25519_KEY *key = pkey->pkey;
   if (!key->has_private) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
     return 0;
diff --git a/crypto/evp/p_rsa.c b/crypto/evp/p_rsa.c
index 7872a92..dc22450 100644
--- a/crypto/evp/p_rsa.c
+++ b/crypto/evp/p_rsa.c
@@ -171,7 +171,7 @@
 static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
                          const uint8_t *tbs, size_t tbslen) {
   RSA_PKEY_CTX *rctx = ctx->data;
-  RSA *rsa = ctx->pkey->pkey.rsa;
+  RSA *rsa = ctx->pkey->pkey;
   const size_t key_len = EVP_PKEY_size(ctx->pkey);
 
   if (!sig) {
@@ -210,7 +210,7 @@
                            size_t siglen, const uint8_t *tbs,
                            size_t tbslen) {
   RSA_PKEY_CTX *rctx = ctx->data;
-  RSA *rsa = ctx->pkey->pkey.rsa;
+  RSA *rsa = ctx->pkey->pkey;
 
   if (rctx->md) {
     switch (rctx->pad_mode) {
@@ -243,7 +243,7 @@
                                    size_t *out_len, const uint8_t *sig,
                                    size_t sig_len) {
   RSA_PKEY_CTX *rctx = ctx->data;
-  RSA *rsa = ctx->pkey->pkey.rsa;
+  RSA *rsa = ctx->pkey->pkey;
   const size_t key_len = EVP_PKEY_size(ctx->pkey);
 
   if (out == NULL) {
@@ -307,7 +307,7 @@
 static int pkey_rsa_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
                             const uint8_t *in, size_t inlen) {
   RSA_PKEY_CTX *rctx = ctx->data;
-  RSA *rsa = ctx->pkey->pkey.rsa;
+  RSA *rsa = ctx->pkey->pkey;
   const size_t key_len = EVP_PKEY_size(ctx->pkey);
 
   if (!out) {
@@ -339,7 +339,7 @@
                             size_t *outlen, const uint8_t *in,
                             size_t inlen) {
   RSA_PKEY_CTX *rctx = ctx->data;
-  RSA *rsa = ctx->pkey->pkey.rsa;
+  RSA *rsa = ctx->pkey->pkey;
   const size_t key_len = EVP_PKEY_size(ctx->pkey);
 
   if (!out) {
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
index cfaf694..dd64731 100644
--- a/crypto/evp/p_rsa_asn1.c
+++ b/crypto/evp/p_rsa_asn1.c
@@ -68,6 +68,7 @@
 
 static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) {
   // See RFC 3279, section 2.3.1.
+  const RSA *rsa = key->pkey;
   CBB spki, algorithm, oid, null, key_bitstring;
   if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
       !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
@@ -76,7 +77,7 @@
       !CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
       !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
       !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
-      !RSA_marshal_public_key(&key_bitstring, key->pkey.rsa) ||
+      !RSA_marshal_public_key(&key_bitstring, rsa) ||
       !CBB_flush(out)) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
     return 0;
@@ -109,11 +110,14 @@
 }
 
 static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
-  return BN_cmp(b->pkey.rsa->n, a->pkey.rsa->n) == 0 &&
-         BN_cmp(b->pkey.rsa->e, a->pkey.rsa->e) == 0;
+  const RSA *a_rsa = a->pkey;
+  const RSA *b_rsa = b->pkey;
+  return BN_cmp(RSA_get0_n(b_rsa), RSA_get0_n(a_rsa)) == 0 &&
+         BN_cmp(RSA_get0_e(b_rsa), RSA_get0_e(a_rsa)) == 0;
 }
 
 static int rsa_priv_encode(CBB *out, const EVP_PKEY *key) {
+  const RSA *rsa = key->pkey;
   CBB pkcs8, algorithm, oid, null, private_key;
   if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
       !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
@@ -122,7 +126,7 @@
       !CBB_add_bytes(&oid, rsa_asn1_meth.oid, rsa_asn1_meth.oid_len) ||
       !CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
       !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
-      !RSA_marshal_private_key(&private_key, key->pkey.rsa) ||
+      !RSA_marshal_private_key(&private_key, rsa) ||
       !CBB_flush(out)) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
     return 0;
@@ -153,18 +157,24 @@
 }
 
 static int rsa_opaque(const EVP_PKEY *pkey) {
-  return RSA_is_opaque(pkey->pkey.rsa);
+  const RSA *rsa = pkey->pkey;
+  return RSA_is_opaque(rsa);
 }
 
 static int int_rsa_size(const EVP_PKEY *pkey) {
-  return RSA_size(pkey->pkey.rsa);
+  const RSA *rsa = pkey->pkey;
+  return RSA_size(rsa);
 }
 
 static int rsa_bits(const EVP_PKEY *pkey) {
-  return RSA_bits(pkey->pkey.rsa);
+  const RSA *rsa = pkey->pkey;
+  return RSA_bits(rsa);
 }
 
-static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); }
+static void int_rsa_free(EVP_PKEY *pkey) {
+  RSA_free(pkey->pkey);
+  pkey->pkey = NULL;
+}
 
 const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = {
     EVP_PKEY_RSA,
diff --git a/crypto/evp/p_x25519.c b/crypto/evp/p_x25519.c
index 75ef6e1..6218943 100644
--- a/crypto/evp/p_x25519.c
+++ b/crypto/evp/p_x25519.c
@@ -38,8 +38,8 @@
   X25519_keypair(key->pub, key->priv);
   key->has_private = 1;
 
-  OPENSSL_free(pkey->pkey.ptr);
-  pkey->pkey.ptr = key;
+  OPENSSL_free(pkey->pkey);
+  pkey->pkey = key;
   return 1;
 }
 
@@ -50,8 +50,8 @@
     return 0;
   }
 
-  const X25519_KEY *our_key = ctx->pkey->pkey.ptr;
-  const X25519_KEY *peer_key = ctx->peerkey->pkey.ptr;
+  const X25519_KEY *our_key = ctx->pkey->pkey;
+  const X25519_KEY *peer_key = ctx->peerkey->pkey;
   if (our_key == NULL || peer_key == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
     return 0;
diff --git a/crypto/evp/p_x25519_asn1.c b/crypto/evp/p_x25519_asn1.c
index 3573f24..bf98427 100644
--- a/crypto/evp/p_x25519_asn1.c
+++ b/crypto/evp/p_x25519_asn1.c
@@ -24,8 +24,8 @@
 
 
 static void x25519_free(EVP_PKEY *pkey) {
-  OPENSSL_free(pkey->pkey.ptr);
-  pkey->pkey.ptr = NULL;
+  OPENSSL_free(pkey->pkey);
+  pkey->pkey = NULL;
 }
 
 static int x25519_set_priv_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) {
@@ -44,7 +44,7 @@
   key->has_private = 1;
 
   x25519_free(pkey);
-  pkey->pkey.ptr = key;
+  pkey->pkey = key;
   return 1;
 }
 
@@ -63,13 +63,13 @@
   key->has_private = 0;
 
   x25519_free(pkey);
-  pkey->pkey.ptr = key;
+  pkey->pkey = key;
   return 1;
 }
 
 static int x25519_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out,
-                                size_t *out_len) {
-  const X25519_KEY *key = pkey->pkey.ptr;
+                               size_t *out_len) {
+  const X25519_KEY *key = pkey->pkey;
   if (!key->has_private) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
     return 0;
@@ -92,7 +92,7 @@
 
 static int x25519_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out,
                                size_t *out_len) {
-  const X25519_KEY *key = pkey->pkey.ptr;
+  const X25519_KEY *key = pkey->pkey;
   if (out == NULL) {
     *out_len = 32;
     return 1;
@@ -115,7 +115,7 @@
 
 static size_t x25519_get1_tls_encodedpoint(const EVP_PKEY *pkey,
                                            uint8_t **out_ptr) {
-  const X25519_KEY *key = pkey->pkey.ptr;
+  const X25519_KEY *key = pkey->pkey;
   if (key == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
     return 0;
@@ -138,7 +138,7 @@
 }
 
 static int x25519_pub_encode(CBB *out, const EVP_PKEY *pkey) {
-  const X25519_KEY *key = pkey->pkey.ptr;
+  const X25519_KEY *key = pkey->pkey;
 
   // See RFC 8410, section 4.
   CBB spki, algorithm, oid, key_bitstring;
@@ -158,8 +158,8 @@
 }
 
 static int x25519_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
-  const X25519_KEY *a_key = a->pkey.ptr;
-  const X25519_KEY *b_key = b->pkey.ptr;
+  const X25519_KEY *a_key = a->pkey;
+  const X25519_KEY *b_key = b->pkey;
   return OPENSSL_memcmp(a_key->pub, b_key->pub, 32) == 0;
 }
 
@@ -180,7 +180,7 @@
 }
 
 static int x25519_priv_encode(CBB *out, const EVP_PKEY *pkey) {
-  X25519_KEY *key = pkey->pkey.ptr;
+  const X25519_KEY *key = pkey->pkey;
   if (!key->has_private) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
     return 0;
diff --git a/crypto/fipsmodule/service_indicator/service_indicator.c b/crypto/fipsmodule/service_indicator/service_indicator.c
index dd38bd7..b1ea28e 100644
--- a/crypto/fipsmodule/service_indicator/service_indicator.c
+++ b/crypto/fipsmodule/service_indicator/service_indicator.c
@@ -238,8 +238,9 @@
     }
   } else if (pkey_type == EVP_PKEY_EC) {
     // Check if the MD type and the elliptic curve are approved.
-    if (md_ok(md_type) && is_ec_fips_approved(EC_GROUP_get_curve_name(
-                              ctx->pctx->pkey->pkey.ec->group))) {
+    if (md_ok(md_type) &&
+        is_ec_fips_approved(EC_GROUP_get_curve_name(
+            EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(ctx->pctx->pkey))))) {
       FIPS_service_indicator_update_state();
     }
   }