/* * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use * this file except in compliance with the License. A copy of the License is * located at * * http://aws.amazon.com/apache2.0/ * * or in the "license" file accompanying this file. This file is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing permissions and * limitations under the License. */ #include #include bool aws_cryptosdk_keyring_trace_is_valid(const struct aws_array_list *trace) { if (trace == NULL) { return false; } AWS_FATAL_PRECONDITION(trace->item_size == sizeof(struct aws_cryptosdk_keyring_trace_record)); if (!aws_array_list_is_valid(trace)) { return false; } /* iterate over each record in the list */ struct aws_cryptosdk_keyring_trace_record *data = (struct aws_cryptosdk_keyring_trace_record *)trace->data; for (size_t i = 0; i < trace->length; ++i) { if (!aws_cryptosdk_keyring_trace_record_is_valid(&(data[i]))) { return false; } } return true; } bool aws_cryptosdk_keyring_trace_record_is_valid(struct aws_cryptosdk_keyring_trace_record *record) { if (record == NULL) { return false; } bool wk_namespace_is_valid = (record->wrapping_key_namespace != NULL); bool wk_name_is_valid = (record->wrapping_key_name != NULL); bool record_readable = AWS_OBJECT_PTR_IS_READABLE(record); return wk_namespace_is_valid && wk_name_is_valid && record_readable; } void aws_cryptosdk_keyring_trace_record_clean_up(struct aws_cryptosdk_keyring_trace_record *record) { AWS_FATAL_PRECONDITION(record != NULL); // AWS_FATAL_PRECONDITION(record->wrapping_key_name != NULL); // AWS_FATAL_PRECONDITION(record->wrapping_key_namespace != NULL); aws_string_destroy(record->wrapping_key_namespace); aws_string_destroy(record->wrapping_key_name); record->flags = 0; record->wrapping_key_namespace = record->wrapping_key_name = NULL; AWS_POSTCONDITION(record->flags == 0); AWS_POSTCONDITION(record->wrapping_key_name == NULL); AWS_POSTCONDITION(record->wrapping_key_namespace == NULL); } static inline int record_init_check(struct aws_cryptosdk_keyring_trace_record *record) { if (record->wrapping_key_namespace && record->wrapping_key_name) { return AWS_OP_SUCCESS; } aws_cryptosdk_keyring_trace_record_clean_up(record); return AWS_OP_ERR; } static int record_init_from_c_strs( struct aws_allocator *alloc, struct aws_cryptosdk_keyring_trace_record *record, const char *wk_namespace, const char *wk_name, uint32_t flags) { record->flags = flags; record->wrapping_key_namespace = aws_string_new_from_c_str(alloc, wk_namespace); record->wrapping_key_name = aws_string_new_from_c_str(alloc, wk_name); return record_init_check(record); } static int record_init_from_strings( struct aws_allocator *alloc, struct aws_cryptosdk_keyring_trace_record *record, const struct aws_string *wk_namespace, const struct aws_string *wk_name, uint32_t flags) { record->flags = flags; record->wrapping_key_namespace = aws_cryptosdk_string_dup(alloc, wk_namespace); record->wrapping_key_name = aws_cryptosdk_string_dup(alloc, wk_name); return record_init_check(record); } static int record_init_from_bufs( struct aws_allocator *alloc, struct aws_cryptosdk_keyring_trace_record *record, const struct aws_byte_buf *wk_namespace, const struct aws_byte_buf *wk_name, uint32_t flags) { record->flags = flags; record->wrapping_key_namespace = aws_string_new_from_array(alloc, wk_namespace->buffer, wk_namespace->len); record->wrapping_key_name = aws_string_new_from_array(alloc, wk_name->buffer, wk_name->len); return record_init_check(record); } static inline int push_record_onto_trace( struct aws_array_list *trace, struct aws_cryptosdk_keyring_trace_record *record) { int ret = aws_array_list_push_back(trace, (void *)record); if (ret) aws_cryptosdk_keyring_trace_record_clean_up(record); // TODO: check for post-condition aws_cryptosdk_keyring_trace_is_valid(trace) return ret; } int aws_cryptosdk_keyring_trace_add_record( struct aws_allocator *alloc, struct aws_array_list *trace, const struct aws_string *wk_namespace, const struct aws_string *wk_name, uint32_t flags) { aws_allocator_is_valid(alloc); AWS_FATAL_PRECONDITION(trace != NULL); AWS_FATAL_PRECONDITION(aws_string_is_valid(wk_namespace)); AWS_FATAL_PRECONDITION(aws_string_is_valid(wk_name)); AWS_FATAL_PRECONDITION(aws_cryptosdk_keyring_trace_is_valid(trace)); AWS_FATAL_PRECONDITION(trace->item_size == sizeof(struct aws_cryptosdk_keyring_trace_record)); struct aws_cryptosdk_keyring_trace_record record; int ret = record_init_from_strings(alloc, &record, wk_namespace, wk_name, flags); if (ret) return ret; return push_record_onto_trace(trace, &record); } int aws_cryptosdk_keyring_trace_add_record_c_str( struct aws_allocator *alloc, struct aws_array_list *trace, const char *wk_namespace, const char *wk_name, uint32_t flags) { aws_allocator_is_valid(alloc); AWS_FATAL_PRECONDITION(trace != NULL); AWS_FATAL_PRECONDITION(aws_c_string_is_valid(wk_namespace)); AWS_FATAL_PRECONDITION(aws_c_string_is_valid(wk_name)); AWS_FATAL_PRECONDITION(aws_cryptosdk_keyring_trace_is_valid(trace)); AWS_FATAL_PRECONDITION(trace->item_size == sizeof(struct aws_cryptosdk_keyring_trace_record)); struct aws_cryptosdk_keyring_trace_record record; int ret = record_init_from_c_strs(alloc, &record, wk_namespace, wk_name, flags); if (ret) return ret; return push_record_onto_trace(trace, &record); } int aws_cryptosdk_keyring_trace_add_record_buf( struct aws_allocator *alloc, struct aws_array_list *trace, const struct aws_byte_buf *wk_namespace, const struct aws_byte_buf *wk_name, uint32_t flags) { aws_allocator_is_valid(alloc); AWS_FATAL_PRECONDITION(trace != NULL); AWS_FATAL_PRECONDITION(wk_namespace != NULL); AWS_FATAL_PRECONDITION(wk_name != NULL); AWS_FATAL_PRECONDITION(aws_byte_buf_is_valid(wk_namespace)); AWS_FATAL_PRECONDITION(aws_byte_buf_is_valid(wk_name)); AWS_FATAL_PRECONDITION(aws_cryptosdk_keyring_trace_is_valid(trace)); AWS_FATAL_PRECONDITION(trace->item_size == sizeof(struct aws_cryptosdk_keyring_trace_record)); struct aws_cryptosdk_keyring_trace_record record; int ret = record_init_from_bufs(alloc, &record, wk_namespace, wk_name, flags); if (ret) return ret; return push_record_onto_trace(trace, &record); } int aws_cryptosdk_keyring_trace_init(struct aws_allocator *alloc, struct aws_array_list *trace) { // arbitrary starting point, list will resize as necessary AWS_FATAL_PRECONDITION(trace != NULL); aws_allocator_is_valid(alloc); const int initial_size = 10; int r_val = aws_array_list_init_dynamic(trace, alloc, initial_size, sizeof(struct aws_cryptosdk_keyring_trace_record)); if (r_val == AWS_OP_SUCCESS) { AWS_POSTCONDITION(aws_array_list_is_valid(trace)); AWS_POSTCONDITION(trace->alloc == alloc); AWS_POSTCONDITION(trace->item_size == sizeof(struct aws_cryptosdk_keyring_trace_record)); AWS_POSTCONDITION(trace->length == 0); } return r_val; } int aws_cryptosdk_keyring_trace_record_init_clone( struct aws_allocator *alloc, struct aws_cryptosdk_keyring_trace_record *dest, const struct aws_cryptosdk_keyring_trace_record *src) { aws_allocator_is_valid(alloc); AWS_FATAL_PRECONDITION(dest != NULL); AWS_FATAL_PRECONDITION(src != NULL); AWS_FATAL_PRECONDITION(aws_string_is_valid(src->wrapping_key_namespace)); AWS_FATAL_PRECONDITION(aws_string_is_valid(src->wrapping_key_name)); dest->wrapping_key_namespace = aws_cryptosdk_string_dup(alloc, src->wrapping_key_namespace); dest->wrapping_key_name = aws_cryptosdk_string_dup(alloc, src->wrapping_key_name); if (record_init_check(dest)) { aws_cryptosdk_keyring_trace_record_clean_up(dest); AWS_POSTCONDITION(dest->flags == 0); AWS_POSTCONDITION(dest->wrapping_key_name == NULL); AWS_POSTCONDITION(dest->wrapping_key_namespace == NULL); return AWS_OP_ERR; } dest->flags = src->flags; AWS_POSTCONDITION(aws_string_eq(src->wrapping_key_namespace, dest->wrapping_key_namespace)); AWS_POSTCONDITION(aws_string_eq(src->wrapping_key_name, dest->wrapping_key_name)); AWS_POSTCONDITION(src->flags == dest->flags); return AWS_OP_SUCCESS; } static bool aws_cryptosdk_keyring_trace_record_eq( const struct aws_cryptosdk_keyring_trace_record *a, const struct aws_cryptosdk_keyring_trace_record *b) { return a->flags == b->flags && aws_string_eq(a->wrapping_key_namespace, b->wrapping_key_namespace) && aws_string_eq(a->wrapping_key_name, b->wrapping_key_name); } bool aws_cryptosdk_keyring_trace_eq(const struct aws_array_list *a, const struct aws_array_list *b) { AWS_FATAL_PRECONDITION(aws_cryptosdk_keyring_trace_is_valid(a)); AWS_FATAL_PRECONDITION(aws_cryptosdk_keyring_trace_is_valid(b)); size_t num_records = aws_array_list_length(a); if (num_records != aws_array_list_length(b)) return false; struct aws_cryptosdk_keyring_trace_record *a_rec; struct aws_cryptosdk_keyring_trace_record *b_rec; for (size_t idx = 0; idx < num_records; ++idx) { if (aws_array_list_get_at_ptr(a, (void **)&a_rec, idx) || aws_array_list_get_at_ptr(b, (void **)&b_rec, idx)) { abort(); } if (!aws_cryptosdk_keyring_trace_record_eq(a_rec, b_rec)) return false; } return true; } void aws_cryptosdk_keyring_trace_clear(struct aws_array_list *trace) { AWS_FATAL_PRECONDITION(aws_cryptosdk_keyring_trace_is_valid(trace)); AWS_FATAL_PRECONDITION(trace->item_size == sizeof(struct aws_cryptosdk_keyring_trace_record)); size_t num_records = aws_array_list_length(trace); for (size_t idx = 0; idx < num_records; ++idx) { struct aws_cryptosdk_keyring_trace_record *record; if (!aws_array_list_get_at_ptr(trace, (void **)&record, idx)) { aws_cryptosdk_keyring_trace_record_clean_up(record); } } aws_array_list_clear(trace); } void aws_cryptosdk_keyring_trace_clean_up(struct aws_array_list *trace) { AWS_FATAL_PRECONDITION(aws_cryptosdk_keyring_trace_is_valid(trace)); AWS_FATAL_PRECONDITION(trace->item_size == sizeof(struct aws_cryptosdk_keyring_trace_record)); aws_cryptosdk_keyring_trace_clear(trace); aws_array_list_clean_up(trace); }