Split aws_cryptosdk_hdr_parse into smaller functions
alex-chew opened this issue · 0 comments
alex-chew commented
The aws_cryptosdk_hdr_parse
function is quite long, making it hard to read/understand/verify. We should split it into smaller functions.
aws-encryption-sdk-c/source/header.c
Lines 189 to 302 in f74405c
int aws_cryptosdk_hdr_parse(struct aws_cryptosdk_hdr *hdr, struct aws_byte_cursor *pcursor) { | |
struct aws_byte_cursor cur = *pcursor; | |
aws_cryptosdk_hdr_clear(hdr); | |
uint8_t header_version; | |
if (!aws_byte_cursor_read_u8(&cur, &header_version)) goto SHORT_BUF; | |
if (aws_cryptosdk_unlikely(!aws_cryptosdk_header_version_is_known(header_version))) goto PARSE_ERR; | |
if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) { | |
uint8_t message_type; | |
if (!aws_byte_cursor_read_u8(&cur, &message_type)) goto SHORT_BUF; | |
if (aws_cryptosdk_unlikely(message_type != AWS_CRYPTOSDK_HEADER_TYPE_CUSTOMER_AED)) goto PARSE_ERR; | |
} | |
uint16_t alg_id; | |
if (!aws_byte_cursor_read_be16(&cur, &alg_id)) goto SHORT_BUF; | |
if (aws_cryptosdk_unlikely(!aws_cryptosdk_algorithm_is_known(alg_id))) goto PARSE_ERR; | |
const struct aws_cryptosdk_alg_properties *alg_props = aws_cryptosdk_alg_props(alg_id); | |
// Prevent header format confusion in case it's inconsistent with alg ID | |
if (aws_cryptosdk_unlikely(alg_props->msg_format_version != header_version)) goto PARSE_ERR; | |
hdr->alg_id = alg_id; | |
size_t message_id_len = aws_cryptosdk_private_algorithm_message_id_len(alg_props); | |
if (aws_byte_buf_init(&hdr->message_id, hdr->alloc, message_id_len)) goto MEM_ERR; | |
if (!aws_byte_cursor_read_and_fill_buffer(&cur, &hdr->message_id)) goto SHORT_BUF; | |
uint16_t aad_len; | |
if (!aws_byte_cursor_read_be16(&cur, &aad_len)) goto SHORT_BUF; | |
if (aad_len) { | |
struct aws_byte_cursor aad = aws_byte_cursor_advance_nospec(&cur, aad_len); | |
// Note that, even if this fails with SHORT_BUF, we report a parse error, since we know we | |
// have enough data (according to the aad length field). | |
if (aws_cryptosdk_enc_ctx_deserialize(hdr->alloc, &hdr->enc_ctx, &aad)) goto PARSE_ERR; | |
if (aad.len) { | |
// trailing garbage after the aad block | |
goto PARSE_ERR; | |
} | |
} | |
uint16_t edk_count; | |
if (!aws_byte_cursor_read_be16(&cur, &edk_count)) goto SHORT_BUF; | |
if (!edk_count) goto PARSE_ERR; | |
for (uint16_t i = 0; i < edk_count; ++i) { | |
struct aws_cryptosdk_edk edk; | |
if (parse_edk(hdr->alloc, &edk, &cur)) { | |
goto RETHROW; | |
} | |
aws_array_list_push_back(&hdr->edk_list, &edk); | |
} | |
uint8_t content_type; | |
if (!aws_byte_cursor_read_u8(&cur, &content_type)) goto SHORT_BUF; | |
if (aws_cryptosdk_unlikely(!is_known_type(content_type))) goto PARSE_ERR; | |
uint32_t reserved; // must be zero | |
uint8_t iv_len; | |
if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) { | |
if (!aws_byte_cursor_read_be32(&cur, &reserved)) goto SHORT_BUF; | |
if (reserved) goto PARSE_ERR; | |
if (!aws_byte_cursor_read_u8(&cur, &iv_len)) goto SHORT_BUF; | |
if (iv_len != aws_cryptosdk_private_algorithm_ivlen(alg_id)) goto PARSE_ERR; | |
} | |
uint32_t frame_len; | |
if (!aws_byte_cursor_read_be32(&cur, &frame_len)) goto SHORT_BUF; | |
if ((content_type == AWS_CRYPTOSDK_HEADER_CTYPE_NONFRAMED && frame_len != 0) || | |
(content_type == AWS_CRYPTOSDK_HEADER_CTYPE_FRAMED && frame_len == 0)) | |
goto PARSE_ERR; | |
hdr->frame_len = frame_len; | |
if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_2_0) { | |
const struct aws_cryptosdk_alg_properties *alg_props = aws_cryptosdk_alg_props(alg_id); | |
if (alg_props->alg_suite_data_len) { | |
if (aws_byte_buf_init(&hdr->alg_suite_data, hdr->alloc, alg_props->alg_suite_data_len)) goto MEM_ERR; | |
if (!aws_byte_cursor_read_and_fill_buffer(&cur, &hdr->alg_suite_data)) goto SHORT_BUF; | |
} | |
} | |
// cur.ptr now points to end of portion of header that is authenticated | |
hdr->auth_len = cur.ptr - pcursor->ptr; | |
if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) { | |
if (aws_byte_buf_init(&hdr->iv, hdr->alloc, iv_len)) goto MEM_ERR; | |
if (!aws_byte_cursor_read_and_fill_buffer(&cur, &hdr->iv)) goto SHORT_BUF; | |
} | |
size_t tag_len = aws_cryptosdk_private_algorithm_taglen(alg_id); | |
if (aws_byte_buf_init(&hdr->auth_tag, hdr->alloc, tag_len)) goto MEM_ERR; | |
if (!aws_byte_cursor_read_and_fill_buffer(&cur, &hdr->auth_tag)) goto SHORT_BUF; | |
*pcursor = cur; | |
return AWS_OP_SUCCESS; | |
SHORT_BUF: | |
aws_cryptosdk_hdr_clear(hdr); | |
return aws_raise_error(AWS_ERROR_SHORT_BUFFER); | |
PARSE_ERR: | |
aws_cryptosdk_hdr_clear(hdr); | |
return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_CIPHERTEXT); | |
MEM_ERR: | |
RETHROW: | |
aws_cryptosdk_hdr_clear(hdr); | |
return AWS_OP_ERR; // Error code will already have been raised in aws_mem_acquire | |
} |