aws/aws-encryption-sdk-c

Split aws_cryptosdk_hdr_parse into smaller functions

alex-chew opened this issue · 0 comments

The aws_cryptosdk_hdr_parse function is quite long, making it hard to read/understand/verify. We should split it into smaller functions.

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
}