Don't use a union in Ed25519 EVP_PKEYs.

This may be okay because of the strict aliasing character type rule, but
easier not to think about it.

Bug: 301
Change-Id: I5eec356a5411a67036425e953e56529bac81ad4a
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53091
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index c8fce57..0037de8 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -239,18 +239,16 @@
 } /* EVP_PKEY_METHOD */;
 
 typedef struct {
-  union {
-    uint8_t priv[64];
-    struct {
-      // Shift the location of the public key to align with where it is in the
-      // private key representation.
-      uint8_t pad[32];
-      uint8_t value[32];
-    } pub;
-  } key;
+  // key is the concatenation of the private seed and public key. It is stored
+  // as a single 64-bit array to allow passing to |ED25519_sign|. If
+  // |has_private| is false, the first 32 bytes are uninitialized and the public
+  // key is in the last 32 bytes.
+  uint8_t key[64];
   char has_private;
 } ED25519_KEY;
 
+#define ED25519_PUBLIC_KEY_OFFSET 32
+
 typedef struct {
   uint8_t pub[32];
   uint8_t priv[32];
diff --git a/crypto/evp/p_ed25519.c b/crypto/evp/p_ed25519.c
index 9149afb..b3d8cc9 100644
--- a/crypto/evp/p_ed25519.c
+++ b/crypto/evp/p_ed25519.c
@@ -37,7 +37,7 @@
   }
 
   uint8_t pubkey_unused[32];
-  ED25519_keypair(pubkey_unused, key->key.priv);
+  ED25519_keypair(pubkey_unused, key->key);
   key->has_private = 1;
 
   OPENSSL_free(pkey->pkey.ptr);
@@ -64,7 +64,7 @@
     return 0;
   }
 
-  if (!ED25519_sign(sig, tbs, tbslen, key->key.priv)) {
+  if (!ED25519_sign(sig, tbs, tbslen, key->key)) {
     return 0;
   }
 
@@ -77,7 +77,7 @@
                                        size_t tbslen) {
   ED25519_KEY *key = ctx->pkey->pkey.ptr;
   if (siglen != 64 ||
-      !ED25519_verify(tbs, tbslen, sig, key->key.pub.value)) {
+      !ED25519_verify(tbs, tbslen, sig, key->key + ED25519_PUBLIC_KEY_OFFSET)) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE);
     return 0;
   }
diff --git a/crypto/evp/p_ed25519_asn1.c b/crypto/evp/p_ed25519_asn1.c
index 8d68592..f823c0d 100644
--- a/crypto/evp/p_ed25519_asn1.c
+++ b/crypto/evp/p_ed25519_asn1.c
@@ -43,7 +43,7 @@
   // The RFC 8032 encoding stores only the 32-byte seed, so we must recover the
   // full representation which we use from it.
   uint8_t pubkey_unused[32];
-  ED25519_keypair_from_seed(pubkey_unused, key->key.priv, in);
+  ED25519_keypair_from_seed(pubkey_unused, key->key, in);
   key->has_private = 1;
 
   ed25519_free(pkey);
@@ -63,7 +63,7 @@
     return 0;
   }
 
-  OPENSSL_memcpy(key->key.pub.value, in, 32);
+  OPENSSL_memcpy(key->key + ED25519_PUBLIC_KEY_OFFSET, in, 32);
   key->has_private = 0;
 
   ed25519_free(pkey);
@@ -90,7 +90,7 @@
   }
 
   // The raw private key format is the first 32 bytes of the private key.
-  OPENSSL_memcpy(out, key->key.priv, 32);
+  OPENSSL_memcpy(out, key->key, 32);
   *out_len = 32;
   return 1;
 }
@@ -108,7 +108,7 @@
     return 0;
   }
 
-  OPENSSL_memcpy(out, key->key.pub.value, 32);
+  OPENSSL_memcpy(out, key->key + ED25519_PUBLIC_KEY_OFFSET, 32);
   *out_len = 32;
   return 1;
 }
@@ -136,7 +136,8 @@
       !CBB_add_bytes(&oid, ed25519_asn1_meth.oid, ed25519_asn1_meth.oid_len) ||
       !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
       !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
-      !CBB_add_bytes(&key_bitstring, key->key.pub.value, 32) ||
+      !CBB_add_bytes(&key_bitstring, key->key + ED25519_PUBLIC_KEY_OFFSET,
+                     32) ||
       !CBB_flush(out)) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
     return 0;
@@ -148,7 +149,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;
-  return OPENSSL_memcmp(a_key->key.pub.value, b_key->key.pub.value, 32) == 0;
+  return OPENSSL_memcmp(a_key->key + ED25519_PUBLIC_KEY_OFFSET,
+                        b_key->key + ED25519_PUBLIC_KEY_OFFSET, 32) == 0;
 }
 
 static int ed25519_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) {
@@ -185,7 +187,7 @@
       !CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) ||
       // The PKCS#8 encoding stores only the 32-byte seed which is the first 32
       // bytes of the private key.
-      !CBB_add_bytes(&inner, key->key.priv, 32) ||
+      !CBB_add_bytes(&inner, key->key, 32) ||
       !CBB_flush(out)) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
     return 0;