diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/restricted/aws/s2n/stuffer | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/aws/s2n/stuffer')
-rw-r--r-- | contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c | 822 | ||||
-rw-r--r-- | contrib/restricted/aws/s2n/stuffer/s2n_stuffer.h | 338 | ||||
-rw-r--r-- | contrib/restricted/aws/s2n/stuffer/s2n_stuffer_base64.c | 418 | ||||
-rw-r--r-- | contrib/restricted/aws/s2n/stuffer/s2n_stuffer_file.c | 214 | ||||
-rw-r--r-- | contrib/restricted/aws/s2n/stuffer/s2n_stuffer_network_order.c | 394 | ||||
-rw-r--r-- | contrib/restricted/aws/s2n/stuffer/s2n_stuffer_pem.c | 342 | ||||
-rw-r--r-- | contrib/restricted/aws/s2n/stuffer/s2n_stuffer_text.c | 388 |
7 files changed, 1458 insertions, 1458 deletions
diff --git a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c index 04ced5b229..026a909850 100644 --- a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c +++ b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c @@ -1,411 +1,411 @@ -/* - * Copyright 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 <sys/param.h> - -#include "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" -#include "utils/s2n_mem.h" - -S2N_RESULT s2n_stuffer_validate(const struct s2n_stuffer* stuffer) -{ - /** - * Note that we do not assert any properties on the alloced, growable, and tainted fields, - * as all possible combinations of boolean values in those fields are valid. - */ - ENSURE_REF(stuffer); - GUARD_RESULT(s2n_blob_validate(&stuffer->blob)); - - /* <= is valid because we can have a fully written/read stuffer */ - DEBUG_ENSURE(stuffer->high_water_mark <= stuffer->blob.size, S2N_ERR_SAFETY); - DEBUG_ENSURE(stuffer->write_cursor <= stuffer->high_water_mark, S2N_ERR_SAFETY); - DEBUG_ENSURE(stuffer->read_cursor <= stuffer->write_cursor, S2N_ERR_SAFETY); - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_stuffer_reservation_validate(const struct s2n_stuffer_reservation* reservation) -{ - /** - * Note that we need two dereferences here to decrease proof complexity - * for CBMC (see https://github.com/awslabs/s2n/issues/2290). We can roll back - * this change once CBMC can handle common subexpression elimination. - */ - ENSURE_REF(reservation); - const struct s2n_stuffer_reservation reserve_obj = *reservation; - GUARD_RESULT(s2n_stuffer_validate(reserve_obj.stuffer)); - const struct s2n_stuffer stuffer_obj = *(reserve_obj.stuffer); - ENSURE(stuffer_obj.blob.size >= reserve_obj.length, S2N_ERR_SAFETY); - - if (reserve_obj.length > 0) { - ENSURE(reserve_obj.write_cursor < stuffer_obj.write_cursor, S2N_ERR_SAFETY); - ENSURE( - S2N_MEM_IS_WRITABLE(stuffer_obj.blob.data + reserve_obj.write_cursor, reserve_obj.length), - S2N_ERR_SAFETY - ); - } - - return S2N_RESULT_OK; -} - -int s2n_stuffer_init(struct s2n_stuffer *stuffer, struct s2n_blob *in) -{ - ENSURE_POSIX_MUT(stuffer); - PRECONDITION_POSIX(s2n_blob_validate(in)); - stuffer->blob = *in; - stuffer->read_cursor = 0; - stuffer->write_cursor = 0; - stuffer->high_water_mark = 0; - stuffer->alloced = 0; - stuffer->growable = 0; - stuffer->tainted = 0; - return S2N_SUCCESS; -} - -int s2n_stuffer_alloc(struct s2n_stuffer *stuffer, const uint32_t size) -{ - notnull_check(stuffer); - *stuffer = (struct s2n_stuffer) {0}; - GUARD(s2n_alloc(&stuffer->blob, size)); - GUARD(s2n_stuffer_init(stuffer, &stuffer->blob)); - - stuffer->alloced = 1; - - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_growable_alloc(struct s2n_stuffer *stuffer, const uint32_t size) -{ - GUARD(s2n_stuffer_alloc(stuffer, size)); - - stuffer->growable = 1; - - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_free(struct s2n_stuffer *stuffer) -{ - if (stuffer != NULL) { - if (stuffer->alloced) { - GUARD(s2n_free(&stuffer->blob)); - } - *stuffer = (struct s2n_stuffer) {0}; - } - return S2N_SUCCESS; -} - -int s2n_stuffer_resize(struct s2n_stuffer *stuffer, const uint32_t size) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - ENSURE_POSIX(!stuffer->tainted, S2N_ERR_RESIZE_TAINTED_STUFFER); - ENSURE_POSIX(stuffer->growable, S2N_ERR_RESIZE_STATIC_STUFFER); - - if (size == stuffer->blob.size) { - return S2N_SUCCESS; - } - - if (size == 0) { - s2n_stuffer_wipe(stuffer); - return s2n_free(&stuffer->blob); - } - - if (size < stuffer->blob.size) { - memset_check(stuffer->blob.data + size, S2N_WIPE_PATTERN, (stuffer->blob.size - size)); - if (stuffer->read_cursor > size) stuffer->read_cursor = size; - if (stuffer->write_cursor > size) stuffer->write_cursor = size; - if (stuffer->high_water_mark > size) stuffer->high_water_mark = size; - stuffer->blob.size = size; - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; - } - - GUARD(s2n_realloc(&stuffer->blob, size)); - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_resize_if_empty(struct s2n_stuffer *stuffer, const uint32_t size) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - if (stuffer->blob.data == NULL) { - ENSURE_POSIX(!stuffer->tainted, S2N_ERR_RESIZE_TAINTED_STUFFER); - ENSURE_POSIX(stuffer->growable, S2N_ERR_RESIZE_STATIC_STUFFER); - GUARD(s2n_realloc(&stuffer->blob, size)); - } - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_rewrite(struct s2n_stuffer *stuffer) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - stuffer->write_cursor = 0; - stuffer->read_cursor = 0; - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_rewind_read(struct s2n_stuffer *stuffer, const uint32_t size) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - ENSURE_POSIX(stuffer->read_cursor >= size, S2N_ERR_STUFFER_OUT_OF_DATA); - stuffer->read_cursor -= size; - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_reread(struct s2n_stuffer *stuffer) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - stuffer->read_cursor = 0; - return S2N_SUCCESS; -} - -int s2n_stuffer_wipe_n(struct s2n_stuffer *stuffer, const uint32_t size) -{ - if (size >= stuffer->write_cursor) { - return s2n_stuffer_wipe(stuffer); - } - - /* We know that size is now less than write_cursor */ - stuffer->write_cursor -= size; - memset_check(stuffer->blob.data + stuffer->write_cursor, S2N_WIPE_PATTERN, size); - stuffer->read_cursor = MIN(stuffer->read_cursor, stuffer->write_cursor); - - return S2N_SUCCESS; -} - -bool s2n_stuffer_is_consumed(struct s2n_stuffer *stuffer) { - return stuffer && (stuffer->read_cursor == stuffer->write_cursor); -} - -int s2n_stuffer_wipe(struct s2n_stuffer *stuffer) -{ - if (!s2n_stuffer_is_wiped(stuffer)) { - memset_check(stuffer->blob.data, S2N_WIPE_PATTERN, stuffer->high_water_mark); - } - - stuffer->tainted = 0; - stuffer->write_cursor = 0; - stuffer->read_cursor = 0; - stuffer->high_water_mark = 0; - return S2N_SUCCESS; -} - -int s2n_stuffer_skip_read(struct s2n_stuffer *stuffer, uint32_t n) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - S2N_ERROR_IF(s2n_stuffer_data_available(stuffer) < n, S2N_ERR_STUFFER_OUT_OF_DATA); - - stuffer->read_cursor += n; - return S2N_SUCCESS; -} - -void *s2n_stuffer_raw_read(struct s2n_stuffer *stuffer, uint32_t data_len) -{ - GUARD_PTR(s2n_stuffer_skip_read(stuffer, data_len)); - - stuffer->tainted = 1; - - return stuffer->blob.data + stuffer->read_cursor - data_len; -} - -int s2n_stuffer_read(struct s2n_stuffer *stuffer, struct s2n_blob *out) -{ - notnull_check(out); - - return s2n_stuffer_read_bytes(stuffer, out->data, out->size); -} - -int s2n_stuffer_erase_and_read(struct s2n_stuffer *stuffer, struct s2n_blob *out) -{ - GUARD(s2n_stuffer_skip_read(stuffer, out->size)); - - void *ptr = stuffer->blob.data + stuffer->read_cursor - out->size; - ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, out->size), S2N_ERR_NULL); - - memcpy_check(out->data, ptr, out->size); - memset_check(ptr, 0, out->size); - - return S2N_SUCCESS; -} - -int s2n_stuffer_read_bytes(struct s2n_stuffer *stuffer, uint8_t * data, uint32_t size) -{ - notnull_check(data); - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - GUARD(s2n_stuffer_skip_read(stuffer, size)); - notnull_check(stuffer->blob.data); - void *ptr = stuffer->blob.data + stuffer->read_cursor - size; - - memcpy_check(data, ptr, size); - - return S2N_SUCCESS; -} - -int s2n_stuffer_erase_and_read_bytes(struct s2n_stuffer *stuffer, uint8_t * data, uint32_t size) -{ - GUARD(s2n_stuffer_skip_read(stuffer, size)); - notnull_check(stuffer->blob.data); - void *ptr = stuffer->blob.data + stuffer->read_cursor - size; - - memcpy_check(data, ptr, size); - memset_check(ptr, 0, size); - - return S2N_SUCCESS; -} - -int s2n_stuffer_skip_write(struct s2n_stuffer *stuffer, const uint32_t n) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - GUARD(s2n_stuffer_reserve_space(stuffer, n)); - stuffer->write_cursor += n; - stuffer->high_water_mark = MAX(stuffer->write_cursor, stuffer->high_water_mark); - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -void *s2n_stuffer_raw_write(struct s2n_stuffer *stuffer, const uint32_t data_len) -{ - GUARD_PTR(s2n_stuffer_skip_write(stuffer, data_len)); - - stuffer->tainted = 1; - - return stuffer->blob.data + stuffer->write_cursor - data_len; -} - -int s2n_stuffer_write(struct s2n_stuffer *stuffer, const struct s2n_blob *in) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - PRECONDITION_POSIX(s2n_blob_validate(in)); - return s2n_stuffer_write_bytes(stuffer, in->data, in->size); -} - -int s2n_stuffer_write_bytes(struct s2n_stuffer *stuffer, const uint8_t * data, const uint32_t size) -{ - ENSURE_POSIX(S2N_MEM_IS_READABLE(data, size), S2N_ERR_SAFETY); - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - GUARD(s2n_stuffer_skip_write(stuffer, size)); - - void *ptr = stuffer->blob.data + stuffer->write_cursor - size; - ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, size), S2N_ERR_NULL); - - if (ptr == data) { - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; - } - - memcpy_check(ptr, data, size); - - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_writev_bytes(struct s2n_stuffer *stuffer, const struct iovec* iov, size_t iov_count, uint32_t offs, uint32_t size) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - notnull_check(iov); - void *ptr = s2n_stuffer_raw_write(stuffer, size); - ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, size), S2N_ERR_NULL); - - size_t size_left = size, to_skip = offs; - for (int i = 0; i < iov_count; i++) { - if (to_skip >= iov[i].iov_len) { - to_skip -= iov[i].iov_len; - continue; - } - size_t iov_len_op = iov[i].iov_len - to_skip; - ENSURE_POSIX(iov_len_op <= UINT32_MAX, S2N_FAILURE); - uint32_t iov_len = (uint32_t)iov_len_op; - uint32_t iov_size_to_take = MIN(size_left, iov_len); - notnull_check(iov[i].iov_base); - ENSURE_POSIX(to_skip < iov[i].iov_len, S2N_FAILURE); - memcpy_check(ptr, ((uint8_t*)(iov[i].iov_base)) + to_skip, iov_size_to_take); - size_left -= iov_size_to_take; - if (size_left == 0) { - break; - } - ptr = (void*)((uint8_t*)ptr + iov_size_to_take); - to_skip = 0; - } - - return S2N_SUCCESS; -} - -static int s2n_stuffer_copy_impl(struct s2n_stuffer *from, struct s2n_stuffer *to, const uint32_t len) -{ - GUARD(s2n_stuffer_skip_read(from, len)); - GUARD(s2n_stuffer_skip_write(to, len)); - - uint8_t *from_ptr = from->blob.data + from->read_cursor - len; - uint8_t *to_ptr = to->blob.data + to->write_cursor - len; - - memcpy_check(to_ptr, from_ptr, len); - - return S2N_SUCCESS; -} - -int s2n_stuffer_reserve_space(struct s2n_stuffer *stuffer, uint32_t n) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - if (s2n_stuffer_space_remaining(stuffer) < n) { - S2N_ERROR_IF(!stuffer->growable, S2N_ERR_STUFFER_IS_FULL); - /* Always grow a stuffer by at least 1k */ - const uint32_t growth = MAX(n - s2n_stuffer_space_remaining(stuffer), S2N_MIN_STUFFER_GROWTH_IN_BYTES); - uint32_t new_size = 0; - GUARD(s2n_add_overflow(stuffer->blob.size, growth, &new_size)); - GUARD(s2n_stuffer_resize(stuffer, new_size)); - } - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -/* Copies "len" bytes from "from" to "to". - * If the copy cannot succeed (i.e. there are either not enough bytes available, or there is not enough space to write them - * restore the old value of the stuffer */ -int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, const uint32_t len) -{ - const uint32_t orig_read_cursor = from->read_cursor; - const uint32_t orig_write_cursor = to->write_cursor; - - if (s2n_stuffer_copy_impl(from, to, len) < 0) { - from->read_cursor = orig_read_cursor; - to->write_cursor = orig_write_cursor; - S2N_ERROR_PRESERVE_ERRNO(); - } - - return S2N_SUCCESS; -} - -int s2n_stuffer_extract_blob(struct s2n_stuffer *stuffer, struct s2n_blob *out) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - notnull_check(out); - GUARD(s2n_realloc(out , s2n_stuffer_data_available(stuffer))); - - if (s2n_stuffer_data_available(stuffer) > 0) { - memcpy_check(out->data, - stuffer->blob.data + stuffer->read_cursor, - s2n_stuffer_data_available(stuffer)); - } - - POSTCONDITION_POSIX(s2n_blob_validate(out)); - return S2N_SUCCESS; -} +/* + * Copyright 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 <sys/param.h> + +#include "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_mem.h" + +S2N_RESULT s2n_stuffer_validate(const struct s2n_stuffer* stuffer) +{ + /** + * Note that we do not assert any properties on the alloced, growable, and tainted fields, + * as all possible combinations of boolean values in those fields are valid. + */ + ENSURE_REF(stuffer); + GUARD_RESULT(s2n_blob_validate(&stuffer->blob)); + + /* <= is valid because we can have a fully written/read stuffer */ + DEBUG_ENSURE(stuffer->high_water_mark <= stuffer->blob.size, S2N_ERR_SAFETY); + DEBUG_ENSURE(stuffer->write_cursor <= stuffer->high_water_mark, S2N_ERR_SAFETY); + DEBUG_ENSURE(stuffer->read_cursor <= stuffer->write_cursor, S2N_ERR_SAFETY); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_stuffer_reservation_validate(const struct s2n_stuffer_reservation* reservation) +{ + /** + * Note that we need two dereferences here to decrease proof complexity + * for CBMC (see https://github.com/awslabs/s2n/issues/2290). We can roll back + * this change once CBMC can handle common subexpression elimination. + */ + ENSURE_REF(reservation); + const struct s2n_stuffer_reservation reserve_obj = *reservation; + GUARD_RESULT(s2n_stuffer_validate(reserve_obj.stuffer)); + const struct s2n_stuffer stuffer_obj = *(reserve_obj.stuffer); + ENSURE(stuffer_obj.blob.size >= reserve_obj.length, S2N_ERR_SAFETY); + + if (reserve_obj.length > 0) { + ENSURE(reserve_obj.write_cursor < stuffer_obj.write_cursor, S2N_ERR_SAFETY); + ENSURE( + S2N_MEM_IS_WRITABLE(stuffer_obj.blob.data + reserve_obj.write_cursor, reserve_obj.length), + S2N_ERR_SAFETY + ); + } + + return S2N_RESULT_OK; +} + +int s2n_stuffer_init(struct s2n_stuffer *stuffer, struct s2n_blob *in) +{ + ENSURE_POSIX_MUT(stuffer); + PRECONDITION_POSIX(s2n_blob_validate(in)); + stuffer->blob = *in; + stuffer->read_cursor = 0; + stuffer->write_cursor = 0; + stuffer->high_water_mark = 0; + stuffer->alloced = 0; + stuffer->growable = 0; + stuffer->tainted = 0; + return S2N_SUCCESS; +} + +int s2n_stuffer_alloc(struct s2n_stuffer *stuffer, const uint32_t size) +{ + notnull_check(stuffer); + *stuffer = (struct s2n_stuffer) {0}; + GUARD(s2n_alloc(&stuffer->blob, size)); + GUARD(s2n_stuffer_init(stuffer, &stuffer->blob)); + + stuffer->alloced = 1; + + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_growable_alloc(struct s2n_stuffer *stuffer, const uint32_t size) +{ + GUARD(s2n_stuffer_alloc(stuffer, size)); + + stuffer->growable = 1; + + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_free(struct s2n_stuffer *stuffer) +{ + if (stuffer != NULL) { + if (stuffer->alloced) { + GUARD(s2n_free(&stuffer->blob)); + } + *stuffer = (struct s2n_stuffer) {0}; + } + return S2N_SUCCESS; +} + +int s2n_stuffer_resize(struct s2n_stuffer *stuffer, const uint32_t size) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + ENSURE_POSIX(!stuffer->tainted, S2N_ERR_RESIZE_TAINTED_STUFFER); + ENSURE_POSIX(stuffer->growable, S2N_ERR_RESIZE_STATIC_STUFFER); + + if (size == stuffer->blob.size) { + return S2N_SUCCESS; + } + + if (size == 0) { + s2n_stuffer_wipe(stuffer); + return s2n_free(&stuffer->blob); + } + + if (size < stuffer->blob.size) { + memset_check(stuffer->blob.data + size, S2N_WIPE_PATTERN, (stuffer->blob.size - size)); + if (stuffer->read_cursor > size) stuffer->read_cursor = size; + if (stuffer->write_cursor > size) stuffer->write_cursor = size; + if (stuffer->high_water_mark > size) stuffer->high_water_mark = size; + stuffer->blob.size = size; + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; + } + + GUARD(s2n_realloc(&stuffer->blob, size)); + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_resize_if_empty(struct s2n_stuffer *stuffer, const uint32_t size) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + if (stuffer->blob.data == NULL) { + ENSURE_POSIX(!stuffer->tainted, S2N_ERR_RESIZE_TAINTED_STUFFER); + ENSURE_POSIX(stuffer->growable, S2N_ERR_RESIZE_STATIC_STUFFER); + GUARD(s2n_realloc(&stuffer->blob, size)); + } + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_rewrite(struct s2n_stuffer *stuffer) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + stuffer->write_cursor = 0; + stuffer->read_cursor = 0; + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_rewind_read(struct s2n_stuffer *stuffer, const uint32_t size) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + ENSURE_POSIX(stuffer->read_cursor >= size, S2N_ERR_STUFFER_OUT_OF_DATA); + stuffer->read_cursor -= size; + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_reread(struct s2n_stuffer *stuffer) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + stuffer->read_cursor = 0; + return S2N_SUCCESS; +} + +int s2n_stuffer_wipe_n(struct s2n_stuffer *stuffer, const uint32_t size) +{ + if (size >= stuffer->write_cursor) { + return s2n_stuffer_wipe(stuffer); + } + + /* We know that size is now less than write_cursor */ + stuffer->write_cursor -= size; + memset_check(stuffer->blob.data + stuffer->write_cursor, S2N_WIPE_PATTERN, size); + stuffer->read_cursor = MIN(stuffer->read_cursor, stuffer->write_cursor); + + return S2N_SUCCESS; +} + +bool s2n_stuffer_is_consumed(struct s2n_stuffer *stuffer) { + return stuffer && (stuffer->read_cursor == stuffer->write_cursor); +} + +int s2n_stuffer_wipe(struct s2n_stuffer *stuffer) +{ + if (!s2n_stuffer_is_wiped(stuffer)) { + memset_check(stuffer->blob.data, S2N_WIPE_PATTERN, stuffer->high_water_mark); + } + + stuffer->tainted = 0; + stuffer->write_cursor = 0; + stuffer->read_cursor = 0; + stuffer->high_water_mark = 0; + return S2N_SUCCESS; +} + +int s2n_stuffer_skip_read(struct s2n_stuffer *stuffer, uint32_t n) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + S2N_ERROR_IF(s2n_stuffer_data_available(stuffer) < n, S2N_ERR_STUFFER_OUT_OF_DATA); + + stuffer->read_cursor += n; + return S2N_SUCCESS; +} + +void *s2n_stuffer_raw_read(struct s2n_stuffer *stuffer, uint32_t data_len) +{ + GUARD_PTR(s2n_stuffer_skip_read(stuffer, data_len)); + + stuffer->tainted = 1; + + return stuffer->blob.data + stuffer->read_cursor - data_len; +} + +int s2n_stuffer_read(struct s2n_stuffer *stuffer, struct s2n_blob *out) +{ + notnull_check(out); + + return s2n_stuffer_read_bytes(stuffer, out->data, out->size); +} + +int s2n_stuffer_erase_and_read(struct s2n_stuffer *stuffer, struct s2n_blob *out) +{ + GUARD(s2n_stuffer_skip_read(stuffer, out->size)); + + void *ptr = stuffer->blob.data + stuffer->read_cursor - out->size; + ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, out->size), S2N_ERR_NULL); + + memcpy_check(out->data, ptr, out->size); + memset_check(ptr, 0, out->size); + + return S2N_SUCCESS; +} + +int s2n_stuffer_read_bytes(struct s2n_stuffer *stuffer, uint8_t * data, uint32_t size) +{ + notnull_check(data); + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + GUARD(s2n_stuffer_skip_read(stuffer, size)); + notnull_check(stuffer->blob.data); + void *ptr = stuffer->blob.data + stuffer->read_cursor - size; + + memcpy_check(data, ptr, size); + + return S2N_SUCCESS; +} + +int s2n_stuffer_erase_and_read_bytes(struct s2n_stuffer *stuffer, uint8_t * data, uint32_t size) +{ + GUARD(s2n_stuffer_skip_read(stuffer, size)); + notnull_check(stuffer->blob.data); + void *ptr = stuffer->blob.data + stuffer->read_cursor - size; + + memcpy_check(data, ptr, size); + memset_check(ptr, 0, size); + + return S2N_SUCCESS; +} + +int s2n_stuffer_skip_write(struct s2n_stuffer *stuffer, const uint32_t n) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + GUARD(s2n_stuffer_reserve_space(stuffer, n)); + stuffer->write_cursor += n; + stuffer->high_water_mark = MAX(stuffer->write_cursor, stuffer->high_water_mark); + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +void *s2n_stuffer_raw_write(struct s2n_stuffer *stuffer, const uint32_t data_len) +{ + GUARD_PTR(s2n_stuffer_skip_write(stuffer, data_len)); + + stuffer->tainted = 1; + + return stuffer->blob.data + stuffer->write_cursor - data_len; +} + +int s2n_stuffer_write(struct s2n_stuffer *stuffer, const struct s2n_blob *in) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + PRECONDITION_POSIX(s2n_blob_validate(in)); + return s2n_stuffer_write_bytes(stuffer, in->data, in->size); +} + +int s2n_stuffer_write_bytes(struct s2n_stuffer *stuffer, const uint8_t * data, const uint32_t size) +{ + ENSURE_POSIX(S2N_MEM_IS_READABLE(data, size), S2N_ERR_SAFETY); + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + GUARD(s2n_stuffer_skip_write(stuffer, size)); + + void *ptr = stuffer->blob.data + stuffer->write_cursor - size; + ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, size), S2N_ERR_NULL); + + if (ptr == data) { + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; + } + + memcpy_check(ptr, data, size); + + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_writev_bytes(struct s2n_stuffer *stuffer, const struct iovec* iov, size_t iov_count, uint32_t offs, uint32_t size) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + notnull_check(iov); + void *ptr = s2n_stuffer_raw_write(stuffer, size); + ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, size), S2N_ERR_NULL); + + size_t size_left = size, to_skip = offs; + for (int i = 0; i < iov_count; i++) { + if (to_skip >= iov[i].iov_len) { + to_skip -= iov[i].iov_len; + continue; + } + size_t iov_len_op = iov[i].iov_len - to_skip; + ENSURE_POSIX(iov_len_op <= UINT32_MAX, S2N_FAILURE); + uint32_t iov_len = (uint32_t)iov_len_op; + uint32_t iov_size_to_take = MIN(size_left, iov_len); + notnull_check(iov[i].iov_base); + ENSURE_POSIX(to_skip < iov[i].iov_len, S2N_FAILURE); + memcpy_check(ptr, ((uint8_t*)(iov[i].iov_base)) + to_skip, iov_size_to_take); + size_left -= iov_size_to_take; + if (size_left == 0) { + break; + } + ptr = (void*)((uint8_t*)ptr + iov_size_to_take); + to_skip = 0; + } + + return S2N_SUCCESS; +} + +static int s2n_stuffer_copy_impl(struct s2n_stuffer *from, struct s2n_stuffer *to, const uint32_t len) +{ + GUARD(s2n_stuffer_skip_read(from, len)); + GUARD(s2n_stuffer_skip_write(to, len)); + + uint8_t *from_ptr = from->blob.data + from->read_cursor - len; + uint8_t *to_ptr = to->blob.data + to->write_cursor - len; + + memcpy_check(to_ptr, from_ptr, len); + + return S2N_SUCCESS; +} + +int s2n_stuffer_reserve_space(struct s2n_stuffer *stuffer, uint32_t n) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + if (s2n_stuffer_space_remaining(stuffer) < n) { + S2N_ERROR_IF(!stuffer->growable, S2N_ERR_STUFFER_IS_FULL); + /* Always grow a stuffer by at least 1k */ + const uint32_t growth = MAX(n - s2n_stuffer_space_remaining(stuffer), S2N_MIN_STUFFER_GROWTH_IN_BYTES); + uint32_t new_size = 0; + GUARD(s2n_add_overflow(stuffer->blob.size, growth, &new_size)); + GUARD(s2n_stuffer_resize(stuffer, new_size)); + } + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +/* Copies "len" bytes from "from" to "to". + * If the copy cannot succeed (i.e. there are either not enough bytes available, or there is not enough space to write them + * restore the old value of the stuffer */ +int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, const uint32_t len) +{ + const uint32_t orig_read_cursor = from->read_cursor; + const uint32_t orig_write_cursor = to->write_cursor; + + if (s2n_stuffer_copy_impl(from, to, len) < 0) { + from->read_cursor = orig_read_cursor; + to->write_cursor = orig_write_cursor; + S2N_ERROR_PRESERVE_ERRNO(); + } + + return S2N_SUCCESS; +} + +int s2n_stuffer_extract_blob(struct s2n_stuffer *stuffer, struct s2n_blob *out) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + notnull_check(out); + GUARD(s2n_realloc(out , s2n_stuffer_data_available(stuffer))); + + if (s2n_stuffer_data_available(stuffer) > 0) { + memcpy_check(out->data, + stuffer->blob.data + stuffer->read_cursor, + s2n_stuffer_data_available(stuffer)); + } + + POSTCONDITION_POSIX(s2n_blob_validate(out)); + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.h b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.h index c67e1c4a73..54154fd74c 100644 --- a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.h +++ b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.h @@ -1,169 +1,169 @@ -/* - * Copyright 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. - */ - -#pragma once - -#include <limits.h> -#include <stdint.h> -#include <stdlib.h> -#include <sys/uio.h> - -#include "utils/s2n_blob.h" -#include "utils/s2n_result.h" - -#define S2N_MIN_STUFFER_GROWTH_IN_BYTES 1024 - -/* Using a non-zero value - * (a) makes wiped data easy to see in the debugger - * (b) makes use of wiped data obvious since this is unlikely to be a valid bit pattern - */ -#define S2N_WIPE_PATTERN 'w' - -#define SIZEOF_IN_BITS( t ) (sizeof(t) * CHAR_BIT) - -#define SIZEOF_UINT24 3 - -struct s2n_stuffer { - /* The data for the s2n_stuffer */ - struct s2n_blob blob; - - /* Cursors to the current read/write position in the s2n_stuffer */ - uint32_t read_cursor; - uint32_t write_cursor; - uint32_t high_water_mark; - - /* Was this stuffer alloc()'d ? */ - unsigned int alloced:1; - - /* Is this stuffer growable? */ - unsigned int growable:1; - - /* Can this stuffer be safely resized? - * A growable stuffer can be temporarily tainted by a raw read/write, - * preventing it from resizing. */ - unsigned int tainted:1; -}; - -#define s2n_stuffer_data_available( s ) ((s)->write_cursor - (s)->read_cursor) -#define s2n_stuffer_space_remaining( s ) ((s)->blob.size - (s)->write_cursor) -#define s2n_stuffer_is_wiped( s ) ((s)->high_water_mark == 0) -/* Check basic validity constraints on the stuffer: e.g. that cursors point within the blob */ -extern S2N_RESULT s2n_stuffer_validate(const struct s2n_stuffer* stuffer); - -/* Initialize and destroying stuffers */ -extern int s2n_stuffer_init(struct s2n_stuffer *stuffer, struct s2n_blob *in); -extern int s2n_stuffer_alloc(struct s2n_stuffer *stuffer, const uint32_t size); -extern int s2n_stuffer_growable_alloc(struct s2n_stuffer *stuffer, const uint32_t size); -extern int s2n_stuffer_free(struct s2n_stuffer *stuffer); -extern int s2n_stuffer_resize(struct s2n_stuffer *stuffer, const uint32_t size); -extern int s2n_stuffer_resize_if_empty(struct s2n_stuffer *stuffer, const uint32_t size); -extern int s2n_stuffer_rewind_read(struct s2n_stuffer *stuffer, const uint32_t size); -extern int s2n_stuffer_reread(struct s2n_stuffer *stuffer); -extern int s2n_stuffer_rewrite(struct s2n_stuffer *stuffer); -extern int s2n_stuffer_wipe(struct s2n_stuffer *stuffer); -extern int s2n_stuffer_wipe_n(struct s2n_stuffer *stuffer, const uint32_t n); -extern bool s2n_stuffer_is_consumed(struct s2n_stuffer *stuffer); - -/* Basic read and write */ -extern int s2n_stuffer_read(struct s2n_stuffer *stuffer, struct s2n_blob *out); -extern int s2n_stuffer_erase_and_read(struct s2n_stuffer *stuffer, struct s2n_blob *out); -extern int s2n_stuffer_write(struct s2n_stuffer *stuffer, const struct s2n_blob *in); -extern int s2n_stuffer_read_bytes(struct s2n_stuffer *stuffer, uint8_t * out, uint32_t n); -extern int s2n_stuffer_erase_and_read_bytes(struct s2n_stuffer *stuffer, uint8_t * data, uint32_t size); -extern int s2n_stuffer_write_bytes(struct s2n_stuffer *stuffer, const uint8_t * in, const uint32_t n); -extern int s2n_stuffer_writev_bytes(struct s2n_stuffer *stuffer, const struct iovec* iov, size_t iov_count, uint32_t offs, uint32_t size); -extern int s2n_stuffer_skip_read(struct s2n_stuffer *stuffer, uint32_t n); -extern int s2n_stuffer_skip_write(struct s2n_stuffer *stuffer, const uint32_t n); - -/* Tries to reserve enough space to write n additional bytes into the stuffer.*/ -extern int s2n_stuffer_reserve_space(struct s2n_stuffer *stuffer, uint32_t n); - -/* Raw read/write move the cursor along and give you a pointer you can - * read/write data_len bytes from/to in-place. - */ -extern void *s2n_stuffer_raw_write(struct s2n_stuffer *stuffer, const uint32_t data_len); -extern void *s2n_stuffer_raw_read(struct s2n_stuffer *stuffer, uint32_t data_len); - -/* Send/receive stuffer to/from a file descriptor */ -extern int s2n_stuffer_recv_from_fd(struct s2n_stuffer *stuffer, const int rfd, const uint32_t len, uint32_t *bytes_written); -extern int s2n_stuffer_send_to_fd(struct s2n_stuffer *stuffer, const int wfd, const uint32_t len, uint32_t *bytes_sent); - -/* Read and write integers in network order */ -extern int s2n_stuffer_read_uint8(struct s2n_stuffer *stuffer, uint8_t * u); -extern int s2n_stuffer_read_uint16(struct s2n_stuffer *stuffer, uint16_t * u); -extern int s2n_stuffer_read_uint24(struct s2n_stuffer *stuffer, uint32_t * u); -extern int s2n_stuffer_read_uint32(struct s2n_stuffer *stuffer, uint32_t * u); -extern int s2n_stuffer_read_uint64(struct s2n_stuffer *stuffer, uint64_t * u); - -extern int s2n_stuffer_write_uint8(struct s2n_stuffer *stuffer, const uint8_t u); -extern int s2n_stuffer_write_uint16(struct s2n_stuffer *stuffer, const uint16_t u); -extern int s2n_stuffer_write_uint24(struct s2n_stuffer *stuffer, const uint32_t u); -extern int s2n_stuffer_write_uint32(struct s2n_stuffer *stuffer, const uint32_t u); -extern int s2n_stuffer_write_uint64(struct s2n_stuffer *stuffer, const uint64_t u); - -/* Allocate space now for network order integers that will be written later. - * These are primarily intended to handle the vector type defined in the RFC: - * https://tools.ietf.org/html/rfc8446#section-3.4 */ -struct s2n_stuffer_reservation { - struct s2n_stuffer *stuffer; - uint32_t write_cursor; - uint8_t length; -}; -/* Check basic validity constraints on the s2n_stuffer_reservation: e.g. stuffer validity. */ -extern S2N_RESULT s2n_stuffer_reservation_validate(const struct s2n_stuffer_reservation* reservation); -extern int s2n_stuffer_reserve_uint16(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation); -extern int s2n_stuffer_reserve_uint24(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation); -extern int s2n_stuffer_write_vector_size(struct s2n_stuffer_reservation *reservation); - -/* Copy one stuffer to another */ -extern int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, uint32_t len); - -/* Read and write base64 */ -extern int s2n_stuffer_read_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *out); -extern int s2n_stuffer_write_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *in); - -/* Useful for text manipulation ... */ -#define s2n_stuffer_write_char( stuffer, c ) s2n_stuffer_write_uint8( (stuffer), (uint8_t) (c) ) -#define s2n_stuffer_read_char( stuffer, c ) s2n_stuffer_read_uint8( (stuffer), (uint8_t *) (c) ) -#define s2n_stuffer_write_str( stuffer, c ) s2n_stuffer_write_bytes( (stuffer), (const uint8_t *) (c), strlen((c)) ) -#define s2n_stuffer_write_text( stuffer, c, n ) s2n_stuffer_write_bytes( (stuffer), (const uint8_t *) (c), (n) ) -#define s2n_stuffer_read_text( stuffer, c, n ) s2n_stuffer_read_bytes( (stuffer), (uint8_t *) (c), (n) ) -extern int s2n_stuffer_read_expected_str(struct s2n_stuffer *stuffer, const char* expected); -extern int s2n_stuffer_peek_char(struct s2n_stuffer *stuffer, char *c); -extern int s2n_stuffer_read_token(struct s2n_stuffer *stuffer, struct s2n_stuffer *token, char delim); -extern int s2n_stuffer_read_line(struct s2n_stuffer *stuffer, struct s2n_stuffer *token); -extern int s2n_stuffer_peek_check_for_str(struct s2n_stuffer *s2n_stuffer, const char *expected); -extern int s2n_stuffer_skip_whitespace(struct s2n_stuffer *stuffer, uint32_t *skipped); -extern int s2n_stuffer_skip_to_char(struct s2n_stuffer *stuffer, char target); -extern int s2n_stuffer_skip_expected_char(struct s2n_stuffer *stuffer, const char expected, const uint32_t min, const uint32_t max, uint32_t *skipped); -extern int s2n_stuffer_skip_read_until(struct s2n_stuffer *stuffer, const char* target); -extern int s2n_stuffer_alloc_ro_from_string(struct s2n_stuffer *stuffer, const char *str); - -/* Read a private key from a PEM encoded stuffer to an ASN1/DER encoded one */ -extern int s2n_stuffer_private_key_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1); - -/* Read a certificate from a PEM encoded stuffer to an ASN1/DER encoded one */ -extern int s2n_stuffer_certificate_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1); - -/* Read DH parameters om a PEM encoded stuffer to a PKCS3 encoded one */ -extern int s2n_stuffer_dhparams_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *pkcs3); - -extern bool s2n_is_base64_char(unsigned char c); - -/* Copies all valid data from "stuffer" into "out". - * The old blob "out" pointed to is freed. - * It is the responsibility of the caller to free the free "out". - */ -extern int s2n_stuffer_extract_blob(struct s2n_stuffer *stuffer, struct s2n_blob *out); +/* + * Copyright 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. + */ + +#pragma once + +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/uio.h> + +#include "utils/s2n_blob.h" +#include "utils/s2n_result.h" + +#define S2N_MIN_STUFFER_GROWTH_IN_BYTES 1024 + +/* Using a non-zero value + * (a) makes wiped data easy to see in the debugger + * (b) makes use of wiped data obvious since this is unlikely to be a valid bit pattern + */ +#define S2N_WIPE_PATTERN 'w' + +#define SIZEOF_IN_BITS( t ) (sizeof(t) * CHAR_BIT) + +#define SIZEOF_UINT24 3 + +struct s2n_stuffer { + /* The data for the s2n_stuffer */ + struct s2n_blob blob; + + /* Cursors to the current read/write position in the s2n_stuffer */ + uint32_t read_cursor; + uint32_t write_cursor; + uint32_t high_water_mark; + + /* Was this stuffer alloc()'d ? */ + unsigned int alloced:1; + + /* Is this stuffer growable? */ + unsigned int growable:1; + + /* Can this stuffer be safely resized? + * A growable stuffer can be temporarily tainted by a raw read/write, + * preventing it from resizing. */ + unsigned int tainted:1; +}; + +#define s2n_stuffer_data_available( s ) ((s)->write_cursor - (s)->read_cursor) +#define s2n_stuffer_space_remaining( s ) ((s)->blob.size - (s)->write_cursor) +#define s2n_stuffer_is_wiped( s ) ((s)->high_water_mark == 0) +/* Check basic validity constraints on the stuffer: e.g. that cursors point within the blob */ +extern S2N_RESULT s2n_stuffer_validate(const struct s2n_stuffer* stuffer); + +/* Initialize and destroying stuffers */ +extern int s2n_stuffer_init(struct s2n_stuffer *stuffer, struct s2n_blob *in); +extern int s2n_stuffer_alloc(struct s2n_stuffer *stuffer, const uint32_t size); +extern int s2n_stuffer_growable_alloc(struct s2n_stuffer *stuffer, const uint32_t size); +extern int s2n_stuffer_free(struct s2n_stuffer *stuffer); +extern int s2n_stuffer_resize(struct s2n_stuffer *stuffer, const uint32_t size); +extern int s2n_stuffer_resize_if_empty(struct s2n_stuffer *stuffer, const uint32_t size); +extern int s2n_stuffer_rewind_read(struct s2n_stuffer *stuffer, const uint32_t size); +extern int s2n_stuffer_reread(struct s2n_stuffer *stuffer); +extern int s2n_stuffer_rewrite(struct s2n_stuffer *stuffer); +extern int s2n_stuffer_wipe(struct s2n_stuffer *stuffer); +extern int s2n_stuffer_wipe_n(struct s2n_stuffer *stuffer, const uint32_t n); +extern bool s2n_stuffer_is_consumed(struct s2n_stuffer *stuffer); + +/* Basic read and write */ +extern int s2n_stuffer_read(struct s2n_stuffer *stuffer, struct s2n_blob *out); +extern int s2n_stuffer_erase_and_read(struct s2n_stuffer *stuffer, struct s2n_blob *out); +extern int s2n_stuffer_write(struct s2n_stuffer *stuffer, const struct s2n_blob *in); +extern int s2n_stuffer_read_bytes(struct s2n_stuffer *stuffer, uint8_t * out, uint32_t n); +extern int s2n_stuffer_erase_and_read_bytes(struct s2n_stuffer *stuffer, uint8_t * data, uint32_t size); +extern int s2n_stuffer_write_bytes(struct s2n_stuffer *stuffer, const uint8_t * in, const uint32_t n); +extern int s2n_stuffer_writev_bytes(struct s2n_stuffer *stuffer, const struct iovec* iov, size_t iov_count, uint32_t offs, uint32_t size); +extern int s2n_stuffer_skip_read(struct s2n_stuffer *stuffer, uint32_t n); +extern int s2n_stuffer_skip_write(struct s2n_stuffer *stuffer, const uint32_t n); + +/* Tries to reserve enough space to write n additional bytes into the stuffer.*/ +extern int s2n_stuffer_reserve_space(struct s2n_stuffer *stuffer, uint32_t n); + +/* Raw read/write move the cursor along and give you a pointer you can + * read/write data_len bytes from/to in-place. + */ +extern void *s2n_stuffer_raw_write(struct s2n_stuffer *stuffer, const uint32_t data_len); +extern void *s2n_stuffer_raw_read(struct s2n_stuffer *stuffer, uint32_t data_len); + +/* Send/receive stuffer to/from a file descriptor */ +extern int s2n_stuffer_recv_from_fd(struct s2n_stuffer *stuffer, const int rfd, const uint32_t len, uint32_t *bytes_written); +extern int s2n_stuffer_send_to_fd(struct s2n_stuffer *stuffer, const int wfd, const uint32_t len, uint32_t *bytes_sent); + +/* Read and write integers in network order */ +extern int s2n_stuffer_read_uint8(struct s2n_stuffer *stuffer, uint8_t * u); +extern int s2n_stuffer_read_uint16(struct s2n_stuffer *stuffer, uint16_t * u); +extern int s2n_stuffer_read_uint24(struct s2n_stuffer *stuffer, uint32_t * u); +extern int s2n_stuffer_read_uint32(struct s2n_stuffer *stuffer, uint32_t * u); +extern int s2n_stuffer_read_uint64(struct s2n_stuffer *stuffer, uint64_t * u); + +extern int s2n_stuffer_write_uint8(struct s2n_stuffer *stuffer, const uint8_t u); +extern int s2n_stuffer_write_uint16(struct s2n_stuffer *stuffer, const uint16_t u); +extern int s2n_stuffer_write_uint24(struct s2n_stuffer *stuffer, const uint32_t u); +extern int s2n_stuffer_write_uint32(struct s2n_stuffer *stuffer, const uint32_t u); +extern int s2n_stuffer_write_uint64(struct s2n_stuffer *stuffer, const uint64_t u); + +/* Allocate space now for network order integers that will be written later. + * These are primarily intended to handle the vector type defined in the RFC: + * https://tools.ietf.org/html/rfc8446#section-3.4 */ +struct s2n_stuffer_reservation { + struct s2n_stuffer *stuffer; + uint32_t write_cursor; + uint8_t length; +}; +/* Check basic validity constraints on the s2n_stuffer_reservation: e.g. stuffer validity. */ +extern S2N_RESULT s2n_stuffer_reservation_validate(const struct s2n_stuffer_reservation* reservation); +extern int s2n_stuffer_reserve_uint16(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation); +extern int s2n_stuffer_reserve_uint24(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation); +extern int s2n_stuffer_write_vector_size(struct s2n_stuffer_reservation *reservation); + +/* Copy one stuffer to another */ +extern int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, uint32_t len); + +/* Read and write base64 */ +extern int s2n_stuffer_read_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *out); +extern int s2n_stuffer_write_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *in); + +/* Useful for text manipulation ... */ +#define s2n_stuffer_write_char( stuffer, c ) s2n_stuffer_write_uint8( (stuffer), (uint8_t) (c) ) +#define s2n_stuffer_read_char( stuffer, c ) s2n_stuffer_read_uint8( (stuffer), (uint8_t *) (c) ) +#define s2n_stuffer_write_str( stuffer, c ) s2n_stuffer_write_bytes( (stuffer), (const uint8_t *) (c), strlen((c)) ) +#define s2n_stuffer_write_text( stuffer, c, n ) s2n_stuffer_write_bytes( (stuffer), (const uint8_t *) (c), (n) ) +#define s2n_stuffer_read_text( stuffer, c, n ) s2n_stuffer_read_bytes( (stuffer), (uint8_t *) (c), (n) ) +extern int s2n_stuffer_read_expected_str(struct s2n_stuffer *stuffer, const char* expected); +extern int s2n_stuffer_peek_char(struct s2n_stuffer *stuffer, char *c); +extern int s2n_stuffer_read_token(struct s2n_stuffer *stuffer, struct s2n_stuffer *token, char delim); +extern int s2n_stuffer_read_line(struct s2n_stuffer *stuffer, struct s2n_stuffer *token); +extern int s2n_stuffer_peek_check_for_str(struct s2n_stuffer *s2n_stuffer, const char *expected); +extern int s2n_stuffer_skip_whitespace(struct s2n_stuffer *stuffer, uint32_t *skipped); +extern int s2n_stuffer_skip_to_char(struct s2n_stuffer *stuffer, char target); +extern int s2n_stuffer_skip_expected_char(struct s2n_stuffer *stuffer, const char expected, const uint32_t min, const uint32_t max, uint32_t *skipped); +extern int s2n_stuffer_skip_read_until(struct s2n_stuffer *stuffer, const char* target); +extern int s2n_stuffer_alloc_ro_from_string(struct s2n_stuffer *stuffer, const char *str); + +/* Read a private key from a PEM encoded stuffer to an ASN1/DER encoded one */ +extern int s2n_stuffer_private_key_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1); + +/* Read a certificate from a PEM encoded stuffer to an ASN1/DER encoded one */ +extern int s2n_stuffer_certificate_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1); + +/* Read DH parameters om a PEM encoded stuffer to a PKCS3 encoded one */ +extern int s2n_stuffer_dhparams_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *pkcs3); + +extern bool s2n_is_base64_char(unsigned char c); + +/* Copies all valid data from "stuffer" into "out". + * The old blob "out" pointed to is freed. + * It is the responsibility of the caller to free the free "out". + */ +extern int s2n_stuffer_extract_blob(struct s2n_stuffer *stuffer, struct s2n_blob *out); diff --git a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_base64.c b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_base64.c index bb156ac5f5..d091c7b12b 100644 --- a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_base64.c +++ b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_base64.c @@ -1,209 +1,209 @@ -/* - * Copyright 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 <string.h> - -#include "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "utils/s2n_safety.h" - -static const uint8_t b64[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' -}; - -/* Generated with this python: - * - * b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - * - * for i in range(0, 256): - * if chr(i) in b64: - * print str(b64.index(chr(i))) + ", ", - * else: - * print "255, ", - * - * if (i + 1) % 16 == 0: - * print - * - * Note that '=' maps to 64. - */ -static const uint8_t b64_inverse[256] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 64, 255, 255, - 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, - 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 -}; - -bool s2n_is_base64_char(unsigned char c) -{ - return (b64_inverse[*((uint8_t*)(&c))] != 255); -} - -/** - * NOTE: - * In general, shift before masking. This avoids needing to worry about how the - * signed bit may be handled. - */ -int s2n_stuffer_read_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *out) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - PRECONDITION_POSIX(s2n_stuffer_validate(out)); - int bytes_this_round = 3; - s2n_stack_blob(o, 4, 4); - - do { - if (s2n_stuffer_data_available(stuffer) < o.size) { - break; - } - - GUARD(s2n_stuffer_read(stuffer, &o)); - - uint8_t value1 = b64_inverse[o.data[0]]; - uint8_t value2 = b64_inverse[o.data[1]]; - uint8_t value3 = b64_inverse[o.data[2]]; - uint8_t value4 = b64_inverse[o.data[3]]; - - /* We assume the entire thing is base64 data, thus, terminate cleanly if we encounter a non-base64 character */ - if (value1 == 255) { - /* Undo the read */ - stuffer->read_cursor -= o.size; - S2N_ERROR(S2N_ERR_INVALID_BASE64); - } - - /* The first two characters can never be '=' and in general - * everything has to be a valid character. - */ - S2N_ERROR_IF(value1 == 64 || value2 == 64 || value2 == 255 || value3 == 255 || value4 == 255, S2N_ERR_INVALID_BASE64); - - if (o.data[2] == '=') { - /* If there is only one output byte, then the second value - * should have none of its bottom four bits set. - */ - S2N_ERROR_IF(o.data[3] != '=' || value2 & 0x0f, S2N_ERR_INVALID_BASE64); - bytes_this_round = 1; - value3 = 0; - value4 = 0; - } else if (o.data[3] == '=') { - /* The last two bits of the final value should be unset */ - S2N_ERROR_IF(value3 & 0x03, S2N_ERR_INVALID_BASE64); - - bytes_this_round = 2; - value4 = 0; - } - - /* Advance by bytes_this_round, and then fill in the data */ - GUARD(s2n_stuffer_skip_write(out, bytes_this_round)); - uint8_t *ptr = out->blob.data + out->write_cursor - bytes_this_round; - - /* value1 maps to the first 6 bits of the first data byte */ - /* value2's top two bits are the rest */ - *ptr = ((value1 << 2) & 0xfc) | ((value2 >> 4) & 0x03); - - if (bytes_this_round > 1) { - /* Put the next four bits in the second data byte */ - /* Put the next four bits in the third data byte */ - ptr++; - *ptr = ((value2 << 4) & 0xf0) | ((value3 >> 2) & 0x0f); - } - - if (bytes_this_round > 2) { - /* Put the next two bits in the third data byte */ - /* Put the next six bits in the fourth data byte */ - ptr++; - *ptr = ((value3 << 6) & 0xc0) | (value4 & 0x3f); - } - } while (bytes_this_round == 3); - - return S2N_SUCCESS; -} - -int s2n_stuffer_write_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *in) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - PRECONDITION_POSIX(s2n_stuffer_validate(in)); - s2n_stack_blob(o, 4, 4); - s2n_stack_blob(i, 3, 3); - - while (s2n_stuffer_data_available(in) > 2) { - GUARD(s2n_stuffer_read(in, &i)); - - /* Take the top 6-bits of the first data byte */ - o.data[0] = b64[(i.data[0] >> 2) & 0x3f]; - - /* Take the bottom 2-bits of the first data byte - 0b00110000 = 0x30 - * and take the top 4-bits of the second data byte - 0b00001111 = 0x0f - */ - o.data[1] = b64[((i.data[0] << 4) & 0x30) | ((i.data[1] >> 4) & 0x0f)]; - - /* Take the bottom 4-bits of the second data byte - 0b00111100 = 0x3c - * and take the top 2-bits of the third data byte - 0b00000011 = 0x03 - */ - o.data[2] = b64[((i.data[1] << 2) & 0x3c) | ((i.data[2] >> 6) & 0x03)]; - - /* Take the bottom 6-bits of the second data byte - 0b00111111 = 0x3f - */ - o.data[3] = b64[i.data[2] & 0x3f]; - - GUARD(s2n_stuffer_write(stuffer, &o)); - } - - if (s2n_stuffer_data_available(in)) { - /* Read just one byte */ - i.size = 1; - GUARD(s2n_stuffer_read(in, &i)); - uint8_t c = i.data[0]; - - /* We at least one data byte left to encode, encode - * its first six bits - */ - o.data[0] = b64[(c >> 2) & 0x3f]; - - /* And our end has to be an equals */ - o.data[3] = '='; - - /* How many bytes are actually left? */ - if (s2n_stuffer_data_available(in) == 0) { - /* We just have the last two bits to deal with */ - o.data[1] = b64[(c << 4) & 0x30]; - o.data[2] = '='; - } else { - /* Read the last byte */ - GUARD(s2n_stuffer_read(in, &i)); - - o.data[1] = b64[((c << 4) & 0x30) | ((i.data[0] >> 4) & 0x0f)]; - o.data[2] = b64[((i.data[0] << 2) & 0x3c)]; - } - - GUARD(s2n_stuffer_write(stuffer, &o)); - } - - return S2N_SUCCESS; -} +/* + * Copyright 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 <string.h> + +#include "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "utils/s2n_safety.h" + +static const uint8_t b64[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +/* Generated with this python: + * + * b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + * + * for i in range(0, 256): + * if chr(i) in b64: + * print str(b64.index(chr(i))) + ", ", + * else: + * print "255, ", + * + * if (i + 1) % 16 == 0: + * print + * + * Note that '=' maps to 64. + */ +static const uint8_t b64_inverse[256] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 64, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 +}; + +bool s2n_is_base64_char(unsigned char c) +{ + return (b64_inverse[*((uint8_t*)(&c))] != 255); +} + +/** + * NOTE: + * In general, shift before masking. This avoids needing to worry about how the + * signed bit may be handled. + */ +int s2n_stuffer_read_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *out) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + PRECONDITION_POSIX(s2n_stuffer_validate(out)); + int bytes_this_round = 3; + s2n_stack_blob(o, 4, 4); + + do { + if (s2n_stuffer_data_available(stuffer) < o.size) { + break; + } + + GUARD(s2n_stuffer_read(stuffer, &o)); + + uint8_t value1 = b64_inverse[o.data[0]]; + uint8_t value2 = b64_inverse[o.data[1]]; + uint8_t value3 = b64_inverse[o.data[2]]; + uint8_t value4 = b64_inverse[o.data[3]]; + + /* We assume the entire thing is base64 data, thus, terminate cleanly if we encounter a non-base64 character */ + if (value1 == 255) { + /* Undo the read */ + stuffer->read_cursor -= o.size; + S2N_ERROR(S2N_ERR_INVALID_BASE64); + } + + /* The first two characters can never be '=' and in general + * everything has to be a valid character. + */ + S2N_ERROR_IF(value1 == 64 || value2 == 64 || value2 == 255 || value3 == 255 || value4 == 255, S2N_ERR_INVALID_BASE64); + + if (o.data[2] == '=') { + /* If there is only one output byte, then the second value + * should have none of its bottom four bits set. + */ + S2N_ERROR_IF(o.data[3] != '=' || value2 & 0x0f, S2N_ERR_INVALID_BASE64); + bytes_this_round = 1; + value3 = 0; + value4 = 0; + } else if (o.data[3] == '=') { + /* The last two bits of the final value should be unset */ + S2N_ERROR_IF(value3 & 0x03, S2N_ERR_INVALID_BASE64); + + bytes_this_round = 2; + value4 = 0; + } + + /* Advance by bytes_this_round, and then fill in the data */ + GUARD(s2n_stuffer_skip_write(out, bytes_this_round)); + uint8_t *ptr = out->blob.data + out->write_cursor - bytes_this_round; + + /* value1 maps to the first 6 bits of the first data byte */ + /* value2's top two bits are the rest */ + *ptr = ((value1 << 2) & 0xfc) | ((value2 >> 4) & 0x03); + + if (bytes_this_round > 1) { + /* Put the next four bits in the second data byte */ + /* Put the next four bits in the third data byte */ + ptr++; + *ptr = ((value2 << 4) & 0xf0) | ((value3 >> 2) & 0x0f); + } + + if (bytes_this_round > 2) { + /* Put the next two bits in the third data byte */ + /* Put the next six bits in the fourth data byte */ + ptr++; + *ptr = ((value3 << 6) & 0xc0) | (value4 & 0x3f); + } + } while (bytes_this_round == 3); + + return S2N_SUCCESS; +} + +int s2n_stuffer_write_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *in) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + PRECONDITION_POSIX(s2n_stuffer_validate(in)); + s2n_stack_blob(o, 4, 4); + s2n_stack_blob(i, 3, 3); + + while (s2n_stuffer_data_available(in) > 2) { + GUARD(s2n_stuffer_read(in, &i)); + + /* Take the top 6-bits of the first data byte */ + o.data[0] = b64[(i.data[0] >> 2) & 0x3f]; + + /* Take the bottom 2-bits of the first data byte - 0b00110000 = 0x30 + * and take the top 4-bits of the second data byte - 0b00001111 = 0x0f + */ + o.data[1] = b64[((i.data[0] << 4) & 0x30) | ((i.data[1] >> 4) & 0x0f)]; + + /* Take the bottom 4-bits of the second data byte - 0b00111100 = 0x3c + * and take the top 2-bits of the third data byte - 0b00000011 = 0x03 + */ + o.data[2] = b64[((i.data[1] << 2) & 0x3c) | ((i.data[2] >> 6) & 0x03)]; + + /* Take the bottom 6-bits of the second data byte - 0b00111111 = 0x3f + */ + o.data[3] = b64[i.data[2] & 0x3f]; + + GUARD(s2n_stuffer_write(stuffer, &o)); + } + + if (s2n_stuffer_data_available(in)) { + /* Read just one byte */ + i.size = 1; + GUARD(s2n_stuffer_read(in, &i)); + uint8_t c = i.data[0]; + + /* We at least one data byte left to encode, encode + * its first six bits + */ + o.data[0] = b64[(c >> 2) & 0x3f]; + + /* And our end has to be an equals */ + o.data[3] = '='; + + /* How many bytes are actually left? */ + if (s2n_stuffer_data_available(in) == 0) { + /* We just have the last two bits to deal with */ + o.data[1] = b64[(c << 4) & 0x30]; + o.data[2] = '='; + } else { + /* Read the last byte */ + GUARD(s2n_stuffer_read(in, &i)); + + o.data[1] = b64[((c << 4) & 0x30) | ((i.data[0] >> 4) & 0x0f)]; + o.data[2] = b64[((i.data[0] << 2) & 0x3c)]; + } + + GUARD(s2n_stuffer_write(stuffer, &o)); + } + + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_file.c b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_file.c index b86e725604..2385572123 100644 --- a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_file.c +++ b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_file.c @@ -1,107 +1,107 @@ -/* - * Copyright 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 <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> - -#include "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "utils/s2n_safety.h" - -int s2n_stuffer_recv_from_fd(struct s2n_stuffer *stuffer, const int rfd, const uint32_t len, uint32_t *bytes_written) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - /* Make sure we have enough space to write */ - GUARD(s2n_stuffer_skip_write(stuffer, len)); - - /* "undo" the skip write */ - stuffer->write_cursor -= len; - - ssize_t r = 0; - do { - r = read(rfd, stuffer->blob.data + stuffer->write_cursor, len); - S2N_ERROR_IF(r < 0 && errno != EINTR, S2N_ERR_READ); - } while (r < 0); - - /* Record just how many bytes we have written */ - S2N_ERROR_IF(r > UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW); - GUARD(s2n_stuffer_skip_write(stuffer, (uint32_t)r)); - if (bytes_written != NULL) *bytes_written = r; - return S2N_SUCCESS; -} - -int s2n_stuffer_send_to_fd(struct s2n_stuffer *stuffer, const int wfd, const uint32_t len, uint32_t *bytes_sent) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - - /* Make sure we even have the data */ - GUARD(s2n_stuffer_skip_read(stuffer, len)); - - /* "undo" the skip read */ - stuffer->read_cursor -= len; - - ssize_t w = 0; - do { - w = write(wfd, stuffer->blob.data + stuffer->read_cursor, len); - S2N_ERROR_IF(w < 0 && errno != EINTR, S2N_ERR_WRITE); - } while (w < 0); - - S2N_ERROR_IF(w > UINT32_MAX - stuffer->read_cursor, S2N_ERR_INTEGER_OVERFLOW); - stuffer->read_cursor += w; - if (bytes_sent != NULL) *bytes_sent = w; - return S2N_SUCCESS; -} - -int s2n_stuffer_alloc_ro_from_fd(struct s2n_stuffer *stuffer, int rfd) -{ - ENSURE_POSIX_MUT(stuffer); - struct stat st = {0}; - - ENSURE_POSIX(fstat(rfd, &st) >= 0, S2N_ERR_FSTAT); - - ENSURE_POSIX(st.st_size > 0, S2N_FAILURE); - ENSURE_POSIX(st.st_size <= UINT32_MAX, S2N_FAILURE); - - uint8_t *map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, rfd, 0); - ENSURE_POSIX(map != MAP_FAILED, S2N_ERR_MMAP); - - struct s2n_blob b = {0}; - ENSURE_POSIX(s2n_blob_init(&b, map, (uint32_t)st.st_size), S2N_FAILURE); - return s2n_stuffer_init(stuffer, &b); -} - -int s2n_stuffer_alloc_ro_from_file(struct s2n_stuffer *stuffer, const char *file) -{ - ENSURE_POSIX_MUT(stuffer); - notnull_check(file); - int fd; - - do { - fd = open(file, O_RDONLY); - ENSURE_POSIX(fd >= 0 || errno == EINTR, S2N_ERR_OPEN); - } while (fd < 0); - - int r = s2n_stuffer_alloc_ro_from_fd(stuffer, fd); - - GUARD(close(fd)); - - return r; -} +/* + * Copyright 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 <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#include "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "utils/s2n_safety.h" + +int s2n_stuffer_recv_from_fd(struct s2n_stuffer *stuffer, const int rfd, const uint32_t len, uint32_t *bytes_written) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + /* Make sure we have enough space to write */ + GUARD(s2n_stuffer_skip_write(stuffer, len)); + + /* "undo" the skip write */ + stuffer->write_cursor -= len; + + ssize_t r = 0; + do { + r = read(rfd, stuffer->blob.data + stuffer->write_cursor, len); + S2N_ERROR_IF(r < 0 && errno != EINTR, S2N_ERR_READ); + } while (r < 0); + + /* Record just how many bytes we have written */ + S2N_ERROR_IF(r > UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW); + GUARD(s2n_stuffer_skip_write(stuffer, (uint32_t)r)); + if (bytes_written != NULL) *bytes_written = r; + return S2N_SUCCESS; +} + +int s2n_stuffer_send_to_fd(struct s2n_stuffer *stuffer, const int wfd, const uint32_t len, uint32_t *bytes_sent) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + + /* Make sure we even have the data */ + GUARD(s2n_stuffer_skip_read(stuffer, len)); + + /* "undo" the skip read */ + stuffer->read_cursor -= len; + + ssize_t w = 0; + do { + w = write(wfd, stuffer->blob.data + stuffer->read_cursor, len); + S2N_ERROR_IF(w < 0 && errno != EINTR, S2N_ERR_WRITE); + } while (w < 0); + + S2N_ERROR_IF(w > UINT32_MAX - stuffer->read_cursor, S2N_ERR_INTEGER_OVERFLOW); + stuffer->read_cursor += w; + if (bytes_sent != NULL) *bytes_sent = w; + return S2N_SUCCESS; +} + +int s2n_stuffer_alloc_ro_from_fd(struct s2n_stuffer *stuffer, int rfd) +{ + ENSURE_POSIX_MUT(stuffer); + struct stat st = {0}; + + ENSURE_POSIX(fstat(rfd, &st) >= 0, S2N_ERR_FSTAT); + + ENSURE_POSIX(st.st_size > 0, S2N_FAILURE); + ENSURE_POSIX(st.st_size <= UINT32_MAX, S2N_FAILURE); + + uint8_t *map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, rfd, 0); + ENSURE_POSIX(map != MAP_FAILED, S2N_ERR_MMAP); + + struct s2n_blob b = {0}; + ENSURE_POSIX(s2n_blob_init(&b, map, (uint32_t)st.st_size), S2N_FAILURE); + return s2n_stuffer_init(stuffer, &b); +} + +int s2n_stuffer_alloc_ro_from_file(struct s2n_stuffer *stuffer, const char *file) +{ + ENSURE_POSIX_MUT(stuffer); + notnull_check(file); + int fd; + + do { + fd = open(file, O_RDONLY); + ENSURE_POSIX(fd >= 0 || errno == EINTR, S2N_ERR_OPEN); + } while (fd < 0); + + int r = s2n_stuffer_alloc_ro_from_fd(stuffer, fd); + + GUARD(close(fd)); + + return r; +} diff --git a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_network_order.c b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_network_order.c index f30c10e82f..d86e8e538a 100644 --- a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_network_order.c +++ b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_network_order.c @@ -1,197 +1,197 @@ -/* - * Copyright 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 "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "utils/s2n_annotations.h" -#include "utils/s2n_safety.h" - -/* Writes length bytes of input to stuffer, in network order, starting from the smallest byte of input. */ -int s2n_stuffer_write_network_order(struct s2n_stuffer *stuffer, const uint64_t input, const uint8_t length) -{ - ENSURE_POSIX(length <= sizeof(input), S2N_ERR_SAFETY); - GUARD(s2n_stuffer_skip_write(stuffer, length)); - uint8_t *data = stuffer->blob.data + stuffer->write_cursor - length; - - for (int i = 0; i < length; i++) { - S2N_INVARIENT(i <= length); - uint8_t shift = (length - i - 1) * CHAR_BIT; - data[i] = (input >> (shift)) & UINT8_MAX; - } - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_reserve(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation, const uint8_t length) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - notnull_check(reservation); - - *reservation = (struct s2n_stuffer_reservation) {.stuffer = stuffer, .write_cursor = stuffer->write_cursor, .length = length}; - - GUARD(s2n_stuffer_skip_write(stuffer, reservation->length)); - memset_check(stuffer->blob.data + reservation->write_cursor, S2N_WIPE_PATTERN, reservation->length); - POSTCONDITION_POSIX(s2n_stuffer_reservation_validate(reservation)); - return S2N_SUCCESS; -} - -int s2n_stuffer_read_uint8(struct s2n_stuffer *stuffer, uint8_t * u) -{ - GUARD(s2n_stuffer_read_bytes(stuffer, u, sizeof(uint8_t))); - - return S2N_SUCCESS; -} - -int s2n_stuffer_write_uint8(struct s2n_stuffer *stuffer, const uint8_t u) -{ - GUARD(s2n_stuffer_write_bytes(stuffer, &u, sizeof(u))); - - return S2N_SUCCESS; -} - -int s2n_stuffer_read_uint16(struct s2n_stuffer *stuffer, uint16_t * u) -{ - notnull_check(u); - uint8_t data[sizeof(uint16_t)]; - - GUARD(s2n_stuffer_read_bytes(stuffer, data, sizeof(data))); - - *u = data[0] << 8; - *u |= data[1]; - - return S2N_SUCCESS; -} - -int s2n_stuffer_write_uint16(struct s2n_stuffer *stuffer, const uint16_t u) -{ - return s2n_stuffer_write_network_order(stuffer, u, sizeof(u)); -} - -int s2n_stuffer_reserve_uint16(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation) -{ - return s2n_stuffer_reserve(stuffer, reservation, sizeof(uint16_t)); -} - -int s2n_stuffer_read_uint24(struct s2n_stuffer *stuffer, uint32_t * u) -{ - notnull_check(u); - uint8_t data[SIZEOF_UINT24]; - - GUARD(s2n_stuffer_read_bytes(stuffer, data, sizeof(data))); - - *u = data[0] << 16; - *u |= data[1] << 8; - *u |= data[2]; - - return S2N_SUCCESS; -} - -int s2n_stuffer_write_uint24(struct s2n_stuffer *stuffer, const uint32_t u) -{ - return s2n_stuffer_write_network_order(stuffer, u, SIZEOF_UINT24); -} - -int s2n_stuffer_reserve_uint24(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation) -{ - return s2n_stuffer_reserve(stuffer, reservation, SIZEOF_UINT24); -} - -int s2n_stuffer_read_uint32(struct s2n_stuffer *stuffer, uint32_t * u) -{ - notnull_check(u); - uint8_t data[sizeof(uint32_t)]; - - GUARD(s2n_stuffer_read_bytes(stuffer, data, sizeof(data))); - - *u = ((uint32_t) data[0]) << 24; - *u |= data[1] << 16; - *u |= data[2] << 8; - *u |= data[3]; - - return S2N_SUCCESS; -} - -int s2n_stuffer_write_uint32(struct s2n_stuffer *stuffer, const uint32_t u) -{ - return s2n_stuffer_write_network_order(stuffer, u, sizeof(u)); -} - -int s2n_stuffer_read_uint64(struct s2n_stuffer *stuffer, uint64_t * u) -{ - notnull_check(u); - uint8_t data[sizeof(uint64_t)]; - - GUARD(s2n_stuffer_read_bytes(stuffer, data, sizeof(data))); - - *u = ((uint64_t) data[0]) << 56; - *u |= ((uint64_t) data[1]) << 48; - *u |= ((uint64_t) data[2]) << 40; - *u |= ((uint64_t) data[3]) << 32; - *u |= ((uint64_t) data[4]) << 24; - *u |= ((uint64_t) data[5]) << 16; - *u |= ((uint64_t) data[6]) << 8; - *u |= data[7]; - - return S2N_SUCCESS; -} - -int s2n_stuffer_write_uint64(struct s2n_stuffer *stuffer, const uint64_t u) -{ - return s2n_stuffer_write_network_order(stuffer, u, sizeof(u)); -} - -static int length_matches_value_check(uint32_t value, uint8_t length) -{ - /* Value is represented as a uint32_t, so shouldn't be assumed larger */ - S2N_ERROR_IF(length > sizeof(uint32_t), S2N_ERR_SIZE_MISMATCH); - - if (length < sizeof(uint32_t)) { - /* Value should be less than the maximum for its length */ - S2N_ERROR_IF(value >= (0x01 << (length * 8)), S2N_ERR_SIZE_MISMATCH); - } - - return S2N_SUCCESS; -} - -static int s2n_stuffer_write_reservation_impl(struct s2n_stuffer_reservation* reservation, const uint32_t u) -{ - reservation->stuffer->write_cursor = reservation->write_cursor; - PRECONDITION_POSIX(s2n_stuffer_validate(reservation->stuffer)); - - GUARD(length_matches_value_check(u, reservation->length)); - GUARD(s2n_stuffer_write_network_order(reservation->stuffer, u, reservation->length)); - POSTCONDITION_POSIX(s2n_stuffer_validate(reservation->stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_write_reservation(struct s2n_stuffer_reservation* reservation, const uint32_t u) -{ - PRECONDITION_POSIX(s2n_stuffer_reservation_validate(reservation)); - uint32_t old_write_cursor = reservation->stuffer->write_cursor; - int result = s2n_stuffer_write_reservation_impl(reservation, u); - reservation->stuffer->write_cursor = old_write_cursor; - return result; -} - -int s2n_stuffer_write_vector_size(struct s2n_stuffer_reservation* reservation) -{ - PRECONDITION_POSIX(s2n_stuffer_reservation_validate(reservation)); - uint32_t size = 0; - GUARD(s2n_sub_overflow(reservation->stuffer->write_cursor, reservation->write_cursor, &size)); - GUARD(s2n_sub_overflow(size, reservation->length, &size)); - return s2n_stuffer_write_reservation(reservation, size); -} +/* + * Copyright 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 "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "utils/s2n_annotations.h" +#include "utils/s2n_safety.h" + +/* Writes length bytes of input to stuffer, in network order, starting from the smallest byte of input. */ +int s2n_stuffer_write_network_order(struct s2n_stuffer *stuffer, const uint64_t input, const uint8_t length) +{ + ENSURE_POSIX(length <= sizeof(input), S2N_ERR_SAFETY); + GUARD(s2n_stuffer_skip_write(stuffer, length)); + uint8_t *data = stuffer->blob.data + stuffer->write_cursor - length; + + for (int i = 0; i < length; i++) { + S2N_INVARIENT(i <= length); + uint8_t shift = (length - i - 1) * CHAR_BIT; + data[i] = (input >> (shift)) & UINT8_MAX; + } + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_reserve(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation, const uint8_t length) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + notnull_check(reservation); + + *reservation = (struct s2n_stuffer_reservation) {.stuffer = stuffer, .write_cursor = stuffer->write_cursor, .length = length}; + + GUARD(s2n_stuffer_skip_write(stuffer, reservation->length)); + memset_check(stuffer->blob.data + reservation->write_cursor, S2N_WIPE_PATTERN, reservation->length); + POSTCONDITION_POSIX(s2n_stuffer_reservation_validate(reservation)); + return S2N_SUCCESS; +} + +int s2n_stuffer_read_uint8(struct s2n_stuffer *stuffer, uint8_t * u) +{ + GUARD(s2n_stuffer_read_bytes(stuffer, u, sizeof(uint8_t))); + + return S2N_SUCCESS; +} + +int s2n_stuffer_write_uint8(struct s2n_stuffer *stuffer, const uint8_t u) +{ + GUARD(s2n_stuffer_write_bytes(stuffer, &u, sizeof(u))); + + return S2N_SUCCESS; +} + +int s2n_stuffer_read_uint16(struct s2n_stuffer *stuffer, uint16_t * u) +{ + notnull_check(u); + uint8_t data[sizeof(uint16_t)]; + + GUARD(s2n_stuffer_read_bytes(stuffer, data, sizeof(data))); + + *u = data[0] << 8; + *u |= data[1]; + + return S2N_SUCCESS; +} + +int s2n_stuffer_write_uint16(struct s2n_stuffer *stuffer, const uint16_t u) +{ + return s2n_stuffer_write_network_order(stuffer, u, sizeof(u)); +} + +int s2n_stuffer_reserve_uint16(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation) +{ + return s2n_stuffer_reserve(stuffer, reservation, sizeof(uint16_t)); +} + +int s2n_stuffer_read_uint24(struct s2n_stuffer *stuffer, uint32_t * u) +{ + notnull_check(u); + uint8_t data[SIZEOF_UINT24]; + + GUARD(s2n_stuffer_read_bytes(stuffer, data, sizeof(data))); + + *u = data[0] << 16; + *u |= data[1] << 8; + *u |= data[2]; + + return S2N_SUCCESS; +} + +int s2n_stuffer_write_uint24(struct s2n_stuffer *stuffer, const uint32_t u) +{ + return s2n_stuffer_write_network_order(stuffer, u, SIZEOF_UINT24); +} + +int s2n_stuffer_reserve_uint24(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation) +{ + return s2n_stuffer_reserve(stuffer, reservation, SIZEOF_UINT24); +} + +int s2n_stuffer_read_uint32(struct s2n_stuffer *stuffer, uint32_t * u) +{ + notnull_check(u); + uint8_t data[sizeof(uint32_t)]; + + GUARD(s2n_stuffer_read_bytes(stuffer, data, sizeof(data))); + + *u = ((uint32_t) data[0]) << 24; + *u |= data[1] << 16; + *u |= data[2] << 8; + *u |= data[3]; + + return S2N_SUCCESS; +} + +int s2n_stuffer_write_uint32(struct s2n_stuffer *stuffer, const uint32_t u) +{ + return s2n_stuffer_write_network_order(stuffer, u, sizeof(u)); +} + +int s2n_stuffer_read_uint64(struct s2n_stuffer *stuffer, uint64_t * u) +{ + notnull_check(u); + uint8_t data[sizeof(uint64_t)]; + + GUARD(s2n_stuffer_read_bytes(stuffer, data, sizeof(data))); + + *u = ((uint64_t) data[0]) << 56; + *u |= ((uint64_t) data[1]) << 48; + *u |= ((uint64_t) data[2]) << 40; + *u |= ((uint64_t) data[3]) << 32; + *u |= ((uint64_t) data[4]) << 24; + *u |= ((uint64_t) data[5]) << 16; + *u |= ((uint64_t) data[6]) << 8; + *u |= data[7]; + + return S2N_SUCCESS; +} + +int s2n_stuffer_write_uint64(struct s2n_stuffer *stuffer, const uint64_t u) +{ + return s2n_stuffer_write_network_order(stuffer, u, sizeof(u)); +} + +static int length_matches_value_check(uint32_t value, uint8_t length) +{ + /* Value is represented as a uint32_t, so shouldn't be assumed larger */ + S2N_ERROR_IF(length > sizeof(uint32_t), S2N_ERR_SIZE_MISMATCH); + + if (length < sizeof(uint32_t)) { + /* Value should be less than the maximum for its length */ + S2N_ERROR_IF(value >= (0x01 << (length * 8)), S2N_ERR_SIZE_MISMATCH); + } + + return S2N_SUCCESS; +} + +static int s2n_stuffer_write_reservation_impl(struct s2n_stuffer_reservation* reservation, const uint32_t u) +{ + reservation->stuffer->write_cursor = reservation->write_cursor; + PRECONDITION_POSIX(s2n_stuffer_validate(reservation->stuffer)); + + GUARD(length_matches_value_check(u, reservation->length)); + GUARD(s2n_stuffer_write_network_order(reservation->stuffer, u, reservation->length)); + POSTCONDITION_POSIX(s2n_stuffer_validate(reservation->stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_write_reservation(struct s2n_stuffer_reservation* reservation, const uint32_t u) +{ + PRECONDITION_POSIX(s2n_stuffer_reservation_validate(reservation)); + uint32_t old_write_cursor = reservation->stuffer->write_cursor; + int result = s2n_stuffer_write_reservation_impl(reservation, u); + reservation->stuffer->write_cursor = old_write_cursor; + return result; +} + +int s2n_stuffer_write_vector_size(struct s2n_stuffer_reservation* reservation) +{ + PRECONDITION_POSIX(s2n_stuffer_reservation_validate(reservation)); + uint32_t size = 0; + GUARD(s2n_sub_overflow(reservation->stuffer->write_cursor, reservation->write_cursor, &size)); + GUARD(s2n_sub_overflow(size, reservation->length, &size)); + return s2n_stuffer_write_reservation(reservation, size); +} diff --git a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_pem.c b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_pem.c index a0805980c2..2028d9a6a6 100644 --- a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_pem.c +++ b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_pem.c @@ -1,171 +1,171 @@ -/* - * Copyright 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 <string.h> -#include "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "utils/s2n_safety.h" - -#define S2N_PEM_DELIMTER_CHAR '-' -#define S2N_PEM_DELIMITER_MIN_COUNT 1 -#define S2N_PEM_DELIMITER_MAX_COUNT 64 -#define S2N_PEM_BEGIN_TOKEN "BEGIN " -#define S2N_PEM_END_TOKEN "END " -#define S2N_PEM_PKCS1_RSA_PRIVATE_KEY "RSA PRIVATE KEY" -#define S2N_PEM_PKCS1_EC_PRIVATE_KEY "EC PRIVATE KEY" -#define S2N_PEM_PKCS8_PRIVATE_KEY "PRIVATE KEY" -#define S2N_PEM_DH_PARAMETERS "DH PARAMETERS" -#define S2N_PEM_EC_PARAMETERS "EC PARAMETERS" -#define S2N_PEM_CERTIFICATE "CERTIFICATE" - -static int s2n_stuffer_pem_read_encapsulation_line(struct s2n_stuffer *pem, const char* encap_marker, const char *keyword) { - - /* Skip any number of Chars until a "-" is reached */ - GUARD(s2n_stuffer_skip_to_char(pem, S2N_PEM_DELIMTER_CHAR)); - - /* Ensure between 1 and 64 '-' chars at start of line */ - GUARD(s2n_stuffer_skip_expected_char(pem, S2N_PEM_DELIMTER_CHAR, S2N_PEM_DELIMITER_MIN_COUNT, S2N_PEM_DELIMITER_MAX_COUNT, NULL)); - - /* Ensure next string in stuffer is "BEGIN " or "END " */ - GUARD(s2n_stuffer_read_expected_str(pem, encap_marker)); - - /* Ensure next string is stuffer is the keyword (Eg "CERTIFICATE", "PRIVATE KEY", etc) */ - GUARD(s2n_stuffer_read_expected_str(pem, keyword)); - - /* Ensure between 1 and 64 '-' chars at end of line */ - GUARD(s2n_stuffer_skip_expected_char(pem, S2N_PEM_DELIMTER_CHAR, S2N_PEM_DELIMITER_MIN_COUNT, S2N_PEM_DELIMITER_MAX_COUNT, NULL)); - - /* Check for missing newline between dashes case: "-----END CERTIFICATE----------BEGIN CERTIFICATE-----" */ - if (strncmp(encap_marker, S2N_PEM_END_TOKEN, strlen(S2N_PEM_END_TOKEN)) == 0 - && s2n_stuffer_peek_check_for_str(pem, S2N_PEM_BEGIN_TOKEN) == S2N_SUCCESS) { - /* Rewind stuffer by 1 byte before BEGIN, so that next read will find the dash before the BEGIN */ - GUARD(s2n_stuffer_rewind_read(pem, 1)); - } - - /* Skip newlines and other whitepsace that may be after the dashes */ - return s2n_stuffer_skip_whitespace(pem, NULL); -} - -static int s2n_stuffer_pem_read_begin(struct s2n_stuffer *pem, const char *keyword) -{ - return s2n_stuffer_pem_read_encapsulation_line(pem, S2N_PEM_BEGIN_TOKEN, keyword); -} - -static int s2n_stuffer_pem_read_end(struct s2n_stuffer *pem, const char *keyword) -{ - return s2n_stuffer_pem_read_encapsulation_line(pem, S2N_PEM_END_TOKEN, keyword); -} - -static int s2n_stuffer_pem_read_contents(struct s2n_stuffer *pem, struct s2n_stuffer *asn1) -{ - s2n_stack_blob(base64__blob, 64, 64); - struct s2n_stuffer base64_stuffer = {0}; - GUARD(s2n_stuffer_init(&base64_stuffer, &base64__blob)); - - while (1) { - /* We need a byte... */ - ENSURE_POSIX(s2n_stuffer_data_available(pem) >= 1, S2N_ERR_STUFFER_OUT_OF_DATA); - - /* Peek to see if the next char is a dash, meaning end of pem_contents */ - uint8_t c = pem->blob.data[pem->read_cursor]; - if (c == '-') { - break; - } - /* Else, move read pointer forward by 1 byte since we will be consuming it. */ - pem->read_cursor += 1; - - /* Skip non-base64 characters */ - if (!s2n_is_base64_char(c)) { - continue; - } - - /* Flush base64_stuffer to asn1 stuffer if we're out of space, and reset base64_stuffer read/write pointers */ - if (s2n_stuffer_space_remaining(&base64_stuffer) == 0) { - GUARD(s2n_stuffer_read_base64(&base64_stuffer, asn1)); - GUARD(s2n_stuffer_rewrite(&base64_stuffer)); - } - - /* Copy next char to base64_stuffer */ - GUARD(s2n_stuffer_write_bytes(&base64_stuffer, (uint8_t *) &c, 1)); - - }; - - /* Flush any remaining bytes to asn1 */ - GUARD(s2n_stuffer_read_base64(&base64_stuffer, asn1)); - - return S2N_SUCCESS; -} - -static int s2n_stuffer_data_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1, const char *keyword) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(pem)); - PRECONDITION_POSIX(s2n_stuffer_validate(asn1)); - notnull_check(keyword); - - GUARD(s2n_stuffer_pem_read_begin(pem, keyword)); - GUARD(s2n_stuffer_pem_read_contents(pem, asn1)); - GUARD(s2n_stuffer_pem_read_end(pem, keyword)); - - POSTCONDITION_POSIX(s2n_stuffer_validate(pem)); - POSTCONDITION_POSIX(s2n_stuffer_validate(asn1)); - return S2N_SUCCESS; -} - -int s2n_stuffer_private_key_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1) { - PRECONDITION_POSIX(s2n_stuffer_validate(pem)); - PRECONDITION_POSIX(s2n_stuffer_validate(asn1)); - int rc; - - rc = s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS1_RSA_PRIVATE_KEY); - if (!rc) { - return rc; - } - - s2n_stuffer_reread(pem); - s2n_stuffer_reread(asn1); - - /* By default, OpenSSL tools always generate both "EC PARAMETERS" and "EC PRIVATE - * KEY" PEM objects in the keyfile. Skip the first "EC PARAMETERS" object so that we're - * compatible with OpenSSL's default output, and since "EC PARAMETERS" is - * only needed for non-standard curves that aren't currently supported. - */ - rc = s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_EC_PARAMETERS); - if (rc < 0) { - s2n_stuffer_reread(pem); - } - s2n_stuffer_wipe(asn1); - - rc = s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS1_EC_PRIVATE_KEY); - if (!rc) { - return rc; - } - - /* If it does not match either format, try PKCS#8 */ - s2n_stuffer_reread(pem); - s2n_stuffer_reread(asn1); - return s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS8_PRIVATE_KEY); -} - -int s2n_stuffer_certificate_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1) -{ - return s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_CERTIFICATE); -} - -int s2n_stuffer_dhparams_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *pkcs3) -{ - return s2n_stuffer_data_from_pem(pem, pkcs3, S2N_PEM_DH_PARAMETERS); -} +/* + * Copyright 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 <string.h> +#include "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "utils/s2n_safety.h" + +#define S2N_PEM_DELIMTER_CHAR '-' +#define S2N_PEM_DELIMITER_MIN_COUNT 1 +#define S2N_PEM_DELIMITER_MAX_COUNT 64 +#define S2N_PEM_BEGIN_TOKEN "BEGIN " +#define S2N_PEM_END_TOKEN "END " +#define S2N_PEM_PKCS1_RSA_PRIVATE_KEY "RSA PRIVATE KEY" +#define S2N_PEM_PKCS1_EC_PRIVATE_KEY "EC PRIVATE KEY" +#define S2N_PEM_PKCS8_PRIVATE_KEY "PRIVATE KEY" +#define S2N_PEM_DH_PARAMETERS "DH PARAMETERS" +#define S2N_PEM_EC_PARAMETERS "EC PARAMETERS" +#define S2N_PEM_CERTIFICATE "CERTIFICATE" + +static int s2n_stuffer_pem_read_encapsulation_line(struct s2n_stuffer *pem, const char* encap_marker, const char *keyword) { + + /* Skip any number of Chars until a "-" is reached */ + GUARD(s2n_stuffer_skip_to_char(pem, S2N_PEM_DELIMTER_CHAR)); + + /* Ensure between 1 and 64 '-' chars at start of line */ + GUARD(s2n_stuffer_skip_expected_char(pem, S2N_PEM_DELIMTER_CHAR, S2N_PEM_DELIMITER_MIN_COUNT, S2N_PEM_DELIMITER_MAX_COUNT, NULL)); + + /* Ensure next string in stuffer is "BEGIN " or "END " */ + GUARD(s2n_stuffer_read_expected_str(pem, encap_marker)); + + /* Ensure next string is stuffer is the keyword (Eg "CERTIFICATE", "PRIVATE KEY", etc) */ + GUARD(s2n_stuffer_read_expected_str(pem, keyword)); + + /* Ensure between 1 and 64 '-' chars at end of line */ + GUARD(s2n_stuffer_skip_expected_char(pem, S2N_PEM_DELIMTER_CHAR, S2N_PEM_DELIMITER_MIN_COUNT, S2N_PEM_DELIMITER_MAX_COUNT, NULL)); + + /* Check for missing newline between dashes case: "-----END CERTIFICATE----------BEGIN CERTIFICATE-----" */ + if (strncmp(encap_marker, S2N_PEM_END_TOKEN, strlen(S2N_PEM_END_TOKEN)) == 0 + && s2n_stuffer_peek_check_for_str(pem, S2N_PEM_BEGIN_TOKEN) == S2N_SUCCESS) { + /* Rewind stuffer by 1 byte before BEGIN, so that next read will find the dash before the BEGIN */ + GUARD(s2n_stuffer_rewind_read(pem, 1)); + } + + /* Skip newlines and other whitepsace that may be after the dashes */ + return s2n_stuffer_skip_whitespace(pem, NULL); +} + +static int s2n_stuffer_pem_read_begin(struct s2n_stuffer *pem, const char *keyword) +{ + return s2n_stuffer_pem_read_encapsulation_line(pem, S2N_PEM_BEGIN_TOKEN, keyword); +} + +static int s2n_stuffer_pem_read_end(struct s2n_stuffer *pem, const char *keyword) +{ + return s2n_stuffer_pem_read_encapsulation_line(pem, S2N_PEM_END_TOKEN, keyword); +} + +static int s2n_stuffer_pem_read_contents(struct s2n_stuffer *pem, struct s2n_stuffer *asn1) +{ + s2n_stack_blob(base64__blob, 64, 64); + struct s2n_stuffer base64_stuffer = {0}; + GUARD(s2n_stuffer_init(&base64_stuffer, &base64__blob)); + + while (1) { + /* We need a byte... */ + ENSURE_POSIX(s2n_stuffer_data_available(pem) >= 1, S2N_ERR_STUFFER_OUT_OF_DATA); + + /* Peek to see if the next char is a dash, meaning end of pem_contents */ + uint8_t c = pem->blob.data[pem->read_cursor]; + if (c == '-') { + break; + } + /* Else, move read pointer forward by 1 byte since we will be consuming it. */ + pem->read_cursor += 1; + + /* Skip non-base64 characters */ + if (!s2n_is_base64_char(c)) { + continue; + } + + /* Flush base64_stuffer to asn1 stuffer if we're out of space, and reset base64_stuffer read/write pointers */ + if (s2n_stuffer_space_remaining(&base64_stuffer) == 0) { + GUARD(s2n_stuffer_read_base64(&base64_stuffer, asn1)); + GUARD(s2n_stuffer_rewrite(&base64_stuffer)); + } + + /* Copy next char to base64_stuffer */ + GUARD(s2n_stuffer_write_bytes(&base64_stuffer, (uint8_t *) &c, 1)); + + }; + + /* Flush any remaining bytes to asn1 */ + GUARD(s2n_stuffer_read_base64(&base64_stuffer, asn1)); + + return S2N_SUCCESS; +} + +static int s2n_stuffer_data_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1, const char *keyword) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(pem)); + PRECONDITION_POSIX(s2n_stuffer_validate(asn1)); + notnull_check(keyword); + + GUARD(s2n_stuffer_pem_read_begin(pem, keyword)); + GUARD(s2n_stuffer_pem_read_contents(pem, asn1)); + GUARD(s2n_stuffer_pem_read_end(pem, keyword)); + + POSTCONDITION_POSIX(s2n_stuffer_validate(pem)); + POSTCONDITION_POSIX(s2n_stuffer_validate(asn1)); + return S2N_SUCCESS; +} + +int s2n_stuffer_private_key_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1) { + PRECONDITION_POSIX(s2n_stuffer_validate(pem)); + PRECONDITION_POSIX(s2n_stuffer_validate(asn1)); + int rc; + + rc = s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS1_RSA_PRIVATE_KEY); + if (!rc) { + return rc; + } + + s2n_stuffer_reread(pem); + s2n_stuffer_reread(asn1); + + /* By default, OpenSSL tools always generate both "EC PARAMETERS" and "EC PRIVATE + * KEY" PEM objects in the keyfile. Skip the first "EC PARAMETERS" object so that we're + * compatible with OpenSSL's default output, and since "EC PARAMETERS" is + * only needed for non-standard curves that aren't currently supported. + */ + rc = s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_EC_PARAMETERS); + if (rc < 0) { + s2n_stuffer_reread(pem); + } + s2n_stuffer_wipe(asn1); + + rc = s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS1_EC_PRIVATE_KEY); + if (!rc) { + return rc; + } + + /* If it does not match either format, try PKCS#8 */ + s2n_stuffer_reread(pem); + s2n_stuffer_reread(asn1); + return s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS8_PRIVATE_KEY); +} + +int s2n_stuffer_certificate_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1) +{ + return s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_CERTIFICATE); +} + +int s2n_stuffer_dhparams_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *pkcs3) +{ + return s2n_stuffer_data_from_pem(pem, pkcs3, S2N_PEM_DH_PARAMETERS); +} diff --git a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_text.c b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_text.c index dc60ca5099..6be5fdbbad 100644 --- a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_text.c +++ b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer_text.c @@ -1,194 +1,194 @@ -/* - * Copyright 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 <string.h> - -#include "stuffer/s2n_stuffer.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_mem.h" - -int s2n_stuffer_peek_char(struct s2n_stuffer *s2n_stuffer, char *c) -{ - int r = s2n_stuffer_read_uint8(s2n_stuffer, (uint8_t *) c); - if (r == S2N_SUCCESS) { - s2n_stuffer->read_cursor--; - } - POSTCONDITION_POSIX(s2n_stuffer_validate(s2n_stuffer)); - return r; -} - -/* Peeks in stuffer to see if expected string is present. */ -int s2n_stuffer_peek_check_for_str(struct s2n_stuffer *s2n_stuffer, const char *expected) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(s2n_stuffer)); - uint32_t orig_read_pos = s2n_stuffer->read_cursor; - int rc = s2n_stuffer_read_expected_str(s2n_stuffer, expected); - s2n_stuffer->read_cursor = orig_read_pos; - POSTCONDITION_POSIX(s2n_stuffer_validate(s2n_stuffer)); - return rc; -} - -int s2n_stuffer_skip_whitespace(struct s2n_stuffer *s2n_stuffer, uint32_t *skipped) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(s2n_stuffer)); - uint32_t initial_read_cursor = s2n_stuffer->read_cursor; - while (s2n_stuffer->read_cursor < s2n_stuffer->write_cursor) { - switch (s2n_stuffer->blob.data[s2n_stuffer->read_cursor]) { - case ' ': /* We don't use isspace, because it changes under locales */ - case '\t': - case '\n': - case '\r': - s2n_stuffer->read_cursor += 1; - break; - default: - goto finished; - } - } - finished: - if(skipped != NULL) *skipped = s2n_stuffer->read_cursor - initial_read_cursor; - POSTCONDITION_POSIX(s2n_stuffer_validate(s2n_stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_read_expected_str(struct s2n_stuffer *stuffer, const char *expected) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - notnull_check(expected); - size_t expected_length = strlen(expected); - if (expected_length == 0) { - return S2N_SUCCESS; - } - ENSURE_POSIX(s2n_stuffer_data_available(stuffer) >= expected_length, S2N_ERR_STUFFER_OUT_OF_DATA); - uint8_t *actual = stuffer->blob.data + stuffer->read_cursor; - notnull_check(actual); - ENSURE_POSIX(!memcmp(actual, expected, expected_length), S2N_ERR_STUFFER_NOT_FOUND); - stuffer->read_cursor += expected_length; - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -/* Read from stuffer until the target string is found, or until there is no more data. */ -int s2n_stuffer_skip_read_until(struct s2n_stuffer *stuffer, const char *target) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - notnull_check(target); - const int len = strlen(target); - if (len == 0) { - return S2N_SUCCESS; - } - while (s2n_stuffer_data_available(stuffer) >= len) { - GUARD(s2n_stuffer_skip_to_char(stuffer, target[0])); - GUARD(s2n_stuffer_skip_read(stuffer, len)); - uint8_t *actual = stuffer->blob.data + stuffer->read_cursor - len; - notnull_check(actual); - - if (strncmp((char*)actual, target, len) == 0){ - return S2N_SUCCESS; - } else { - /* If string doesn't match, rewind stuffer to 1 byte after last read */ - GUARD(s2n_stuffer_rewind_read(stuffer, len - 1)); - continue; - } - } - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -/* Skips the stuffer until the first instance of the target character or until there is no more data. */ -int s2n_stuffer_skip_to_char(struct s2n_stuffer *stuffer, const char target) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - while (s2n_stuffer_data_available(stuffer) > 0) { - if (stuffer->blob.data[stuffer->read_cursor] == target) { - break; - } - stuffer->read_cursor += 1; - } - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -/* Skips an expected character in the stuffer between min and max times */ -int s2n_stuffer_skip_expected_char(struct s2n_stuffer *stuffer, const char expected, const uint32_t min, const uint32_t max, uint32_t *skipped) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - ENSURE_POSIX(min <= max, S2N_ERR_SAFETY); - - uint32_t skip = 0; - while (stuffer->read_cursor < stuffer->write_cursor && skip < max) { - if (stuffer->blob.data[stuffer->read_cursor] == expected){ - stuffer->read_cursor += 1; - skip += 1; - } else { - break; - } - } - ENSURE_POSIX(skip >= min, S2N_ERR_STUFFER_NOT_FOUND); - if(skipped != NULL) *skipped = skip; - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -/* Read a line of text. Agnostic to LF or CR+LF line endings. */ -int s2n_stuffer_read_line(struct s2n_stuffer *stuffer, struct s2n_stuffer *token) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - PRECONDITION_POSIX(s2n_stuffer_validate(token)); - /* Consume an LF terminated line */ - GUARD(s2n_stuffer_read_token(stuffer, token, '\n')); - - /* Snip off the carriage return if it's present */ - if ((s2n_stuffer_data_available(token) > 0) && (token->blob.data[(token->write_cursor - 1)] == '\r')) { - token->write_cursor--; - } - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - POSTCONDITION_POSIX(s2n_stuffer_validate(token)); - return S2N_SUCCESS; -} - -int s2n_stuffer_read_token(struct s2n_stuffer *stuffer, struct s2n_stuffer *token, char delim) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - PRECONDITION_POSIX(s2n_stuffer_validate(token)); - uint32_t token_size = 0; - - while ((stuffer->read_cursor + token_size) < stuffer->write_cursor) { - if (stuffer->blob.data[stuffer->read_cursor + token_size] == delim) { - break; - } - token_size++; - } - - GUARD(s2n_stuffer_copy(stuffer, token, token_size)); - - /* Consume the delimiter too */ - if (stuffer->read_cursor < stuffer->write_cursor) { - stuffer->read_cursor++; - } - - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - POSTCONDITION_POSIX(s2n_stuffer_validate(token)); - return S2N_SUCCESS; -} - -int s2n_stuffer_alloc_ro_from_string(struct s2n_stuffer *stuffer, const char *str) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - notnull_check(str); - uint32_t length = strlen(str); - GUARD(s2n_stuffer_alloc(stuffer, length + 1)); - return s2n_stuffer_write_bytes(stuffer, (const uint8_t *)str, length); -} +/* + * Copyright 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 <string.h> + +#include "stuffer/s2n_stuffer.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_mem.h" + +int s2n_stuffer_peek_char(struct s2n_stuffer *s2n_stuffer, char *c) +{ + int r = s2n_stuffer_read_uint8(s2n_stuffer, (uint8_t *) c); + if (r == S2N_SUCCESS) { + s2n_stuffer->read_cursor--; + } + POSTCONDITION_POSIX(s2n_stuffer_validate(s2n_stuffer)); + return r; +} + +/* Peeks in stuffer to see if expected string is present. */ +int s2n_stuffer_peek_check_for_str(struct s2n_stuffer *s2n_stuffer, const char *expected) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(s2n_stuffer)); + uint32_t orig_read_pos = s2n_stuffer->read_cursor; + int rc = s2n_stuffer_read_expected_str(s2n_stuffer, expected); + s2n_stuffer->read_cursor = orig_read_pos; + POSTCONDITION_POSIX(s2n_stuffer_validate(s2n_stuffer)); + return rc; +} + +int s2n_stuffer_skip_whitespace(struct s2n_stuffer *s2n_stuffer, uint32_t *skipped) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(s2n_stuffer)); + uint32_t initial_read_cursor = s2n_stuffer->read_cursor; + while (s2n_stuffer->read_cursor < s2n_stuffer->write_cursor) { + switch (s2n_stuffer->blob.data[s2n_stuffer->read_cursor]) { + case ' ': /* We don't use isspace, because it changes under locales */ + case '\t': + case '\n': + case '\r': + s2n_stuffer->read_cursor += 1; + break; + default: + goto finished; + } + } + finished: + if(skipped != NULL) *skipped = s2n_stuffer->read_cursor - initial_read_cursor; + POSTCONDITION_POSIX(s2n_stuffer_validate(s2n_stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_read_expected_str(struct s2n_stuffer *stuffer, const char *expected) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + notnull_check(expected); + size_t expected_length = strlen(expected); + if (expected_length == 0) { + return S2N_SUCCESS; + } + ENSURE_POSIX(s2n_stuffer_data_available(stuffer) >= expected_length, S2N_ERR_STUFFER_OUT_OF_DATA); + uint8_t *actual = stuffer->blob.data + stuffer->read_cursor; + notnull_check(actual); + ENSURE_POSIX(!memcmp(actual, expected, expected_length), S2N_ERR_STUFFER_NOT_FOUND); + stuffer->read_cursor += expected_length; + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +/* Read from stuffer until the target string is found, or until there is no more data. */ +int s2n_stuffer_skip_read_until(struct s2n_stuffer *stuffer, const char *target) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + notnull_check(target); + const int len = strlen(target); + if (len == 0) { + return S2N_SUCCESS; + } + while (s2n_stuffer_data_available(stuffer) >= len) { + GUARD(s2n_stuffer_skip_to_char(stuffer, target[0])); + GUARD(s2n_stuffer_skip_read(stuffer, len)); + uint8_t *actual = stuffer->blob.data + stuffer->read_cursor - len; + notnull_check(actual); + + if (strncmp((char*)actual, target, len) == 0){ + return S2N_SUCCESS; + } else { + /* If string doesn't match, rewind stuffer to 1 byte after last read */ + GUARD(s2n_stuffer_rewind_read(stuffer, len - 1)); + continue; + } + } + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +/* Skips the stuffer until the first instance of the target character or until there is no more data. */ +int s2n_stuffer_skip_to_char(struct s2n_stuffer *stuffer, const char target) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + while (s2n_stuffer_data_available(stuffer) > 0) { + if (stuffer->blob.data[stuffer->read_cursor] == target) { + break; + } + stuffer->read_cursor += 1; + } + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +/* Skips an expected character in the stuffer between min and max times */ +int s2n_stuffer_skip_expected_char(struct s2n_stuffer *stuffer, const char expected, const uint32_t min, const uint32_t max, uint32_t *skipped) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + ENSURE_POSIX(min <= max, S2N_ERR_SAFETY); + + uint32_t skip = 0; + while (stuffer->read_cursor < stuffer->write_cursor && skip < max) { + if (stuffer->blob.data[stuffer->read_cursor] == expected){ + stuffer->read_cursor += 1; + skip += 1; + } else { + break; + } + } + ENSURE_POSIX(skip >= min, S2N_ERR_STUFFER_NOT_FOUND); + if(skipped != NULL) *skipped = skip; + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +/* Read a line of text. Agnostic to LF or CR+LF line endings. */ +int s2n_stuffer_read_line(struct s2n_stuffer *stuffer, struct s2n_stuffer *token) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + PRECONDITION_POSIX(s2n_stuffer_validate(token)); + /* Consume an LF terminated line */ + GUARD(s2n_stuffer_read_token(stuffer, token, '\n')); + + /* Snip off the carriage return if it's present */ + if ((s2n_stuffer_data_available(token) > 0) && (token->blob.data[(token->write_cursor - 1)] == '\r')) { + token->write_cursor--; + } + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + POSTCONDITION_POSIX(s2n_stuffer_validate(token)); + return S2N_SUCCESS; +} + +int s2n_stuffer_read_token(struct s2n_stuffer *stuffer, struct s2n_stuffer *token, char delim) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + PRECONDITION_POSIX(s2n_stuffer_validate(token)); + uint32_t token_size = 0; + + while ((stuffer->read_cursor + token_size) < stuffer->write_cursor) { + if (stuffer->blob.data[stuffer->read_cursor + token_size] == delim) { + break; + } + token_size++; + } + + GUARD(s2n_stuffer_copy(stuffer, token, token_size)); + + /* Consume the delimiter too */ + if (stuffer->read_cursor < stuffer->write_cursor) { + stuffer->read_cursor++; + } + + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + POSTCONDITION_POSIX(s2n_stuffer_validate(token)); + return S2N_SUCCESS; +} + +int s2n_stuffer_alloc_ro_from_string(struct s2n_stuffer *stuffer, const char *str) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + notnull_check(str); + uint32_t length = strlen(str); + GUARD(s2n_stuffer_alloc(stuffer, length + 1)); + return s2n_stuffer_write_bytes(stuffer, (const uint8_t *)str, length); +} |