Skip to content

Commit d780e5e

Browse files
authored
Detect GCM-SIV alignment change (#1145)
1 parent 7c3fe1a commit d780e5e

File tree

5 files changed

+145
-4
lines changed

5 files changed

+145
-4
lines changed

crypto/cipher_extra/aead_test.cc

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include "../fipsmodule/cipher/internal.h"
2727
#include "../internal.h"
28+
#include "./internal.h"
2829
#include "../test/abi_test.h"
2930
#include "../test/file_test.h"
3031
#include "../test/test_util.h"
@@ -1247,6 +1248,117 @@ TEST(AEADTest, WycheproofXChaCha20Poly1305) {
12471248
});
12481249
}
12491250

1251+
static int awslc_encrypt(EVP_AEAD_CTX *ctx, uint8_t *nonce,
1252+
uint8_t *ct, uint8_t *pt) {
1253+
size_t ct_len = 0;
1254+
GTEST_LOG_(INFO) << "awslc_encrypt: Ctx.State Location: "
1255+
<< &ctx->state;
1256+
if (EVP_AEAD_CTX_seal(ctx, ct, &ct_len, 32, nonce, 12, pt, 16, NULL, 0) !=
1257+
1) {
1258+
return 1;
1259+
}
1260+
1261+
return 0;
1262+
}
1263+
1264+
static int awslc_decrypt(const EVP_AEAD *cipher, uint8_t ct[32], uint8_t *key,
1265+
size_t key_len, uint8_t nonce[12], uint8_t pt[16]) {
1266+
1267+
EVP_AEAD_CTX ctx;
1268+
size_t pt_len = 0;
1269+
1270+
EVP_AEAD_CTX_zero(&ctx);
1271+
if (EVP_AEAD_CTX_init(&ctx, cipher, key, key_len, 16, NULL) != 1) {
1272+
return 1;
1273+
}
1274+
GTEST_LOG_(INFO) << "awslc_decrypt: Ctx.State Location: " << &ctx.state;
1275+
1276+
if (EVP_AEAD_CTX_open(&ctx, pt, &pt_len, 16, nonce, 12, ct, 32, NULL, 0) !=
1277+
1) {
1278+
return 1;
1279+
}
1280+
1281+
return 0;
1282+
}
1283+
1284+
TEST(AEADTest, TestGCMSIV128Change16Alignment) {
1285+
uint8_t key[16] = {0};
1286+
uint8_t nonce[12] = {0};
1287+
uint8_t pt[16] = {0};
1288+
uint8_t ct[32] = {0};
1289+
EVP_AEAD_CTX* encrypt_ctx_128 = (EVP_AEAD_CTX*)malloc(sizeof(EVP_AEAD_CTX) + 8);
1290+
1291+
const EVP_AEAD *cipher_128 = EVP_aead_aes_128_gcm_siv();
1292+
1293+
EVP_AEAD_CTX_zero(encrypt_ctx_128);
1294+
ASSERT_TRUE(EVP_AEAD_CTX_init(encrypt_ctx_128, cipher_128, key, 16, 16, NULL))
1295+
<< ERR_error_string(ERR_get_error(), NULL);
1296+
ASSERT_FALSE(awslc_encrypt(encrypt_ctx_128, nonce, ct, pt))
1297+
<< ERR_error_string(ERR_get_error(), NULL);
1298+
ASSERT_FALSE(awslc_decrypt(cipher_128, ct, key, 16, nonce, pt))
1299+
<< ERR_error_string(ERR_get_error(), NULL);
1300+
1301+
GTEST_LOG_(INFO) << "Orig. Ctx.State Location: " << &encrypt_ctx_128->state;
1302+
EVP_AEAD_CTX *moved_encrypt_ctx_128 =
1303+
(EVP_AEAD_CTX *)(((uint8_t *)encrypt_ctx_128) + 8);
1304+
memmove(moved_encrypt_ctx_128, encrypt_ctx_128, sizeof(EVP_AEAD_CTX));
1305+
GTEST_LOG_(INFO) << "Moved Ctx.State Location: "
1306+
<< &moved_encrypt_ctx_128->state;
1307+
1308+
if (awslc_encrypt(moved_encrypt_ctx_128, nonce, ct, pt) != 1) {
1309+
if (x86_64_assembly_implementation_FOR_TESTING()) {
1310+
FAIL() << "Expected failure in awslc_encrypt";
1311+
}
1312+
} else {
1313+
if (!x86_64_assembly_implementation_FOR_TESTING()) {
1314+
FAIL() << "Failure in awslc_encrypt";
1315+
}
1316+
uint32_t err = ERR_get_error();
1317+
EXPECT_EQ(ERR_R_CIPHER_LIB, ERR_GET_LIB(err));
1318+
EXPECT_EQ(CIPHER_R_ALIGNMENT_CHANGED, ERR_GET_REASON(err));
1319+
}
1320+
free(encrypt_ctx_128);
1321+
}
1322+
1323+
TEST(AEADTest, TestGCMSIV256Change16Alignment) {
1324+
uint8_t nonce[12] = {0};
1325+
uint8_t key[32] = {0};
1326+
uint8_t pt[16] = {0};
1327+
uint8_t ct[32] = {0};
1328+
EVP_AEAD_CTX* encrypt_ctx_256 = (EVP_AEAD_CTX*)malloc(sizeof(EVP_AEAD_CTX) + 8);
1329+
1330+
const EVP_AEAD *cipher_256 = EVP_aead_aes_256_gcm_siv();
1331+
1332+
EVP_AEAD_CTX_zero(encrypt_ctx_256);
1333+
ASSERT_TRUE(EVP_AEAD_CTX_init(encrypt_ctx_256, cipher_256, key, 32, 16, NULL))
1334+
<< ERR_error_string(ERR_get_error(), NULL);
1335+
ASSERT_FALSE(awslc_encrypt(encrypt_ctx_256, nonce, ct, pt))
1336+
<< ERR_error_string(ERR_get_error(), NULL);
1337+
ASSERT_FALSE(awslc_decrypt(cipher_256, ct, key, 32, nonce, pt))
1338+
<< ERR_error_string(ERR_get_error(), NULL);
1339+
1340+
GTEST_LOG_(INFO) << "Orig. Ctx.State Location: " << &encrypt_ctx_256->state;
1341+
EVP_AEAD_CTX *moved_encrypt_ctx_256 =
1342+
(EVP_AEAD_CTX *)(((uint8_t *)encrypt_ctx_256) + 8);
1343+
memmove(moved_encrypt_ctx_256, encrypt_ctx_256, sizeof(EVP_AEAD_CTX));
1344+
GTEST_LOG_(INFO) << "Moved Ctx.State Location: "
1345+
<< &moved_encrypt_ctx_256->state;
1346+
1347+
if (awslc_encrypt(moved_encrypt_ctx_256, nonce, ct, pt) != 1) {
1348+
if (x86_64_assembly_implementation_FOR_TESTING()) {
1349+
FAIL() << "Expected failure in awslc_encrypt";
1350+
}
1351+
} else {
1352+
if (!x86_64_assembly_implementation_FOR_TESTING()) {
1353+
FAIL() << "Failure in awslc_encrypt";
1354+
}
1355+
uint32_t err = ERR_get_error();
1356+
EXPECT_EQ(ERR_R_CIPHER_LIB, ERR_GET_LIB(err));
1357+
EXPECT_EQ(CIPHER_R_ALIGNMENT_CHANGED, ERR_GET_REASON(err));
1358+
}
1359+
free(encrypt_ctx_256);
1360+
}
1361+
12501362
TEST(AEADTest, FreeNull) { EVP_AEAD_CTX_free(nullptr); }
12511363

12521364
// Deterministic IV generation for AES-GCM 256.

crypto/cipher_extra/e_aesgcmsiv.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
#include <openssl/err.h>
2222

2323
#include "../fipsmodule/cipher/internal.h"
24-
#include "../internal.h"
25-
24+
#include "./internal.h"
2625

2726
#define EVP_AEAD_AES_GCM_SIV_NONCE_LEN 12
2827
#define EVP_AEAD_AES_GCM_SIV_TAG_LEN 16
@@ -53,8 +52,11 @@ static struct aead_aes_gcm_siv_asm_ctx *asm_ctx_from_ctx(
5352
const EVP_AEAD_CTX *ctx) {
5453
// ctx->state must already be 8-byte aligned. Thus, at most, we may need to
5554
// add eight to align it to 16 bytes.
56-
const uintptr_t offset = ((uintptr_t)&ctx->state) & 8;
57-
return (struct aead_aes_gcm_siv_asm_ctx *)(&ctx->state.opaque[offset]);
55+
const uintptr_t actual_offset = ((uintptr_t)&ctx->state) & 8;
56+
if(ctx->state_offset != actual_offset) {
57+
return NULL;
58+
}
59+
return (struct aead_aes_gcm_siv_asm_ctx *)(&ctx->state.opaque[actual_offset]);
5860
}
5961

6062
// aes128gcmsiv_aes_ks writes an AES-128 key schedule for |key| to
@@ -85,7 +87,12 @@ static int aead_aes_gcm_siv_asm_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
8587
return 0;
8688
}
8789

90+
ctx->state_offset = ((uintptr_t)&ctx->state) & 8;
8891
struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = asm_ctx_from_ctx(ctx);
92+
if(gcm_siv_ctx == NULL) {
93+
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INITIALIZATION_ERROR);
94+
return 0;
95+
}
8996
assert((((uintptr_t)gcm_siv_ctx) & 15) == 0);
9097

9198
if (key_bits == 128) {
@@ -332,6 +339,10 @@ static int aead_aes_gcm_siv_asm_seal_scatter(
332339
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
333340
size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
334341
const struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = asm_ctx_from_ctx(ctx);
342+
if(gcm_siv_ctx == NULL) {
343+
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_ALIGNMENT_CHANGED);
344+
return 0;
345+
}
335346
const uint64_t in_len_64 = in_len;
336347
const uint64_t ad_len_64 = ad_len;
337348

@@ -420,6 +431,10 @@ static int aead_aes_gcm_siv_asm_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
420431
}
421432

422433
const struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = asm_ctx_from_ctx(ctx);
434+
if(gcm_siv_ctx == NULL) {
435+
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_ALIGNMENT_CHANGED);
436+
return 0;
437+
}
423438
const size_t plaintext_len = in_len - EVP_AEAD_AES_GCM_SIV_TAG_LEN;
424439
const uint8_t *const given_tag = in + plaintext_len;
425440

@@ -852,6 +867,13 @@ const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void) {
852867
return &aead_aes_256_gcm_siv;
853868
}
854869

870+
int x86_64_assembly_implementation_FOR_TESTING(void) {
871+
if (CRYPTO_is_AVX_capable() && CRYPTO_is_AESNI_capable()) {
872+
return 1;
873+
}
874+
return 0;
875+
}
876+
855877
#else
856878

857879
const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void) {
@@ -862,4 +884,8 @@ const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void) {
862884
return &aead_aes_256_gcm_siv;
863885
}
864886

887+
int x86_64_assembly_implementation_FOR_TESTING(void) {
888+
return 0;
889+
}
890+
865891
#endif // AES_GCM_SIV_ASM

crypto/cipher_extra/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ OPENSSL_INLINE void chacha20_poly1305_seal(uint8_t *out_ciphertext,
245245
}
246246
#endif
247247

248+
OPENSSL_EXPORT int x86_64_assembly_implementation_FOR_TESTING(void);
248249

249250
#if defined(__cplusplus)
250251
} // extern C

include/openssl/aead.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ union evp_aead_ctx_st_state {
222222
struct evp_aead_ctx_st {
223223
const EVP_AEAD *aead;
224224
union evp_aead_ctx_st_state state;
225+
uint8_t state_offset;
225226
// tag_len may contain the actual length of the authentication tag if it is
226227
// known at initialization time.
227228
uint8_t tag_len;

include/openssl/cipher.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,5 +690,6 @@ BSSL_NAMESPACE_END
690690
#define CIPHER_R_XTS_DATA_UNIT_IS_TOO_LARGE 139
691691
#define CIPHER_R_CTRL_OPERATION_NOT_PERFORMED 140
692692
#define CIPHER_R_SERIALIZATION_INVALID_EVP_AEAD_CTX 141
693+
#define CIPHER_R_ALIGNMENT_CHANGED 142
693694

694695
#endif // OPENSSL_HEADER_CIPHER_H

0 commit comments

Comments
 (0)