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;