Replace some more C unions.
I don't think these are all UB by C's rules, but it's easier not to
think about the pointers. Still more to go, but these were some easy
ones.
Bug: 301
Change-Id: Icdcb7fb40f85983cbf566786c5f7dbfd7bb06571
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/52905
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/crypto/bytestring/cbb.c b/crypto/bytestring/cbb.c
index 12587cd..6ce20ad 100644
--- a/crypto/bytestring/cbb.c
+++ b/crypto/bytestring/cbb.c
@@ -542,14 +542,11 @@
return CBB_add_asn1_uint64(cbb, value);
}
- union {
- int64_t i;
- uint8_t bytes[sizeof(int64_t)];
- } u;
- u.i = value;
+ uint8_t bytes[sizeof(int64_t)];
+ memcpy(bytes, &value, sizeof(value));
int start = 7;
// Skip leading sign-extension bytes unless they are necessary.
- while (start > 0 && (u.bytes[start] == 0xff && (u.bytes[start - 1] & 0x80))) {
+ while (start > 0 && (bytes[start] == 0xff && (bytes[start - 1] & 0x80))) {
start--;
}
@@ -558,7 +555,7 @@
return 0;
}
for (int i = start; i >= 0; i--) {
- if (!CBB_add_u8(&child, u.bytes[i])) {
+ if (!CBB_add_u8(&child, bytes[i])) {
return 0;
}
}
diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c
index 010897b..741ecfb 100644
--- a/crypto/bytestring/cbs.c
+++ b/crypto/bytestring/cbs.c
@@ -496,15 +496,12 @@
if (len > sizeof(int64_t)) {
return 0;
}
- union {
- int64_t i;
- uint8_t bytes[sizeof(int64_t)];
- } u;
- memset(u.bytes, is_negative ? 0xff : 0, sizeof(u.bytes)); // Sign-extend.
+ uint8_t sign_extend[sizeof(int64_t)];
+ memset(sign_extend, is_negative ? 0xff : 0, sizeof(sign_extend));
for (size_t i = 0; i < len; i++) {
- u.bytes[i] = data[len - i - 1];
+ sign_extend[i] = data[len - i - 1];
}
- *out = u.i;
+ memcpy(out, sign_extend, sizeof(sign_extend));
return 1;
}
diff --git a/crypto/cipher_extra/e_aesgcmsiv.c b/crypto/cipher_extra/e_aesgcmsiv.c
index 387eaff..555922d 100644
--- a/crypto/cipher_extra/e_aesgcmsiv.c
+++ b/crypto/cipher_extra/e_aesgcmsiv.c
@@ -262,17 +262,10 @@
aesgcmsiv_polyval_horner(out_tag, auth_key, scratch, 1);
}
- union {
- uint8_t c[16];
- struct {
- uint64_t ad;
- uint64_t in;
- } bitlens;
- } length_block;
-
- length_block.bitlens.ad = ad_len * 8;
- length_block.bitlens.in = in_len * 8;
- aesgcmsiv_polyval_horner(out_tag, auth_key, length_block.c, 1);
+ uint8_t length_block[16];
+ CRYPTO_store_u64_le(length_block, ad_len * 8);
+ CRYPTO_store_u64_le(length_block + 8, in_len * 8);
+ aesgcmsiv_polyval_horner(out_tag, auth_key, length_block, 1);
for (size_t i = 0; i < 12; i++) {
out_tag[i] ^= nonce[i];
@@ -289,18 +282,15 @@
int is_128_bit, uint8_t *out, const uint8_t *in, size_t in_len,
const uint8_t tag[16],
const struct aead_aes_gcm_siv_asm_ctx *enc_key_expanded) {
- alignas(16) union {
- uint8_t c[16];
- uint32_t u32[4];
- } counter;
+ alignas(16) uint8_t counter[16];
OPENSSL_memcpy(&counter, tag, sizeof(counter));
- counter.c[15] |= 0x80;
- counter.u32[0] += in_len / 16;
+ counter[15] |= 0x80;
+ CRYPTO_store_u32_le(counter, CRYPTO_load_u32_le(counter) + in_len / 16);
if (is_128_bit) {
- aes128gcmsiv_ecb_enc_block(&counter.c[0], &counter.c[0], enc_key_expanded);
+ aes128gcmsiv_ecb_enc_block(counter, counter, enc_key_expanded);
} else {
- aes256gcmsiv_ecb_enc_block(&counter.c[0], &counter.c[0], enc_key_expanded);
+ aes256gcmsiv_ecb_enc_block(counter, counter, enc_key_expanded);
}
const size_t last_bytes_offset = in_len & ~15;
@@ -308,7 +298,7 @@
uint8_t *last_bytes_out = &out[last_bytes_offset];
const uint8_t *last_bytes_in = &in[last_bytes_offset];
for (size_t i = 0; i < last_bytes_len; i++) {
- last_bytes_out[i] = last_bytes_in[i] ^ counter.c[i];
+ last_bytes_out[i] = last_bytes_in[i] ^ counter[i];
}
}
@@ -489,18 +479,11 @@
scratch, 1);
}
- union {
- uint8_t c[16];
- struct {
- uint64_t ad;
- uint64_t in;
- } bitlens;
- } length_block;
-
- length_block.bitlens.ad = ad_len * 8;
- length_block.bitlens.in = plaintext_len * 8;
+ uint8_t length_block[16];
+ CRYPTO_store_u64_le(length_block, ad_len * 8);
+ CRYPTO_store_u64_le(length_block + 8, plaintext_len * 8);
aesgcmsiv_polyval_horner(calculated_tag, (const uint8_t *)record_auth_key,
- length_block.c, 1);
+ length_block, 1);
for (size_t i = 0; i < 12; i++) {
calculated_tag[i] ^= nonce[i];
@@ -619,18 +602,15 @@
static void gcm_siv_crypt(uint8_t *out, const uint8_t *in, size_t in_len,
const uint8_t initial_counter[AES_BLOCK_SIZE],
block128_f enc_block, const AES_KEY *key) {
- union {
- uint32_t w[4];
- uint8_t c[16];
- } counter;
+ uint8_t counter[16];
- OPENSSL_memcpy(counter.c, initial_counter, AES_BLOCK_SIZE);
- counter.c[15] |= 0x80;
+ OPENSSL_memcpy(counter, initial_counter, AES_BLOCK_SIZE);
+ counter[15] |= 0x80;
for (size_t done = 0; done < in_len;) {
uint8_t keystream[AES_BLOCK_SIZE];
- enc_block(counter.c, keystream, key);
- counter.w[0]++;
+ enc_block(counter, keystream, key);
+ CRYPTO_store_u32_le(counter, CRYPTO_load_u32_le(counter) + 1);
size_t todo = AES_BLOCK_SIZE;
if (in_len - done < todo) {
@@ -670,17 +650,10 @@
CRYPTO_POLYVAL_update_blocks(&polyval_ctx, scratch, sizeof(scratch));
}
- union {
- uint8_t c[16];
- struct {
- uint64_t ad;
- uint64_t in;
- } bitlens;
- } length_block;
-
- length_block.bitlens.ad = ad_len * 8;
- length_block.bitlens.in = in_len * 8;
- CRYPTO_POLYVAL_update_blocks(&polyval_ctx, length_block.c,
+ uint8_t length_block[16];
+ CRYPTO_store_u64_le(length_block, ad_len * 8);
+ CRYPTO_store_u64_le(length_block + 8, in_len * 8);
+ CRYPTO_POLYVAL_update_blocks(&polyval_ctx, length_block,
sizeof(length_block));
CRYPTO_POLYVAL_finish(&polyval_ctx, out_tag);
diff --git a/crypto/curve25519/curve25519.c b/crypto/curve25519/curve25519.c
index e316acd..4bf37b9 100644
--- a/crypto/curve25519/curve25519.c
+++ b/crypto/curve25519/curve25519.c
@@ -1936,11 +1936,8 @@
OPENSSL_memcpy(pkcopy, public_key, 32);
uint8_t rcopy[32];
OPENSSL_memcpy(rcopy, signature, 32);
- union {
- uint64_t u64[4];
- uint8_t u8[32];
- } scopy;
- OPENSSL_memcpy(&scopy.u8[0], signature + 32, 32);
+ uint8_t scopy[32];
+ OPENSSL_memcpy(scopy, signature + 32, 32);
// https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
// the range [0, order) in order to prevent signature malleability.
@@ -1953,9 +1950,10 @@
UINT64_C(0x1000000000000000),
};
for (size_t i = 3;; i--) {
- if (scopy.u64[i] > kOrder[i]) {
+ uint64_t word = CRYPTO_load_u64_le(scopy + i * 8);
+ if (word > kOrder[i]) {
return 0;
- } else if (scopy.u64[i] < kOrder[i]) {
+ } else if (word < kOrder[i]) {
break;
} else if (i == 0) {
return 0;
@@ -1973,7 +1971,7 @@
x25519_sc_reduce(h);
ge_p2 R;
- ge_double_scalarmult_vartime(&R, h, &A, scopy.u8);
+ ge_double_scalarmult_vartime(&R, h, &A, scopy);
uint8_t rcheck[32];
x25519_ge_tobytes(rcheck, &R);
diff --git a/crypto/fipsmodule/cipher/e_aes.c b/crypto/fipsmodule/cipher/e_aes.c
index 7677355..61f4ef3 100644
--- a/crypto/fipsmodule/cipher/e_aes.c
+++ b/crypto/fipsmodule/cipher/e_aes.c
@@ -99,16 +99,13 @@
out += 16 * bsaes_blocks;
blocks -= bsaes_blocks;
- union {
- uint32_t u32[4];
- uint8_t u8[16];
- } new_ivec;
- memcpy(new_ivec.u8, ivec, 16);
- uint32_t ctr = CRYPTO_bswap4(new_ivec.u32[3]) + bsaes_blocks;
- new_ivec.u32[3] = CRYPTO_bswap4(ctr);
+ uint8_t new_ivec[16];
+ memcpy(new_ivec, ivec, 12);
+ uint32_t ctr = CRYPTO_load_u32_be(ivec + 12) + bsaes_blocks;
+ CRYPTO_store_u32_be(new_ivec + 12, ctr);
// Finish any remaining blocks with |vpaes_ctr32_encrypt_blocks|.
- vpaes_ctr32_encrypt_blocks(in, out, blocks, key, new_ivec.u8);
+ vpaes_ctr32_encrypt_blocks(in, out, blocks, key, new_ivec);
}
#endif // BSAES
diff --git a/crypto/fipsmodule/modes/gcm.c b/crypto/fipsmodule/modes/gcm.c
index 5b909aa..1a77ec0 100644
--- a/crypto/fipsmodule/modes/gcm.c
+++ b/crypto/fipsmodule/modes/gcm.c
@@ -137,76 +137,69 @@
const uint8_t gcm_key[16]) {
*out_is_avx = 0;
- union {
- uint64_t u[2];
- uint8_t c[16];
- } H;
-
- OPENSSL_memcpy(H.c, gcm_key, 16);
-
- // H is stored in host byte order
- H.u[0] = CRYPTO_bswap8(H.u[0]);
- H.u[1] = CRYPTO_bswap8(H.u[1]);
-
- OPENSSL_memcpy(out_key, H.c, 16);
+ // H is stored in host byte order.
+ uint64_t H[2] = {CRYPTO_load_u64_be(gcm_key),
+ CRYPTO_load_u64_be(gcm_key + 8)};
+ out_key->hi = H[0];
+ out_key->lo = H[1];
#if defined(GHASH_ASM_X86_64)
if (crypto_gcm_clmul_enabled()) {
if (CRYPTO_is_AVX_capable() && CRYPTO_is_MOVBE_capable()) {
- gcm_init_avx(out_table, H.u);
+ gcm_init_avx(out_table, H);
*out_mult = gcm_gmult_avx;
*out_hash = gcm_ghash_avx;
*out_is_avx = 1;
return;
}
- gcm_init_clmul(out_table, H.u);
+ gcm_init_clmul(out_table, H);
*out_mult = gcm_gmult_clmul;
*out_hash = gcm_ghash_clmul;
return;
}
if (CRYPTO_is_SSSE3_capable()) {
- gcm_init_ssse3(out_table, H.u);
+ gcm_init_ssse3(out_table, H);
*out_mult = gcm_gmult_ssse3;
*out_hash = gcm_ghash_ssse3;
return;
}
#elif defined(GHASH_ASM_X86)
if (crypto_gcm_clmul_enabled()) {
- gcm_init_clmul(out_table, H.u);
+ gcm_init_clmul(out_table, H);
*out_mult = gcm_gmult_clmul;
*out_hash = gcm_ghash_clmul;
return;
}
if (CRYPTO_is_SSSE3_capable()) {
- gcm_init_ssse3(out_table, H.u);
+ gcm_init_ssse3(out_table, H);
*out_mult = gcm_gmult_ssse3;
*out_hash = gcm_ghash_ssse3;
return;
}
#elif defined(GHASH_ASM_ARM)
if (gcm_pmull_capable()) {
- gcm_init_v8(out_table, H.u);
+ gcm_init_v8(out_table, H);
*out_mult = gcm_gmult_v8;
*out_hash = gcm_ghash_v8;
return;
}
if (gcm_neon_capable()) {
- gcm_init_neon(out_table, H.u);
+ gcm_init_neon(out_table, H);
*out_mult = gcm_gmult_neon;
*out_hash = gcm_ghash_neon;
return;
}
#elif defined(GHASH_ASM_PPC64LE)
if (CRYPTO_is_PPC64LE_vcrypto_capable()) {
- gcm_init_p8(out_table, H.u);
+ gcm_init_p8(out_table, H);
*out_mult = gcm_gmult_p8;
*out_hash = gcm_ghash_p8;
return;
}
#endif
- gcm_init_nohw(out_table, H.u);
+ gcm_init_nohw(out_table, H);
*out_mult = gcm_gmult_nohw;
*out_hash = gcm_ghash_nohw;
}
diff --git a/crypto/internal.h b/crypto/internal.h
index c9b5e8e..2e94399 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -881,6 +881,16 @@
OPENSSL_memcpy(out, &v, sizeof(v));
}
+static inline uint64_t CRYPTO_load_u64_le(const void *in) {
+ uint64_t v;
+ OPENSSL_memcpy(&v, in, sizeof(v));
+ return v;
+}
+
+static inline void CRYPTO_store_u64_le(void *out, uint64_t v) {
+ OPENSSL_memcpy(out, &v, sizeof(v));
+}
+
static inline uint64_t CRYPTO_load_u64_be(const void *ptr) {
uint64_t ret;
OPENSSL_memcpy(&ret, ptr, sizeof(ret));
diff --git a/crypto/siphash/siphash.c b/crypto/siphash/siphash.c
index bb9a0c1..0921eac 100644
--- a/crypto/siphash/siphash.c
+++ b/crypto/siphash/siphash.c
@@ -48,8 +48,7 @@
v[3] = key[1] ^ UINT64_C(0x7465646279746573);
while (input_len >= sizeof(uint64_t)) {
- uint64_t m;
- memcpy(&m, input, sizeof(m));
+ uint64_t m = CRYPTO_load_u64_le(input);
v[3] ^= m;
siphash_round(v);
siphash_round(v);
@@ -59,18 +58,16 @@
input_len -= sizeof(uint64_t);
}
- union {
- uint8_t bytes[8];
- uint64_t word;
- } last_block;
- last_block.word = 0;
- OPENSSL_memcpy(last_block.bytes, input, input_len);
- last_block.bytes[7] = orig_input_len & 0xff;
+ uint8_t last_block[8];
+ OPENSSL_memset(last_block, 0, sizeof(last_block));
+ OPENSSL_memcpy(last_block, input, input_len);
+ last_block[7] = orig_input_len & 0xff;
- v[3] ^= last_block.word;
+ uint64_t last_block_word = CRYPTO_load_u64_le(last_block);
+ v[3] ^= last_block_word;
siphash_round(v);
siphash_round(v);
- v[0] ^= last_block.word;
+ v[0] ^= last_block_word;
v[2] ^= 0xff;
siphash_round(v);
diff --git a/crypto/siphash/siphash_test.cc b/crypto/siphash/siphash_test.cc
index 6d8f9e7..6407e0d 100644
--- a/crypto/siphash/siphash_test.cc
+++ b/crypto/siphash/siphash_test.cc
@@ -23,14 +23,12 @@
TEST(SipHash, Basic) {
// This is the example from appendix A of the SipHash paper.
- union {
- uint8_t bytes[16];
- uint64_t words[2];
- } key;
-
+ uint8_t key_bytes[16];
for (unsigned i = 0; i < 16; i++) {
- key.bytes[i] = i;
+ key_bytes[i] = i;
}
+ uint64_t key[2];
+ memcpy(key, key_bytes, sizeof(key));
uint8_t input[15];
for (unsigned i = 0; i < sizeof(input); i++) {
@@ -38,7 +36,7 @@
}
EXPECT_EQ(UINT64_C(0xa129ca6149be45e5),
- SIPHASH_24(key.words, input, sizeof(input)));
+ SIPHASH_24(key, input, sizeof(input)));
}
TEST(SipHash, Vectors) {