vfs/tresor_trust_anchor: fix alignment faults

Fixes alignment faults that occured in the AES256 implementations while
wrapping or unwrapping keys on imx53_qsb, imx6q_sabrelite, and imx7d_sabre.
The problem was that the unwrap_key/wrap_key functions did reinterpret casts
from unsigned char pointers to uint64_t pointers and then directly used the 64
bit values of referenced by the latter. Most probably this caused the compiler
to optimize operations in the assumption that the pointer is 8-byte aligned
which then created alignment faults.

As a solution, this commit changes the interface of the wrap_key/unwrap_key
functions to take uint64 pointers as arguments instead of unsigned char
pointers and then adapts the function users to ensure that they refer to
appropriately aligned memory regions.

Fixed #4932
This commit is contained in:
Martin Stein 2023-06-28 10:49:54 +02:00 committed by Norman Feske
parent 6e7b66cb8a
commit 7b7851abfb
3 changed files with 68 additions and 60 deletions

View File

@ -97,12 +97,12 @@ void Aes_256::decrypt_with_zeroed_iv(unsigned char *plaintext_base,
}
void Aes_256_key_wrap::wrap_key(unsigned char *ciphertext_uint8,
size_t ciphertext_size,
unsigned char const *key_plaintext_uint8,
size_t key_plaintext_size,
unsigned char const *key_encryption_key_uint8,
size_t key_encryption_key_size)
void Aes_256_key_wrap::wrap_key(uint64_t *ciphertext_u64_ptr,
size_t ciphertext_size,
uint64_t const *key_plaintext_u64_ptr,
size_t key_plaintext_size,
uint64_t const *key_encryption_key_u64_ptr,
size_t key_encryption_key_size)
{
if (ciphertext_size != CIPHERTEXT_SIZE) {
class Bad_ciphertext_size { };
@ -116,15 +116,10 @@ void Aes_256_key_wrap::wrap_key(unsigned char *ciphertext_uint8,
class Bad_key_encryption_key_size { };
throw Bad_key_encryption_key_size { };
}
uint64_t *ciphertext { (uint64_t *)ciphertext_uint8 };
uint64_t const *key_plaintext { (uint64_t const *)key_plaintext_uint8 };
uint64_t const *key_encryption_key {
(uint64_t const *)key_encryption_key_uint8 };
ciphertext[0] = INTEGRITY_CHECK_VALUE;
ciphertext_u64_ptr[0] = INTEGRITY_CHECK_VALUE;
memcpy(
&ciphertext[1], &key_plaintext[0],
ciphertext_size - sizeof(ciphertext[0]));
&ciphertext_u64_ptr[1], &key_plaintext_u64_ptr[0],
ciphertext_size - sizeof(ciphertext_u64_ptr[0]));
for (unsigned step_idx = 0;
step_idx < NR_OF_WRAPPING_STEPS;
@ -135,8 +130,8 @@ void Aes_256_key_wrap::wrap_key(unsigned char *ciphertext_uint8,
value_idx++) {
uint64_t encryption_input[2];
encryption_input[0] = ciphertext[0];
encryption_input[1] = ciphertext[value_idx];
encryption_input[0] = ciphertext_u64_ptr[0];
encryption_input[1] = ciphertext_u64_ptr[value_idx];
uint64_t encryption_output[2];
@ -144,7 +139,7 @@ void Aes_256_key_wrap::wrap_key(unsigned char *ciphertext_uint8,
(unsigned char *)encryption_output,
sizeof(encryption_output),
(unsigned char *)encryption_input,
(unsigned char *)key_encryption_key,
(unsigned char *)key_encryption_key_u64_ptr,
key_encryption_key_size);
uint64_t const xor_operand {
@ -152,20 +147,20 @@ void Aes_256_key_wrap::wrap_key(unsigned char *ciphertext_uint8,
((uint64_t)KEY_PLAINTEXT_NR_OF_64_BIT_VALUES * step_idx) +
value_idx) };
ciphertext[0] = encryption_output[0] ^ xor_operand;
ciphertext[value_idx] = encryption_output[1];
ciphertext_u64_ptr[0] = encryption_output[0] ^ xor_operand;
ciphertext_u64_ptr[value_idx] = encryption_output[1];
}
}
}
void Aes_256_key_wrap::unwrap_key(unsigned char *key_plaintext_uint8,
size_t key_plaintext_size,
bool &key_plaintext_corrupt,
unsigned char const *ciphertext_uint8,
size_t ciphertext_size,
unsigned char const *key_encryption_key_uint8,
size_t key_encryption_key_size)
void Aes_256_key_wrap::unwrap_key(uint64_t *key_plaintext_u64_ptr,
size_t key_plaintext_size,
bool &key_plaintext_corrupt,
uint64_t const *ciphertext_u64_ptr,
size_t ciphertext_size,
uint64_t const *key_encryption_key_u64_ptr,
size_t key_encryption_key_size)
{
if (key_plaintext_size != KEY_PLAINTEXT_SIZE) {
class Bad_key_plaintext_size { };
@ -179,13 +174,8 @@ void Aes_256_key_wrap::unwrap_key(unsigned char *key_plaintext_uint8,
class Bad_key_encryption_key_size { };
throw Bad_key_encryption_key_size { };
}
uint64_t *key_plaintext { (uint64_t *)key_plaintext_uint8 };
uint64_t const *ciphertext { (uint64_t const *)ciphertext_uint8 };
uint64_t const *key_encryption_key {
(uint64_t const *)key_encryption_key_uint8 };
uint64_t integrity_check_value { ciphertext[0] };
memcpy(&key_plaintext[0], &ciphertext[1], key_plaintext_size);
uint64_t integrity_check_value { ciphertext_u64_ptr[0] };
memcpy(&key_plaintext_u64_ptr[0], &ciphertext_u64_ptr[1], key_plaintext_size);
for (signed step_idx = NR_OF_WRAPPING_STEPS - 1;
step_idx >= 0;
@ -202,7 +192,7 @@ void Aes_256_key_wrap::unwrap_key(unsigned char *key_plaintext_uint8,
uint64_t encryption_input[2];
encryption_input[0] = integrity_check_value ^ xor_operand;
encryption_input[1] = key_plaintext[value_idx - 1];
encryption_input[1] = key_plaintext_u64_ptr[value_idx - 1];
uint64_t encryption_output[2];
@ -210,11 +200,11 @@ void Aes_256_key_wrap::unwrap_key(unsigned char *key_plaintext_uint8,
(unsigned char *)encryption_output,
sizeof(encryption_output),
(unsigned char *)encryption_input,
(unsigned char *)key_encryption_key,
(unsigned char *)key_encryption_key_u64_ptr,
key_encryption_key_size);
integrity_check_value = encryption_output[0];
key_plaintext[value_idx - 1] = encryption_output[1];
key_plaintext_u64_ptr[value_idx - 1] = encryption_output[1];
}
}
if (integrity_check_value == INTEGRITY_CHECK_VALUE) {

View File

@ -45,12 +45,12 @@ namespace Aes_256_key_wrap
* key-encryption-key (KEK) size of 256 bits and a key (key data) size of
* 256 bits.
*/
void wrap_key(unsigned char *ciphertext_uint8,
Genode::size_t ciphertext_size,
unsigned char const *key_plaintext_uint8,
Genode::size_t key_plaintext_size,
unsigned char const *key_encryption_key_uint8,
Genode::size_t key_encryption_key_size);
void wrap_key(Genode::uint64_t *ciphertext_u64_ptr,
Genode::size_t ciphertext_size,
Genode::uint64_t const *key_plaintext_u64_ptr,
Genode::size_t key_plaintext_size,
Genode::uint64_t const *key_encryption_key_u64_ptr,
Genode::size_t key_encryption_key_size);
/**
* Implementation of the "Key Unwrap" algorithm (alternative indexing-based
@ -59,13 +59,13 @@ namespace Aes_256_key_wrap
* key-encryption-key (KEK) size of 256 bits and a key (key data) size of
* 256 bits.
*/
void unwrap_key(unsigned char *key_plaintext_uint8,
Genode::size_t key_plaintext_size,
bool &key_plaintext_corrupt,
unsigned char const *ciphertext_uint8,
Genode::size_t ciphertext_size,
unsigned char const *key_encryption_key_uint8,
Genode::size_t key_encryption_key_size);
void unwrap_key(Genode::uint64_t *key_plaintext_u64_ptr,
Genode::size_t key_plaintext_size,
bool &key_plaintext_corrupt,
Genode::uint64_t const *ciphertext_u64_ptr,
Genode::size_t ciphertext_size,
Genode::uint64_t const *key_encryption_key_u64_ptr,
Genode::size_t key_encryption_key_size);
}
#endif /* _AES_256_H_ */

View File

@ -68,6 +68,7 @@ class Trust_anchor
Trust_anchor(Trust_anchor const &) = delete;
Trust_anchor &operator=(Trust_anchor const&) = delete;
using uint64_t = Genode::uint64_t;
using size_t = Genode::size_t;
using Byte_range_ptr = Genode::Byte_range_ptr;
using Const_byte_range_ptr = Genode::Const_byte_range_ptr;
@ -113,8 +114,12 @@ class Trust_anchor
struct Private_key
{
unsigned char value[PRIVATE_KEY_SIZE] { };
unsigned char value[PRIVATE_KEY_SIZE] __attribute__((aligned(sizeof(uint64_t)))) { };
uint64_t const *u64_ptr() const { return (uint64_t const *)value; }
uint64_t *u64_ptr() { return (uint64_t *)value; }
};
Private_key _private_key { };
struct Last_hash
@ -128,9 +133,13 @@ class Trust_anchor
struct Key
{
enum { KEY_LEN = 32 };
unsigned char value[KEY_LEN] { };
unsigned char value[KEY_LEN] __attribute__((aligned(sizeof(uint64_t)))) { };
static constexpr size_t length = KEY_LEN;
uint64_t const *u64_ptr() const { return (uint64_t const *)value; }
uint64_t *u64_ptr() { return (uint64_t *)value; }
};
Key _decrypt_key { };
Key _encrypt_key { };
Key _generated_key { };
@ -269,12 +278,12 @@ class Trust_anchor
bool private_key_corrupt;
Aes_256_key_wrap::unwrap_key(
_private_key.value,
_private_key.u64_ptr(),
sizeof(_private_key.value),
private_key_corrupt,
(unsigned char *)_key_io_job_buffer.base,
_key_io_job_buffer.u64_ptr(),
_key_io_job_buffer.size,
(unsigned char *)_passphrase_hash_buffer.base,
_passphrase_hash_buffer.u64_ptr(),
_passphrase_hash_buffer.size);
if (private_key_corrupt) {
@ -342,11 +351,11 @@ class Trust_anchor
_key_io_job_buffer.size = Aes_256_key_wrap::CIPHERTEXT_SIZE;
Aes_256_key_wrap::wrap_key(
(unsigned char *)_key_io_job_buffer.base,
_key_io_job_buffer.u64_ptr(),
_key_io_job_buffer.size,
(unsigned char *)_private_key_io_job_buffer.base,
_private_key_io_job_buffer.u64_ptr(),
_private_key_io_job_buffer.size,
(unsigned char *)_passphrase_hash_buffer.base,
_passphrase_hash_buffer.u64_ptr(),
_passphrase_hash_buffer.size);
_job_state = Job_state::PENDING;
@ -543,13 +552,16 @@ class Trust_anchor
struct Private_key_io_job_buffer : Util::Io_job::Buffer
{
char buffer[PRIVATE_KEY_SIZE] { };
char buffer[PRIVATE_KEY_SIZE] __attribute__((aligned(sizeof(uint64_t)))) { };
Private_key_io_job_buffer()
{
Buffer::base = buffer;
Buffer::size = sizeof (buffer);
}
uint64_t const *u64_ptr() const { return (uint64_t const *)buffer; }
uint64_t *u64_ptr() { return (uint64_t *)buffer; }
};
Vfs::Vfs_handle *_private_key_handle { nullptr };
@ -563,24 +575,30 @@ class Trust_anchor
struct Key_io_job_buffer : Util::Io_job::Buffer
{
char buffer[Aes_256_key_wrap::CIPHERTEXT_SIZE] { };
char buffer[Aes_256_key_wrap::CIPHERTEXT_SIZE] __attribute__((aligned(sizeof(uint64_t)))) { };
Key_io_job_buffer()
{
Buffer::base = buffer;
Buffer::size = sizeof (buffer);
}
uint64_t const *u64_ptr() const { return (uint64_t const *)buffer; }
uint64_t *u64_ptr() { return (uint64_t *)buffer; }
};
struct Passphrase_hash_buffer : Util::Io_job::Buffer
{
char buffer[PASSPHRASE_HASH_SIZE] { };
char buffer[PASSPHRASE_HASH_SIZE] __attribute__((aligned(sizeof(uint64_t)))) { };
Passphrase_hash_buffer()
{
Buffer::base = buffer;
Buffer::size = sizeof (buffer);
}
uint64_t const *u64_ptr() const { return (uint64_t const *)buffer; }
uint64_t *u64_ptr() { return (uint64_t *)buffer; }
};
Key_io_job_buffer _key_io_job_buffer { };