Skip to content

Commit

Permalink
Added validation for key and iv sizes. (#146)
Browse files Browse the repository at this point in the history
* Added validation for aes key and iv sizes.
  • Loading branch information
JonathanHenson committed Apr 20, 2023
1 parent e6f21a4 commit d6332a8
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 7 deletions.
1 change: 1 addition & 0 deletions include/aws/cal/cal.h
Expand Up @@ -23,6 +23,7 @@ enum aws_cal_errors {
AWS_ERROR_CAL_MISMATCHED_DER_TYPE,
AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM,
AWS_ERROR_CAL_BUFFER_TOO_LARGE_FOR_ALGORITHM,
AWS_ERROR_CAL_INVALID_CIPHER_MATERIAL_SIZE_FOR_ALGORITHM,
AWS_ERROR_CAL_END_RANGE = AWS_ERROR_ENUM_END_RANGE(AWS_C_CAL_PACKAGE_ID)
};

Expand Down
6 changes: 5 additions & 1 deletion source/cal.c
Expand Up @@ -36,7 +36,11 @@ static struct aws_error_info s_errors[] = {
AWS_DEFINE_ERROR_INFO_CAL(
AWS_ERROR_CAL_BUFFER_TOO_LARGE_FOR_ALGORITHM,
"The input passed to a cipher algorithm was too large for that algorithm. Consider breaking the input into "
"smaller chunks.")};
"smaller chunks."),
AWS_DEFINE_ERROR_INFO_CAL(
AWS_ERROR_CAL_INVALID_CIPHER_MATERIAL_SIZE_FOR_ALGORITHM,
"A cipher material such as an initialization vector or tag was an incorrect size for the selected algorithm."),
};

static struct aws_error_info_list s_list = {
.error_list = s_errors,
Expand Down
43 changes: 37 additions & 6 deletions source/symmetric_cipher.c
Expand Up @@ -79,23 +79,47 @@ static aws_aes_ctr_256_new_fn *s_aes_ctr_new_fn = aws_aes_ctr_256_new_impl;
static aws_aes_gcm_256_new_fn *s_aes_gcm_new_fn = aws_aes_gcm_256_new_impl;
static aws_aes_keywrap_256_new_fn *s_aes_keywrap_new_fn = aws_aes_keywrap_256_new_impl;

static bool s_check_input_size_limits(const struct aws_symmetric_cipher *cipher, const struct aws_byte_cursor *input) {
static int s_check_input_size_limits(const struct aws_symmetric_cipher *cipher, const struct aws_byte_cursor *input) {
/* libcrypto uses int, not size_t, so this is the limit.
* For simplicity, enforce the same rules on all platforms. */
return input->len <= INT_MAX - cipher->block_size;
return input->len <= INT_MAX - cipher->block_size ? AWS_OP_SUCCESS
: aws_raise_error(AWS_ERROR_CAL_BUFFER_TOO_LARGE_FOR_ALGORITHM);
}

static int s_validate_key_materials(
const struct aws_byte_cursor *key,
size_t expected_key_size,
const struct aws_byte_cursor *iv,
size_t expected_iv_size) {
if (key && key->len != expected_key_size) {
return aws_raise_error(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM);
}

if (iv && iv->len != expected_iv_size) {
return aws_raise_error(AWS_ERROR_CAL_INVALID_CIPHER_MATERIAL_SIZE_FOR_ALGORITHM);
}

return AWS_OP_SUCCESS;
}

struct aws_symmetric_cipher *aws_aes_cbc_256_new(
struct aws_allocator *allocator,
const struct aws_byte_cursor *key,
const struct aws_byte_cursor *iv) {

if (s_validate_key_materials(key, AWS_AES_256_KEY_BYTE_LEN, iv, AWS_AES_256_CIPHER_BLOCK_SIZE) != AWS_OP_SUCCESS) {
return NULL;
}
return s_aes_cbc_new_fn(allocator, key, iv);
}

struct aws_symmetric_cipher *aws_aes_ctr_256_new(
struct aws_allocator *allocator,
const struct aws_byte_cursor *key,
const struct aws_byte_cursor *iv) {
if (s_validate_key_materials(key, AWS_AES_256_KEY_BYTE_LEN, iv, AWS_AES_256_CIPHER_BLOCK_SIZE) != AWS_OP_SUCCESS) {
return NULL;
}
return s_aes_ctr_new_fn(allocator, key, iv);
}

Expand All @@ -105,12 +129,19 @@ struct aws_symmetric_cipher *aws_aes_gcm_256_new(
const struct aws_byte_cursor *iv,
const struct aws_byte_cursor *aad,
const struct aws_byte_cursor *decryption_tag) {
if (s_validate_key_materials(key, AWS_AES_256_KEY_BYTE_LEN, iv, AWS_AES_256_CIPHER_BLOCK_SIZE - sizeof(uint32_t)) !=
AWS_OP_SUCCESS) {
return NULL;
}
return s_aes_gcm_new_fn(allocator, key, iv, aad, decryption_tag);
}

struct aws_symmetric_cipher *aws_aes_keywrap_256_new(
struct aws_allocator *allocator,
const struct aws_byte_cursor *key) {
if (s_validate_key_materials(key, AWS_AES_256_KEY_BYTE_LEN, NULL, 0) != AWS_OP_SUCCESS) {
return NULL;
}
return s_aes_keywrap_new_fn(allocator, key);
}

Expand All @@ -125,8 +156,8 @@ int aws_symmetric_cipher_encrypt(
struct aws_byte_cursor to_encrypt,
struct aws_byte_buf *out) {

if (AWS_UNLIKELY(!s_check_input_size_limits(cipher, &to_encrypt))) {
return aws_raise_error(AWS_ERROR_CAL_BUFFER_TOO_LARGE_FOR_ALGORITHM);
if (AWS_UNLIKELY(s_check_input_size_limits(cipher, &to_encrypt) != AWS_OP_SUCCESS)) {
return AWS_OP_ERR;
}

if (cipher->good) {
Expand All @@ -141,8 +172,8 @@ int aws_symmetric_cipher_decrypt(
struct aws_byte_cursor to_decrypt,
struct aws_byte_buf *out) {

if (AWS_UNLIKELY(!s_check_input_size_limits(cipher, &to_decrypt))) {
return aws_raise_error(AWS_ERROR_CAL_BUFFER_TOO_LARGE_FOR_ALGORITHM);
if (AWS_UNLIKELY(s_check_input_size_limits(cipher, &to_decrypt) != AWS_OP_SUCCESS)) {
return AWS_OP_ERR;
}

if (cipher->good) {
Expand Down
4 changes: 4 additions & 0 deletions tests/CMakeLists.txt
Expand Up @@ -78,10 +78,12 @@ add_test_case(aes_cbc_NIST_CBCVarTxt256_case_110)
add_test_case(aes_cbc_NIST_CBCMMT256_case_4)
add_test_case(aes_cbc_NIST_CBCMMT256_case_9)
add_test_case(aes_cbc_test_with_generated_key_iv)
add_test_case(aes_cbc_validate_materials_fails)
add_test_case(aes_ctr_RFC3686_Case_7)
add_test_case(aes_ctr_RFC3686_Case_8)
add_test_case(aes_ctr_RFC3686_Case_9)
add_test_case(aes_ctr_test_with_generated_key_iv)
add_test_case(aes_ctr_validate_materials_fails)
add_test_case(gcm_NIST_gcmEncryptExtIV256_PTLen_128_Test_0)
add_test_case(gcm_NIST_gcmEncryptExtIV256_PTLen_104_Test_3)
add_test_case(gcm_NIST_gcmEncryptExtIV256_PTLen_256_Test_6)
Expand All @@ -90,12 +92,14 @@ add_test_case(gcm_256_KAT_1)
add_test_case(gcm_256_KAT_2)
add_test_case(gcm_256_KAT_3)
add_test_case(gcm_test_with_generated_key_iv)
add_test_case(aes_gcm_validate_materials_fails)
add_test_case(aes_keywrap_RFC3394_256BitKey256CekTestVector)
add_test_case(aes_keywrap_Rfc3394_256BitKey_TestIntegrityCheckFailed)
add_test_case(aes_keywrap_RFC3394_256BitKeyTestBadPayload)
add_test_case(aes_keywrap_RFC3394_256BitKey128BitCekTestVector)
add_test_case(aes_keywrap_RFC3394_256BitKey128BitCekIntegrityCheckFailedTestVector)
add_test_case(aes_keywrap_RFC3394_256BitKey128BitCekPayloadCheckFailedTestVector)
add_test_case(aes_keywrap_validate_materials_fails)
add_test_case(aes_test_input_too_large)

add_test_case(der_encode_integer)
Expand Down
126 changes: 126 additions & 0 deletions tests/aes256_test.c
Expand Up @@ -258,6 +258,42 @@ static int s_aes_cbc_test_with_generated_key_iv_fn(struct aws_allocator *allocat
}
AWS_TEST_CASE(aes_cbc_test_with_generated_key_iv, s_aes_cbc_test_with_generated_key_iv_fn)

static int s_aes_cbc_validate_materials_fails_fn(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

uint8_t iv_too_small[AWS_AES_256_CIPHER_BLOCK_SIZE - 1] = {0};
uint8_t iv_too_large[AWS_AES_256_CIPHER_BLOCK_SIZE + 1] = {0};

uint8_t key_too_small[AWS_AES_256_KEY_BYTE_LEN - 1] = {0};
uint8_t key_too_large[AWS_AES_256_KEY_BYTE_LEN + 1] = {0};

uint8_t valid_key_size[AWS_AES_256_KEY_BYTE_LEN] = {0};
uint8_t valid_iv_size[AWS_AES_256_CIPHER_BLOCK_SIZE] = {0};

struct aws_byte_cursor key = aws_byte_cursor_from_array(valid_key_size, sizeof(valid_key_size));
struct aws_byte_cursor iv = aws_byte_cursor_from_array(iv_too_small, sizeof(iv_too_small));
ASSERT_NULL(aws_aes_cbc_256_new(allocator, &key, &iv));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_CIPHER_MATERIAL_SIZE_FOR_ALGORITHM, aws_last_error());

key = aws_byte_cursor_from_array(valid_key_size, sizeof(valid_key_size));
iv = aws_byte_cursor_from_array(iv_too_large, sizeof(iv_too_large));
ASSERT_NULL(aws_aes_cbc_256_new(allocator, &key, &iv));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_CIPHER_MATERIAL_SIZE_FOR_ALGORITHM, aws_last_error());

key = aws_byte_cursor_from_array(key_too_small, sizeof(key_too_small));
iv = aws_byte_cursor_from_array(valid_iv_size, sizeof(valid_iv_size));
ASSERT_NULL(aws_aes_cbc_256_new(allocator, &key, &iv));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM, aws_last_error());

key = aws_byte_cursor_from_array(key_too_small, sizeof(key_too_small));
iv = aws_byte_cursor_from_array(key_too_large, sizeof(key_too_large));
ASSERT_NULL(aws_aes_cbc_256_new(allocator, &key, &iv));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM, aws_last_error());

return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(aes_cbc_validate_materials_fails, s_aes_cbc_validate_materials_fails_fn)

static int s_check_single_block_ctr(
struct aws_allocator *allocator,
const struct aws_byte_cursor key,
Expand Down Expand Up @@ -461,6 +497,42 @@ static int s_aes_ctr_test_with_generated_key_iv_fn(struct aws_allocator *allocat
}
AWS_TEST_CASE(aes_ctr_test_with_generated_key_iv, s_aes_ctr_test_with_generated_key_iv_fn)

static int s_aes_ctr_validate_materials_fails_fn(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

uint8_t iv_too_small[AWS_AES_256_CIPHER_BLOCK_SIZE - 1] = {0};
uint8_t iv_too_large[AWS_AES_256_CIPHER_BLOCK_SIZE + 1] = {0};

uint8_t key_too_small[AWS_AES_256_KEY_BYTE_LEN - 1] = {0};
uint8_t key_too_large[AWS_AES_256_KEY_BYTE_LEN + 1] = {0};

uint8_t valid_key_size[AWS_AES_256_KEY_BYTE_LEN] = {0};
uint8_t valid_iv_size[AWS_AES_256_CIPHER_BLOCK_SIZE] = {0};

struct aws_byte_cursor key = aws_byte_cursor_from_array(valid_key_size, sizeof(valid_key_size));
struct aws_byte_cursor iv = aws_byte_cursor_from_array(iv_too_small, sizeof(iv_too_small));
ASSERT_NULL(aws_aes_ctr_256_new(allocator, &key, &iv));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_CIPHER_MATERIAL_SIZE_FOR_ALGORITHM, aws_last_error());

key = aws_byte_cursor_from_array(valid_key_size, sizeof(valid_key_size));
iv = aws_byte_cursor_from_array(iv_too_large, sizeof(iv_too_large));
ASSERT_NULL(aws_aes_ctr_256_new(allocator, &key, &iv));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_CIPHER_MATERIAL_SIZE_FOR_ALGORITHM, aws_last_error());

key = aws_byte_cursor_from_array(key_too_small, sizeof(key_too_small));
iv = aws_byte_cursor_from_array(valid_iv_size, sizeof(valid_iv_size));
ASSERT_NULL(aws_aes_ctr_256_new(allocator, &key, &iv));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM, aws_last_error());

key = aws_byte_cursor_from_array(key_too_small, sizeof(key_too_small));
iv = aws_byte_cursor_from_array(key_too_large, sizeof(key_too_large));
ASSERT_NULL(aws_aes_ctr_256_new(allocator, &key, &iv));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM, aws_last_error());

return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(aes_ctr_validate_materials_fails, s_aes_ctr_validate_materials_fails_fn)

static int s_check_multi_block_gcm(
struct aws_allocator *allocator,
const struct aws_byte_cursor key,
Expand Down Expand Up @@ -1011,6 +1083,42 @@ static int s_aes_gcm_test_with_generated_key_iv_fn(struct aws_allocator *allocat
}
AWS_TEST_CASE(gcm_test_with_generated_key_iv, s_aes_gcm_test_with_generated_key_iv_fn)

static int s_aes_gcm_validate_materials_fails_fn(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

uint8_t iv_too_small[AWS_AES_256_CIPHER_BLOCK_SIZE - 5] = {0};
uint8_t iv_too_large[AWS_AES_256_CIPHER_BLOCK_SIZE - 3] = {0};

uint8_t key_too_small[AWS_AES_256_KEY_BYTE_LEN - 1] = {0};
uint8_t key_too_large[AWS_AES_256_KEY_BYTE_LEN + 1] = {0};

uint8_t valid_key_size[AWS_AES_256_KEY_BYTE_LEN] = {0};
uint8_t valid_iv_size[AWS_AES_256_CIPHER_BLOCK_SIZE] = {0};

struct aws_byte_cursor key = aws_byte_cursor_from_array(valid_key_size, sizeof(valid_key_size));
struct aws_byte_cursor iv = aws_byte_cursor_from_array(iv_too_small, sizeof(iv_too_small));
ASSERT_NULL(aws_aes_gcm_256_new(allocator, &key, &iv, NULL, NULL));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_CIPHER_MATERIAL_SIZE_FOR_ALGORITHM, aws_last_error());

key = aws_byte_cursor_from_array(valid_key_size, sizeof(valid_key_size));
iv = aws_byte_cursor_from_array(iv_too_large, sizeof(iv_too_large));
ASSERT_NULL(aws_aes_gcm_256_new(allocator, &key, &iv, NULL, NULL));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_CIPHER_MATERIAL_SIZE_FOR_ALGORITHM, aws_last_error());

key = aws_byte_cursor_from_array(key_too_small, sizeof(key_too_small));
iv = aws_byte_cursor_from_array(valid_iv_size, sizeof(valid_iv_size));
ASSERT_NULL(aws_aes_gcm_256_new(allocator, &key, &iv, NULL, NULL));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM, aws_last_error());

key = aws_byte_cursor_from_array(key_too_small, sizeof(key_too_small));
iv = aws_byte_cursor_from_array(key_too_large, sizeof(key_too_large));
ASSERT_NULL(aws_aes_gcm_256_new(allocator, &key, &iv, NULL, NULL));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM, aws_last_error());

return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(aes_gcm_validate_materials_fails, s_aes_gcm_validate_materials_fails_fn)

static int s_test_aes_keywrap_RFC3394_256BitKey256CekTestVector(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

Expand Down Expand Up @@ -1299,6 +1407,24 @@ AWS_TEST_CASE(
aes_keywrap_RFC3394_256BitKey128BitCekPayloadCheckFailedTestVector,
s_test_RFC3394_256BitKey128BitCekPayloadCheckFailedTestVector);

static int s_aes_keywrap_validate_materials_fails_fn(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

uint8_t key_too_small[AWS_AES_256_KEY_BYTE_LEN - 1] = {0};
uint8_t key_too_large[AWS_AES_256_KEY_BYTE_LEN + 1] = {0};

struct aws_byte_cursor key = aws_byte_cursor_from_array(key_too_small, sizeof(key_too_small));
ASSERT_NULL(aws_aes_keywrap_256_new(allocator, &key));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM, aws_last_error());

key = aws_byte_cursor_from_array(key_too_large, sizeof(key_too_large));
ASSERT_NULL(aws_aes_keywrap_256_new(allocator, &key));
ASSERT_UINT_EQUALS(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM, aws_last_error());

return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(aes_keywrap_validate_materials_fails, s_aes_keywrap_validate_materials_fails_fn)

static int s_test_input_too_large_fn(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

Expand Down

0 comments on commit d6332a8

Please sign in to comment.