Skip to content

Commit

Permalink
Detect GCM-SIV alignment change (#1144)
Browse files Browse the repository at this point in the history
  • Loading branch information
justsmth authored Aug 10, 2023
1 parent f1d3a58 commit b90ca07
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 3 deletions.
112 changes: 112 additions & 0 deletions crypto/cipher_extra/aead_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "../fipsmodule/cipher/internal.h"
#include "../internal.h"
#include "./internal.h"
#include "../test/abi_test.h"
#include "../test/file_test.h"
#include "../test/test_util.h"
Expand Down Expand Up @@ -1263,3 +1264,114 @@ TEST(AEADTest, AEADAES256GCMDetIVGen) {
EXPECT_TRUE(EVP_AEAD_get_iv_from_ipv4_nanosecs(ip_address, fake_time, out));
EXPECT_EQ(Bytes(out, sizeof(out)), Bytes(expected, sizeof(expected)));
}

static int awslc_encrypt(EVP_AEAD_CTX *ctx, uint8_t *nonce,
uint8_t *ct, uint8_t *pt) {
size_t ct_len = 0;
GTEST_LOG_(INFO) << "awslc_encrypt: Ctx.State Location: "
<< &ctx->state;
if (EVP_AEAD_CTX_seal(ctx, ct, &ct_len, 32, nonce, 12, pt, 16, NULL, 0) !=
1) {
return 1;
}

return 0;
}

static int awslc_decrypt(const EVP_AEAD *cipher, uint8_t ct[32], uint8_t *key,
size_t key_len, uint8_t nonce[12], uint8_t pt[16]) {

EVP_AEAD_CTX ctx;
size_t pt_len = 0;

EVP_AEAD_CTX_zero(&ctx);
if (EVP_AEAD_CTX_init(&ctx, cipher, key, key_len, 16, NULL) != 1) {
return 1;
}
GTEST_LOG_(INFO) << "awslc_decrypt: Ctx.State Location: " << &ctx.state;

if (EVP_AEAD_CTX_open(&ctx, pt, &pt_len, 16, nonce, 12, ct, 32, NULL, 0) !=
1) {
return 1;
}

return 0;
}

TEST(AEADTest, TestGCMSIV128Change16Alignment) {
uint8_t key[16] = {0};
uint8_t nonce[12] = {0};
uint8_t pt[16] = {0};
uint8_t ct[32] = {0};
EVP_AEAD_CTX* encrypt_ctx_128 = (EVP_AEAD_CTX*)malloc(sizeof(EVP_AEAD_CTX) + 8);

const EVP_AEAD *cipher_128 = EVP_aead_aes_128_gcm_siv();

EVP_AEAD_CTX_zero(encrypt_ctx_128);
ASSERT_TRUE(EVP_AEAD_CTX_init(encrypt_ctx_128, cipher_128, key, 16, 16, NULL))
<< ERR_error_string(ERR_get_error(), NULL);
ASSERT_FALSE(awslc_encrypt(encrypt_ctx_128, nonce, ct, pt))
<< ERR_error_string(ERR_get_error(), NULL);
ASSERT_FALSE(awslc_decrypt(cipher_128, ct, key, 16, nonce, pt))
<< ERR_error_string(ERR_get_error(), NULL);

GTEST_LOG_(INFO) << "Orig. Ctx.State Location: " << &encrypt_ctx_128->state;
EVP_AEAD_CTX *moved_encrypt_ctx_128 =
(EVP_AEAD_CTX *)(((uint8_t *)encrypt_ctx_128) + 8);
memmove(moved_encrypt_ctx_128, encrypt_ctx_128, sizeof(EVP_AEAD_CTX));
GTEST_LOG_(INFO) << "Moved Ctx.State Location: "
<< &moved_encrypt_ctx_128->state;

if (awslc_encrypt(moved_encrypt_ctx_128, nonce, ct, pt) != 1) {
if (x86_64_assembly_implementation_FOR_TESTING()) {
FAIL() << "Expected failure in awslc_encrypt";
}
} else {
if (!x86_64_assembly_implementation_FOR_TESTING()) {
FAIL() << "Failure in awslc_encrypt";
}
uint32_t err = ERR_get_error();
EXPECT_EQ(ERR_R_CIPHER_LIB, ERR_GET_LIB(err));
EXPECT_EQ(CIPHER_R_ALIGNMENT_CHANGED, ERR_GET_REASON(err));
}
free(encrypt_ctx_128);
}

TEST(AEADTest, TestGCMSIV256Change16Alignment) {
uint8_t nonce[12] = {0};
uint8_t key[32] = {0};
uint8_t pt[16] = {0};
uint8_t ct[32] = {0};
EVP_AEAD_CTX* encrypt_ctx_256 = (EVP_AEAD_CTX*)malloc(sizeof(EVP_AEAD_CTX) + 8);

const EVP_AEAD *cipher_256 = EVP_aead_aes_256_gcm_siv();

EVP_AEAD_CTX_zero(encrypt_ctx_256);
ASSERT_TRUE(EVP_AEAD_CTX_init(encrypt_ctx_256, cipher_256, key, 32, 16, NULL))
<< ERR_error_string(ERR_get_error(), NULL);
ASSERT_FALSE(awslc_encrypt(encrypt_ctx_256, nonce, ct, pt))
<< ERR_error_string(ERR_get_error(), NULL);
ASSERT_FALSE(awslc_decrypt(cipher_256, ct, key, 32, nonce, pt))
<< ERR_error_string(ERR_get_error(), NULL);

GTEST_LOG_(INFO) << "Orig. Ctx.State Location: " << &encrypt_ctx_256->state;
EVP_AEAD_CTX *moved_encrypt_ctx_256 =
(EVP_AEAD_CTX *)(((uint8_t *)encrypt_ctx_256) + 8);
memmove(moved_encrypt_ctx_256, encrypt_ctx_256, sizeof(EVP_AEAD_CTX));
GTEST_LOG_(INFO) << "Moved Ctx.State Location: "
<< &moved_encrypt_ctx_256->state;

if (awslc_encrypt(moved_encrypt_ctx_256, nonce, ct, pt) != 1) {
if (x86_64_assembly_implementation_FOR_TESTING()) {
FAIL() << "Expected failure in awslc_encrypt";
}
} else {
if (!x86_64_assembly_implementation_FOR_TESTING()) {
FAIL() << "Failure in awslc_encrypt";
}
uint32_t err = ERR_get_error();
EXPECT_EQ(ERR_R_CIPHER_LIB, ERR_GET_LIB(err));
EXPECT_EQ(CIPHER_R_ALIGNMENT_CHANGED, ERR_GET_REASON(err));
}
free(encrypt_ctx_256);
}
32 changes: 30 additions & 2 deletions crypto/cipher_extra/e_aesgcmsiv.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "../fipsmodule/cipher/internal.h"
#include "../internal.h"
#include "./internal.h"


#define EVP_AEAD_AES_GCM_SIV_NONCE_LEN 12
Expand Down Expand Up @@ -53,8 +54,11 @@ static struct aead_aes_gcm_siv_asm_ctx *asm_ctx_from_ctx(
const EVP_AEAD_CTX *ctx) {
// ctx->state must already be 8-byte aligned. Thus, at most, we may need to
// add eight to align it to 16 bytes.
const uintptr_t offset = ((uintptr_t)&ctx->state) & 8;
return (struct aead_aes_gcm_siv_asm_ctx *)(&ctx->state.opaque[offset]);
const uintptr_t actual_offset = ((uintptr_t)&ctx->state) & 8;
if(ctx->state_offset != actual_offset) {
return NULL;
}
return (struct aead_aes_gcm_siv_asm_ctx *)(&ctx->state.opaque[actual_offset]);
}

// aes128gcmsiv_aes_ks writes an AES-128 key schedule for |key| to
Expand Down Expand Up @@ -85,7 +89,12 @@ static int aead_aes_gcm_siv_asm_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
return 0;
}

ctx->state_offset = ((uintptr_t)&ctx->state) & 8;
struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = asm_ctx_from_ctx(ctx);
if(gcm_siv_ctx == NULL) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INITIALIZATION_ERROR);
return 0;
}
assert((((uintptr_t)gcm_siv_ctx) & 15) == 0);

if (key_bits == 128) {
Expand Down Expand Up @@ -332,6 +341,10 @@ static int aead_aes_gcm_siv_asm_seal_scatter(
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
const struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = asm_ctx_from_ctx(ctx);
if(gcm_siv_ctx == NULL) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_ALIGNMENT_CHANGED);
return 0;
}
const uint64_t in_len_64 = in_len;
const uint64_t ad_len_64 = ad_len;

Expand Down Expand Up @@ -419,6 +432,10 @@ static int aead_aes_gcm_siv_asm_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
}

const struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = asm_ctx_from_ctx(ctx);
if(gcm_siv_ctx == NULL) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_ALIGNMENT_CHANGED);
return 0;
}
const size_t plaintext_len = in_len - EVP_AEAD_AES_GCM_SIV_TAG_LEN;
const uint8_t *const given_tag = in + plaintext_len;

Expand Down Expand Up @@ -849,10 +866,21 @@ const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void) {
return &aead_aes_256_gcm_siv;
}

int x86_64_assembly_implementation_FOR_TESTING(void) {
if (CRYPTO_is_AVX_capable() && CRYPTO_is_AESNI_capable()) {
return 1;
}
return 0;
}

#else

const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void) { return &aead_aes_128_gcm_siv; }

const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void) { return &aead_aes_256_gcm_siv; }

int x86_64_assembly_implementation_FOR_TESTING(void) {
return 0;
}

#endif // AES_GCM_SIV_ASM
4 changes: 3 additions & 1 deletion crypto/cipher_extra/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
extern "C" {
#endif

OPENSSL_EXPORT int x86_64_assembly_implementation_FOR_TESTING(void);

#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
!defined(MY_ASSEMBLER_IS_TOO_OLD_FOR_AVX) && !defined(AWSLC_FIPS)
#define AES_CBC_HMAC_SHA_STITCH
Expand Down Expand Up @@ -149,7 +151,7 @@ int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out,
const uint8_t *mac_secret,
unsigned mac_secret_length);

// EVP_tls_cbc_digest_record_sha256 performs the same functionality of
// EVP_tls_cbc_digest_record_sha256 performs the same functionality of
// EVP_tls_cbc_digest_record except it internally calls SHA256 instead of SHA1.
int EVP_tls_cbc_digest_record_sha256(const EVP_MD *md, uint8_t *md_out,
size_t *md_out_size, const uint8_t header[13],
Expand Down
1 change: 1 addition & 0 deletions include/openssl/aead.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ union evp_aead_ctx_st_state {
struct evp_aead_ctx_st {
const EVP_AEAD *aead;
union evp_aead_ctx_st_state state;
uint8_t state_offset;
// tag_len may contain the actual length of the authentication tag if it is
// known at initialization time.
uint8_t tag_len;
Expand Down
1 change: 1 addition & 0 deletions include/openssl/cipher.h
Original file line number Diff line number Diff line change
Expand Up @@ -709,5 +709,6 @@ BSSL_NAMESPACE_END
#define CIPHER_R_XTS_DATA_UNIT_IS_TOO_LARGE 139
#define CIPHER_R_CTRL_OPERATION_NOT_PERFORMED 140
#define CIPHER_R_SERIALIZATION_INVALID_EVP_AEAD_CTX 141
#define CIPHER_R_ALIGNMENT_CHANGED 142

#endif // OPENSSL_HEADER_CIPHER_H

0 comments on commit b90ca07

Please sign in to comment.