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;