aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:44:49 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:49 +0300
commit718c552901d703c502ccbefdfc3c9028d608b947 (patch)
tree46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c
parente9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff)
downloadydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c')
-rw-r--r--contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c822
1 files changed, 411 insertions, 411 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;
+}