int aws_cryptosdk_hdr_write()

in source/header.c [479:575]


int aws_cryptosdk_hdr_write(
    const struct aws_cryptosdk_hdr *hdr, size_t *bytes_written, uint8_t *outbuf, size_t outlen) {
    AWS_PRECONDITION(aws_cryptosdk_hdr_is_valid(hdr));
    AWS_PRECONDITION(hdr->iv.len <= UINT8_MAX);  // uint8_t max value
    AWS_PRECONDITION(outlen == 0 || AWS_MEM_IS_READABLE(outbuf, outlen));
    AWS_PRECONDITION(bytes_written != NULL);
    struct aws_byte_buf output = aws_byte_buf_from_array(outbuf, outlen);
    output.len                 = 0;

    const struct aws_cryptosdk_alg_properties *alg_props = aws_cryptosdk_alg_props(hdr->alg_id);
    if (!alg_props) goto INVALID_HEADER;
    enum aws_cryptosdk_hdr_version header_version = alg_props->msg_format_version;

    if (!aws_byte_buf_write_u8(&output, header_version)) goto WRITE_ERR;
    if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
        if (!aws_byte_buf_write_u8(&output, AWS_CRYPTOSDK_HEADER_TYPE_CUSTOMER_AED)) goto WRITE_ERR;
    }
    if (!aws_byte_buf_write_be16(&output, hdr->alg_id)) goto WRITE_ERR;
    if (!aws_byte_buf_write_from_whole_cursor(
            &output, aws_byte_cursor_from_array(hdr->message_id.buffer, hdr->message_id.len)))
        goto WRITE_ERR;

    // TODO - unify everything on byte_bufs when the aws-c-common refactor lands
    // See: https://github.com/awslabs/aws-c-common/pull/130
    struct aws_byte_buf aad_length_field;
    init_aws_byte_buf_raw(&aad_length_field);

    if (!aws_byte_buf_advance(&output, &aad_length_field, 2)) goto WRITE_ERR;

    size_t old_len = output.len;
    if (aws_cryptosdk_enc_ctx_serialize(aws_default_allocator(), &output, &hdr->enc_ctx)) goto WRITE_ERR;

    if (!aws_byte_buf_write_be16(&aad_length_field, (uint16_t)(output.len - old_len))) goto WRITE_ERR;

    size_t edk_count = aws_array_list_length(&hdr->edk_list);
    if (!aws_byte_buf_write_be16(&output, (uint16_t)edk_count)) goto WRITE_ERR;

    for (size_t idx = 0; idx < edk_count; ++idx) {
        void *vp_edk = NULL;

        aws_array_list_get_at_ptr(&hdr->edk_list, &vp_edk, idx);
        assert(vp_edk);

        const struct aws_cryptosdk_edk *edk = vp_edk;

        if (!aws_byte_buf_write_be16(&output, (uint16_t)edk->provider_id.len)) goto WRITE_ERR;
        if (!aws_byte_buf_write_from_whole_cursor(
                &output, aws_byte_cursor_from_array(edk->provider_id.buffer, edk->provider_id.len)))
            goto WRITE_ERR;

        if (!aws_byte_buf_write_be16(&output, (uint16_t)edk->provider_info.len)) goto WRITE_ERR;
        if (!aws_byte_buf_write_from_whole_cursor(
                &output, aws_byte_cursor_from_array(edk->provider_info.buffer, edk->provider_info.len)))
            goto WRITE_ERR;

        if (!aws_byte_buf_write_be16(&output, (uint16_t)edk->ciphertext.len)) goto WRITE_ERR;
        if (!aws_byte_buf_write_from_whole_cursor(
                &output, aws_byte_cursor_from_array(edk->ciphertext.buffer, edk->ciphertext.len)))
            goto WRITE_ERR;
    }

    if (!aws_byte_buf_write_u8(
            &output, hdr->frame_len ? AWS_CRYPTOSDK_HEADER_CTYPE_FRAMED : AWS_CRYPTOSDK_HEADER_CTYPE_NONFRAMED))
        goto WRITE_ERR;

    if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
        if (!aws_byte_buf_write(&output, zero.bytes, 4)) goto WRITE_ERR;  // v01 reserved field
        if (!aws_byte_buf_write_u8(&output, (uint8_t)hdr->iv.len)) goto WRITE_ERR;
    }

    if (!aws_byte_buf_write_be32(&output, hdr->frame_len)) goto WRITE_ERR;

    if (!aws_byte_buf_write_from_whole_cursor(
            &output, aws_byte_cursor_from_array(hdr->alg_suite_data.buffer, hdr->alg_suite_data.len)))
        goto WRITE_ERR;

    if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
        if (!aws_byte_buf_write_from_whole_cursor(&output, aws_byte_cursor_from_array(hdr->iv.buffer, hdr->iv.len)))
            goto WRITE_ERR;
    }
    if (!aws_byte_buf_write_from_whole_cursor(
            &output, aws_byte_cursor_from_array(hdr->auth_tag.buffer, hdr->auth_tag.len)))
        goto WRITE_ERR;

    *bytes_written = output.len;
    return AWS_OP_SUCCESS;

INVALID_HEADER:
    aws_secure_zero(outbuf, outlen);
    *bytes_written = 0;
    return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_STATE);

WRITE_ERR:
    aws_secure_zero(outbuf, outlen);
    *bytes_written = 0;
    return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
}