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/utils | |
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/utils')
33 files changed, 3774 insertions, 3774 deletions
diff --git a/contrib/restricted/aws/s2n/utils/s2n_annotations.h b/contrib/restricted/aws/s2n/utils/s2n_annotations.h index 4a004c92a1..245f434d96 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_annotations.h +++ b/contrib/restricted/aws/s2n/utils/s2n_annotations.h @@ -1,19 +1,19 @@ -/* - * 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 - -/* For compilation purposes, these annotations are no-ops */ -#define S2N_PUBLIC_INPUT(__a) -#define S2N_INVARIENT(__a) +/* + * 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 + +/* For compilation purposes, these annotations are no-ops */ +#define S2N_PUBLIC_INPUT(__a) +#define S2N_INVARIENT(__a) diff --git a/contrib/restricted/aws/s2n/utils/s2n_array.c b/contrib/restricted/aws/s2n/utils/s2n_array.c index ecdf9a2cf2..0f4837193c 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_array.c +++ b/contrib/restricted/aws/s2n/utils/s2n_array.c @@ -1,196 +1,196 @@ -/* - * 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 "utils/s2n_blob.h" -#include "utils/s2n_mem.h" -#include "utils/s2n_safety.h" -#include "utils/s2n_array.h" - -S2N_RESULT s2n_array_validate(const struct s2n_array *array) -{ - uint32_t mem_size = 0; - ENSURE_REF(array); - GUARD_RESULT(s2n_blob_validate(&array->mem)); - ENSURE_NE(array->element_size, 0); - GUARD_AS_RESULT(s2n_mul_overflow(array->len, array->element_size, &mem_size)); - ENSURE_GTE(array->mem.size, mem_size); - return S2N_RESULT_OK; -} - -static S2N_RESULT s2n_array_enlarge(struct s2n_array *array, uint32_t capacity) -{ - ENSURE_REF(array); - - /* Acquire the memory */ - uint32_t mem_needed; - GUARD_AS_RESULT(s2n_mul_overflow(array->element_size, capacity, &mem_needed)); - GUARD_AS_RESULT(s2n_realloc(&array->mem, mem_needed)); - - /* Zero the extened part */ - uint32_t array_elements_size; - GUARD_AS_RESULT(s2n_mul_overflow(array->element_size, array->len, &array_elements_size)); - CHECKED_MEMSET(array->mem.data + array_elements_size, 0, array->mem.size - array_elements_size); - GUARD_RESULT(s2n_array_validate(array)); - return S2N_RESULT_OK; -} - -struct s2n_array *s2n_array_new(uint32_t element_size) -{ - struct s2n_blob mem = {0}; - GUARD_PTR(s2n_alloc(&mem, sizeof(struct s2n_array))); - - struct s2n_array *array = (void *) mem.data; - - *array = (struct s2n_array) {.mem = {0}, .len = 0, .element_size = element_size}; - - if (s2n_result_is_error(s2n_array_enlarge(array, S2N_INITIAL_ARRAY_SIZE))) { - /* Avoid memory leak if allocation fails */ - GUARD_PTR(s2n_free(&mem)); - return NULL; - } - return array; -} - -S2N_RESULT s2n_array_init(struct s2n_array *array, uint32_t element_size) -{ - ENSURE_REF(array); - - *array = (struct s2n_array){.element_size = element_size}; - - GUARD_RESULT(s2n_array_validate(array)); - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_array_pushback(struct s2n_array *array, void **element) -{ - GUARD_RESULT(s2n_array_validate(array)); - ENSURE_REF(element); - return s2n_array_insert(array, array->len, element); -} - -S2N_RESULT s2n_array_get(struct s2n_array *array, uint32_t index, void **element) -{ - GUARD_RESULT(s2n_array_validate(array)); - ENSURE_REF(element); - ENSURE(index < array->len, S2N_ERR_ARRAY_INDEX_OOB); - *element = array->mem.data + (array->element_size * index); - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_array_insert_and_copy(struct s2n_array *array, uint32_t index, void* element) -{ - void* insert_location = NULL; - GUARD_RESULT(s2n_array_insert(array, index, &insert_location)); - CHECKED_MEMCPY(insert_location, element, array->element_size); - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_array_insert(struct s2n_array *array, uint32_t index, void **element) -{ - GUARD_RESULT(s2n_array_validate(array)); - ENSURE_REF(element); - /* index == len is ok since we're about to add one element */ - ENSURE(index <= array->len, S2N_ERR_ARRAY_INDEX_OOB); - - /* We are about to add one more element to the array. Add capacity if necessary */ - uint32_t current_capacity = 0; - GUARD_RESULT(s2n_array_capacity(array, ¤t_capacity)); - - if (array->len >= current_capacity) { - /* Enlarge the array */ - uint32_t new_capacity = 0; - GUARD_AS_RESULT(s2n_mul_overflow(current_capacity, 2, &new_capacity)); - new_capacity = MAX(new_capacity, S2N_INITIAL_ARRAY_SIZE); - GUARD_RESULT(s2n_array_enlarge(array, new_capacity)); - } - - /* If we are adding at an existing index, slide everything down. */ - if (index < array->len) { - memmove(array->mem.data + array->element_size * (index + 1), - array->mem.data + array->element_size * index, - (array->len - index) * array->element_size); - } - - *element = array->mem.data + array->element_size * index; - array->len++; - - GUARD_RESULT(s2n_array_validate(array)); - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_array_remove(struct s2n_array *array, uint32_t index) -{ - GUARD_RESULT(s2n_array_validate(array)); - ENSURE(index < array->len, S2N_ERR_ARRAY_INDEX_OOB); - - /* If the removed element is the last one, no need to move anything. - * Otherwise, shift everything down */ - if (index != array->len - 1) { - memmove(array->mem.data + array->element_size * index, - array->mem.data + array->element_size * (index + 1), - (array->len - index - 1) * array->element_size); - } - array->len--; - - /* After shifting, zero the last element */ - CHECKED_MEMSET(array->mem.data + array->element_size * array->len, - 0, - array->element_size); - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_array_num_elements(struct s2n_array *array, uint32_t *len) -{ - GUARD_RESULT(s2n_array_validate(array)); - ENSURE_MUT(len); - - *len = array->len; - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_array_capacity(struct s2n_array *array, uint32_t *capacity) -{ - GUARD_RESULT(s2n_array_validate(array)); - ENSURE_MUT(capacity); - - *capacity = array->mem.size / array->element_size; - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_array_free_p(struct s2n_array **parray) -{ - ENSURE_REF(parray); - struct s2n_array *array = *parray; - - ENSURE_REF(array); - /* Free the elements */ - GUARD_AS_RESULT(s2n_free(&array->mem)); - - /* And finally the array */ - GUARD_AS_RESULT(s2n_free_object((uint8_t **)parray, sizeof(struct s2n_array))); - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_array_free(struct s2n_array *array) -{ - ENSURE_REF(array); - return s2n_array_free_p(&array); -} +/* + * 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 "utils/s2n_blob.h" +#include "utils/s2n_mem.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_array.h" + +S2N_RESULT s2n_array_validate(const struct s2n_array *array) +{ + uint32_t mem_size = 0; + ENSURE_REF(array); + GUARD_RESULT(s2n_blob_validate(&array->mem)); + ENSURE_NE(array->element_size, 0); + GUARD_AS_RESULT(s2n_mul_overflow(array->len, array->element_size, &mem_size)); + ENSURE_GTE(array->mem.size, mem_size); + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_array_enlarge(struct s2n_array *array, uint32_t capacity) +{ + ENSURE_REF(array); + + /* Acquire the memory */ + uint32_t mem_needed; + GUARD_AS_RESULT(s2n_mul_overflow(array->element_size, capacity, &mem_needed)); + GUARD_AS_RESULT(s2n_realloc(&array->mem, mem_needed)); + + /* Zero the extened part */ + uint32_t array_elements_size; + GUARD_AS_RESULT(s2n_mul_overflow(array->element_size, array->len, &array_elements_size)); + CHECKED_MEMSET(array->mem.data + array_elements_size, 0, array->mem.size - array_elements_size); + GUARD_RESULT(s2n_array_validate(array)); + return S2N_RESULT_OK; +} + +struct s2n_array *s2n_array_new(uint32_t element_size) +{ + struct s2n_blob mem = {0}; + GUARD_PTR(s2n_alloc(&mem, sizeof(struct s2n_array))); + + struct s2n_array *array = (void *) mem.data; + + *array = (struct s2n_array) {.mem = {0}, .len = 0, .element_size = element_size}; + + if (s2n_result_is_error(s2n_array_enlarge(array, S2N_INITIAL_ARRAY_SIZE))) { + /* Avoid memory leak if allocation fails */ + GUARD_PTR(s2n_free(&mem)); + return NULL; + } + return array; +} + +S2N_RESULT s2n_array_init(struct s2n_array *array, uint32_t element_size) +{ + ENSURE_REF(array); + + *array = (struct s2n_array){.element_size = element_size}; + + GUARD_RESULT(s2n_array_validate(array)); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_array_pushback(struct s2n_array *array, void **element) +{ + GUARD_RESULT(s2n_array_validate(array)); + ENSURE_REF(element); + return s2n_array_insert(array, array->len, element); +} + +S2N_RESULT s2n_array_get(struct s2n_array *array, uint32_t index, void **element) +{ + GUARD_RESULT(s2n_array_validate(array)); + ENSURE_REF(element); + ENSURE(index < array->len, S2N_ERR_ARRAY_INDEX_OOB); + *element = array->mem.data + (array->element_size * index); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_array_insert_and_copy(struct s2n_array *array, uint32_t index, void* element) +{ + void* insert_location = NULL; + GUARD_RESULT(s2n_array_insert(array, index, &insert_location)); + CHECKED_MEMCPY(insert_location, element, array->element_size); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_array_insert(struct s2n_array *array, uint32_t index, void **element) +{ + GUARD_RESULT(s2n_array_validate(array)); + ENSURE_REF(element); + /* index == len is ok since we're about to add one element */ + ENSURE(index <= array->len, S2N_ERR_ARRAY_INDEX_OOB); + + /* We are about to add one more element to the array. Add capacity if necessary */ + uint32_t current_capacity = 0; + GUARD_RESULT(s2n_array_capacity(array, ¤t_capacity)); + + if (array->len >= current_capacity) { + /* Enlarge the array */ + uint32_t new_capacity = 0; + GUARD_AS_RESULT(s2n_mul_overflow(current_capacity, 2, &new_capacity)); + new_capacity = MAX(new_capacity, S2N_INITIAL_ARRAY_SIZE); + GUARD_RESULT(s2n_array_enlarge(array, new_capacity)); + } + + /* If we are adding at an existing index, slide everything down. */ + if (index < array->len) { + memmove(array->mem.data + array->element_size * (index + 1), + array->mem.data + array->element_size * index, + (array->len - index) * array->element_size); + } + + *element = array->mem.data + array->element_size * index; + array->len++; + + GUARD_RESULT(s2n_array_validate(array)); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_array_remove(struct s2n_array *array, uint32_t index) +{ + GUARD_RESULT(s2n_array_validate(array)); + ENSURE(index < array->len, S2N_ERR_ARRAY_INDEX_OOB); + + /* If the removed element is the last one, no need to move anything. + * Otherwise, shift everything down */ + if (index != array->len - 1) { + memmove(array->mem.data + array->element_size * index, + array->mem.data + array->element_size * (index + 1), + (array->len - index - 1) * array->element_size); + } + array->len--; + + /* After shifting, zero the last element */ + CHECKED_MEMSET(array->mem.data + array->element_size * array->len, + 0, + array->element_size); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_array_num_elements(struct s2n_array *array, uint32_t *len) +{ + GUARD_RESULT(s2n_array_validate(array)); + ENSURE_MUT(len); + + *len = array->len; + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_array_capacity(struct s2n_array *array, uint32_t *capacity) +{ + GUARD_RESULT(s2n_array_validate(array)); + ENSURE_MUT(capacity); + + *capacity = array->mem.size / array->element_size; + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_array_free_p(struct s2n_array **parray) +{ + ENSURE_REF(parray); + struct s2n_array *array = *parray; + + ENSURE_REF(array); + /* Free the elements */ + GUARD_AS_RESULT(s2n_free(&array->mem)); + + /* And finally the array */ + GUARD_AS_RESULT(s2n_free_object((uint8_t **)parray, sizeof(struct s2n_array))); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_array_free(struct s2n_array *array) +{ + ENSURE_REF(array); + return s2n_array_free_p(&array); +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_array.h b/contrib/restricted/aws/s2n/utils/s2n_array.h index 3ae0996948..bf48b3aaac 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_array.h +++ b/contrib/restricted/aws/s2n/utils/s2n_array.h @@ -1,45 +1,45 @@ -/* - * 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 <s2n.h> -#include "utils/s2n_blob.h" -#include "utils/s2n_result.h" - -#define S2N_INITIAL_ARRAY_SIZE 16 - -struct s2n_array { - /* Pointer to elements in array */ - struct s2n_blob mem; - - /* The total number of elements currently in the array. */ - uint32_t len; - - /* The size of each element in the array */ - uint32_t element_size; -}; - -extern S2N_RESULT s2n_array_validate(const struct s2n_array *array); -extern struct s2n_array *s2n_array_new(uint32_t element_size); -extern S2N_RESULT s2n_array_init(struct s2n_array *array, uint32_t element_size); -extern S2N_RESULT s2n_array_pushback(struct s2n_array *array, void **element); -extern S2N_RESULT s2n_array_get(struct s2n_array *array, uint32_t index, void **element); -extern S2N_RESULT s2n_array_insert(struct s2n_array *array, uint32_t index, void **element); -extern S2N_RESULT s2n_array_insert_and_copy(struct s2n_array *array, uint32_t index, void *element); -extern S2N_RESULT s2n_array_num_elements(struct s2n_array *array, uint32_t *len); -extern S2N_RESULT s2n_array_capacity(struct s2n_array *array, uint32_t *capacity); -extern S2N_RESULT s2n_array_remove(struct s2n_array *array, uint32_t index); -extern S2N_RESULT s2n_array_free_p(struct s2n_array **parray); -extern S2N_RESULT s2n_array_free(struct s2n_array *array); +/* + * 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 <s2n.h> +#include "utils/s2n_blob.h" +#include "utils/s2n_result.h" + +#define S2N_INITIAL_ARRAY_SIZE 16 + +struct s2n_array { + /* Pointer to elements in array */ + struct s2n_blob mem; + + /* The total number of elements currently in the array. */ + uint32_t len; + + /* The size of each element in the array */ + uint32_t element_size; +}; + +extern S2N_RESULT s2n_array_validate(const struct s2n_array *array); +extern struct s2n_array *s2n_array_new(uint32_t element_size); +extern S2N_RESULT s2n_array_init(struct s2n_array *array, uint32_t element_size); +extern S2N_RESULT s2n_array_pushback(struct s2n_array *array, void **element); +extern S2N_RESULT s2n_array_get(struct s2n_array *array, uint32_t index, void **element); +extern S2N_RESULT s2n_array_insert(struct s2n_array *array, uint32_t index, void **element); +extern S2N_RESULT s2n_array_insert_and_copy(struct s2n_array *array, uint32_t index, void *element); +extern S2N_RESULT s2n_array_num_elements(struct s2n_array *array, uint32_t *len); +extern S2N_RESULT s2n_array_capacity(struct s2n_array *array, uint32_t *capacity); +extern S2N_RESULT s2n_array_remove(struct s2n_array *array, uint32_t index); +extern S2N_RESULT s2n_array_free_p(struct s2n_array **parray); +extern S2N_RESULT s2n_array_free(struct s2n_array *array); diff --git a/contrib/restricted/aws/s2n/utils/s2n_asn1_time.c b/contrib/restricted/aws/s2n/utils/s2n_asn1_time.c index 01b7acceb1..3acaaa41f5 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_asn1_time.c +++ b/contrib/restricted/aws/s2n/utils/s2n_asn1_time.c @@ -1,289 +1,289 @@ -/* - * 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 "utils/s2n_asn1_time.h" -#include "utils/s2n_result.h" -#include "utils/s2n_safety.h" - -#include <time.h> -#include <ctype.h> - -typedef enum parser_state { - ON_YEAR_DIGIT_1 = 0, - ON_YEAR_DIGIT_2, - ON_YEAR_DIGIT_3, - ON_YEAR_DIGIT_4, - ON_MONTH_DIGIT_1, - ON_MONTH_DIGIT_2, - ON_DAY_DIGIT_1, - ON_DAY_DIGIT_2, - ON_HOUR_DIGIT_1, - ON_HOUR_DIGIT_2, - ON_MINUTE_DIGIT_1, - ON_MINUTE_DIGIT_2, - ON_SECOND_DIGIT_1, - ON_SECOND_DIGIT_2, - ON_SUBSECOND, - ON_TIMEZONE, - ON_OFFSET_HOURS_DIGIT_1, - ON_OFFSET_HOURS_DIGIT_2, - ON_OFFSET_MINUTES_DIGIT_1, - ON_OFFSET_MINUTES_DIGIT_2, - FINISHED, - PARSE_ERROR -} parser_state; - -static inline long get_gmt_offset(struct tm *t) { -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__ANDROID__) || defined(ANDROID) || defined(__APPLE__) && defined(__MACH__) - return t->tm_gmtoff; -#else - return t->tm_gmtoff; -#endif -} - -static inline void get_current_timesettings(long *gmt_offset, int *is_dst) { - struct tm time_ptr = {0}; - time_t raw_time; - time(&raw_time); - localtime_r(&raw_time, &time_ptr); - *gmt_offset = get_gmt_offset(&time_ptr); - *is_dst = time_ptr.tm_isdst; -} - -#define PARSE_DIGIT(c, d) do { ENSURE(isdigit(c), S2N_ERR_SAFETY); d = c - '0'; } while(0) - -/* this is just a standard state machine for ASN1 date format... nothing special. - * just do a character at a time and change the state per character encountered. - * when finished the above time structure should be filled in along with some - * crazy timezone info we'll need shortly afterwards.*/ -static S2N_RESULT process_state(parser_state *state, char current_char, struct parser_args *args) { - switch (*state) { - case ON_YEAR_DIGIT_1: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_year = args->current_digit; - *state = ON_YEAR_DIGIT_2; - return S2N_RESULT_OK; - case ON_YEAR_DIGIT_2: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_year = args->time.tm_year * 10 + args->current_digit; - *state = ON_YEAR_DIGIT_3; - return S2N_RESULT_OK; - case ON_YEAR_DIGIT_3: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_year = args->time.tm_year * 10 + args->current_digit; - *state = ON_YEAR_DIGIT_4; - return S2N_RESULT_OK; - case ON_YEAR_DIGIT_4: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_year = args->time.tm_year * 10 + args->current_digit; - args->time.tm_year -= 1900; - if (args->time.tm_year < 0) { - return S2N_RESULT_ERROR; - } - - *state = ON_MONTH_DIGIT_1; - return S2N_RESULT_OK; - case ON_MONTH_DIGIT_1: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_mon = args->current_digit; - *state = ON_MONTH_DIGIT_2; - return S2N_RESULT_OK; - case ON_MONTH_DIGIT_2: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_mon = args->time.tm_mon * 10 + args->current_digit; - args->time.tm_mon -= 1; - - if (args->time.tm_mon < 0 || args->time.tm_mon > 11) { - return S2N_RESULT_ERROR; - } - - *state = ON_DAY_DIGIT_1; - return S2N_RESULT_OK; - case ON_DAY_DIGIT_1: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_mday = args->current_digit; - *state = ON_DAY_DIGIT_2; - return S2N_RESULT_OK; - case ON_DAY_DIGIT_2: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_mday = args->time.tm_mday * 10 + args->current_digit; - - if (args->time.tm_mday < 0 || args->time.tm_mday > 31) { - return S2N_RESULT_ERROR; - } - - *state = ON_HOUR_DIGIT_1; - return S2N_RESULT_OK; - case ON_HOUR_DIGIT_1: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_hour = args->current_digit; - *state = ON_HOUR_DIGIT_2; - return S2N_RESULT_OK; - case ON_HOUR_DIGIT_2: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_hour = args->time.tm_hour * 10 + args->current_digit; - - if (args->time.tm_hour < 0 || args->time.tm_hour > 23) { - return S2N_RESULT_ERROR; - } - - *state = ON_MINUTE_DIGIT_1; - return S2N_RESULT_OK; - case ON_MINUTE_DIGIT_1: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_min = args->current_digit; - *state = ON_MINUTE_DIGIT_2; - return S2N_RESULT_OK; - case ON_MINUTE_DIGIT_2: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_min = args->time.tm_min * 10 + args->current_digit; - - if (args->time.tm_min < 0 || args->time.tm_min > 59) { - return S2N_RESULT_ERROR; - } - - *state = ON_SECOND_DIGIT_1; - return S2N_RESULT_OK; - case ON_SECOND_DIGIT_1: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_sec = args->current_digit; - *state = ON_SECOND_DIGIT_2; - return S2N_RESULT_OK; - case ON_SECOND_DIGIT_2: - PARSE_DIGIT(current_char, args->current_digit); - args->time.tm_sec = args->time.tm_sec * 10 + args->current_digit; - - if (args->time.tm_sec < 0 || args->time.tm_sec > 59) { - return S2N_RESULT_ERROR; - } - - *state = ON_SUBSECOND; - return S2N_RESULT_OK; - case ON_SUBSECOND: - if (current_char == '.' || isdigit(current_char)) { - *state = ON_SUBSECOND; - return S2N_RESULT_OK; - } - FALL_THROUGH; - case ON_TIMEZONE: - if (current_char == 'Z' || current_char == 'z') { - args->local_time_assumed = 0; - *state = FINISHED; - return S2N_RESULT_OK; - } else if (current_char == '-') { - args->local_time_assumed = 0; - args->offset_negative = 1; - *state = ON_OFFSET_HOURS_DIGIT_1; - return S2N_RESULT_OK; - } else if (current_char == '+') { - args->local_time_assumed = 0; - args->offset_negative = 0; - *state = ON_OFFSET_HOURS_DIGIT_1; - return S2N_RESULT_OK; - } - - return S2N_RESULT_ERROR; - case ON_OFFSET_HOURS_DIGIT_1: - PARSE_DIGIT(current_char, args->current_digit); - args->offset_hours = args->current_digit; - *state = ON_OFFSET_HOURS_DIGIT_2; - return S2N_RESULT_OK; - case ON_OFFSET_HOURS_DIGIT_2: - PARSE_DIGIT(current_char, args->current_digit); - args->offset_hours = args->offset_hours * 10 + args->current_digit; - - if (args->offset_hours < 0 || args->offset_hours > 23) { - return S2N_RESULT_ERROR; - } - - *state = ON_OFFSET_MINUTES_DIGIT_1; - return S2N_RESULT_OK; - case ON_OFFSET_MINUTES_DIGIT_1: - PARSE_DIGIT(current_char, args->current_digit); - args->offset_minutes = args->current_digit; - *state = ON_OFFSET_MINUTES_DIGIT_2; - return S2N_RESULT_OK; - case ON_OFFSET_MINUTES_DIGIT_2: - PARSE_DIGIT(current_char, args->current_digit); - args->offset_minutes = args->offset_minutes * 10 + args->current_digit; - - if (args->offset_minutes < 0 || args->offset_minutes > 23) { - return S2N_RESULT_ERROR; - } - - *state = FINISHED; - return S2N_RESULT_OK; - default: - return S2N_RESULT_ERROR; - } -} - -S2N_RESULT s2n_asn1_time_to_nano_since_epoch_ticks(const char *asn1_time, uint32_t len, uint64_t *ticks) { - - /* figure out if we are on something other than UTC since timegm is not supported everywhere. */ - long gmt_offset_current = 0; - int is_dst = 0; - get_current_timesettings(&gmt_offset_current, &is_dst); - - uint32_t str_len = len; - parser_state state = ON_YEAR_DIGIT_1; - - struct parser_args args = { - .time = {.tm_hour = 0, .tm_isdst = -1, .tm_mday = 0, .tm_min = 0, .tm_mon = 0, - .tm_sec = 0, .tm_wday = 0, .tm_yday = 0, .tm_year = 0, - }, - .current_digit = 0, - .local_time_assumed = 1, - .offset_hours = 0, - .offset_minutes = 0, - .offset_negative = 0 - }; - - size_t current_pos = 0; - - while (state < FINISHED && current_pos < str_len) { - char current_char = asn1_time[current_pos]; - ENSURE_OK(process_state(&state, current_char, &args), S2N_ERR_INVALID_ARGUMENT); - current_pos++; - } - - /* state on subsecond means no timezone info was found and we assume local time */ - ENSURE(state == FINISHED || state == ON_SUBSECOND, S2N_ERR_INVALID_ARGUMENT); - - time_t clock_data = mktime(&args.time); - ENSURE_GTE(clock_data, 0); - - /* ASN1 + and - is in format HHMM. We need to convert it to seconds for the adjustment */ - long gmt_offset = (args.offset_hours * 3600) + (args.offset_minutes * 60); - - if (args.offset_negative) { - gmt_offset = 0 - gmt_offset; - } - - /* if we detected UTC is being used (please always use UTC), we need to add the detected timezone on the local - * machine back to the offset. Also, the offset includes an offset for daylight savings time. When the time being parsed - * and the local time are on different sides of the dst barrier, the offset has to be adjusted to account for it. */ - if (!args.local_time_assumed) { - gmt_offset -= gmt_offset_current; - gmt_offset -= args.time.tm_isdst != is_dst ? (args.time.tm_isdst - is_dst) * 3600 : 0; - } - - ENSURE_GTE(clock_data, gmt_offset); - - /* convert to nanoseconds and add the timezone offset. */ - *ticks = ((uint64_t) clock_data - gmt_offset) * 1000000000; - return S2N_RESULT_OK; -} - +/* + * 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 "utils/s2n_asn1_time.h" +#include "utils/s2n_result.h" +#include "utils/s2n_safety.h" + +#include <time.h> +#include <ctype.h> + +typedef enum parser_state { + ON_YEAR_DIGIT_1 = 0, + ON_YEAR_DIGIT_2, + ON_YEAR_DIGIT_3, + ON_YEAR_DIGIT_4, + ON_MONTH_DIGIT_1, + ON_MONTH_DIGIT_2, + ON_DAY_DIGIT_1, + ON_DAY_DIGIT_2, + ON_HOUR_DIGIT_1, + ON_HOUR_DIGIT_2, + ON_MINUTE_DIGIT_1, + ON_MINUTE_DIGIT_2, + ON_SECOND_DIGIT_1, + ON_SECOND_DIGIT_2, + ON_SUBSECOND, + ON_TIMEZONE, + ON_OFFSET_HOURS_DIGIT_1, + ON_OFFSET_HOURS_DIGIT_2, + ON_OFFSET_MINUTES_DIGIT_1, + ON_OFFSET_MINUTES_DIGIT_2, + FINISHED, + PARSE_ERROR +} parser_state; + +static inline long get_gmt_offset(struct tm *t) { +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__ANDROID__) || defined(ANDROID) || defined(__APPLE__) && defined(__MACH__) + return t->tm_gmtoff; +#else + return t->tm_gmtoff; +#endif +} + +static inline void get_current_timesettings(long *gmt_offset, int *is_dst) { + struct tm time_ptr = {0}; + time_t raw_time; + time(&raw_time); + localtime_r(&raw_time, &time_ptr); + *gmt_offset = get_gmt_offset(&time_ptr); + *is_dst = time_ptr.tm_isdst; +} + +#define PARSE_DIGIT(c, d) do { ENSURE(isdigit(c), S2N_ERR_SAFETY); d = c - '0'; } while(0) + +/* this is just a standard state machine for ASN1 date format... nothing special. + * just do a character at a time and change the state per character encountered. + * when finished the above time structure should be filled in along with some + * crazy timezone info we'll need shortly afterwards.*/ +static S2N_RESULT process_state(parser_state *state, char current_char, struct parser_args *args) { + switch (*state) { + case ON_YEAR_DIGIT_1: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_year = args->current_digit; + *state = ON_YEAR_DIGIT_2; + return S2N_RESULT_OK; + case ON_YEAR_DIGIT_2: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_year = args->time.tm_year * 10 + args->current_digit; + *state = ON_YEAR_DIGIT_3; + return S2N_RESULT_OK; + case ON_YEAR_DIGIT_3: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_year = args->time.tm_year * 10 + args->current_digit; + *state = ON_YEAR_DIGIT_4; + return S2N_RESULT_OK; + case ON_YEAR_DIGIT_4: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_year = args->time.tm_year * 10 + args->current_digit; + args->time.tm_year -= 1900; + if (args->time.tm_year < 0) { + return S2N_RESULT_ERROR; + } + + *state = ON_MONTH_DIGIT_1; + return S2N_RESULT_OK; + case ON_MONTH_DIGIT_1: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_mon = args->current_digit; + *state = ON_MONTH_DIGIT_2; + return S2N_RESULT_OK; + case ON_MONTH_DIGIT_2: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_mon = args->time.tm_mon * 10 + args->current_digit; + args->time.tm_mon -= 1; + + if (args->time.tm_mon < 0 || args->time.tm_mon > 11) { + return S2N_RESULT_ERROR; + } + + *state = ON_DAY_DIGIT_1; + return S2N_RESULT_OK; + case ON_DAY_DIGIT_1: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_mday = args->current_digit; + *state = ON_DAY_DIGIT_2; + return S2N_RESULT_OK; + case ON_DAY_DIGIT_2: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_mday = args->time.tm_mday * 10 + args->current_digit; + + if (args->time.tm_mday < 0 || args->time.tm_mday > 31) { + return S2N_RESULT_ERROR; + } + + *state = ON_HOUR_DIGIT_1; + return S2N_RESULT_OK; + case ON_HOUR_DIGIT_1: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_hour = args->current_digit; + *state = ON_HOUR_DIGIT_2; + return S2N_RESULT_OK; + case ON_HOUR_DIGIT_2: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_hour = args->time.tm_hour * 10 + args->current_digit; + + if (args->time.tm_hour < 0 || args->time.tm_hour > 23) { + return S2N_RESULT_ERROR; + } + + *state = ON_MINUTE_DIGIT_1; + return S2N_RESULT_OK; + case ON_MINUTE_DIGIT_1: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_min = args->current_digit; + *state = ON_MINUTE_DIGIT_2; + return S2N_RESULT_OK; + case ON_MINUTE_DIGIT_2: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_min = args->time.tm_min * 10 + args->current_digit; + + if (args->time.tm_min < 0 || args->time.tm_min > 59) { + return S2N_RESULT_ERROR; + } + + *state = ON_SECOND_DIGIT_1; + return S2N_RESULT_OK; + case ON_SECOND_DIGIT_1: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_sec = args->current_digit; + *state = ON_SECOND_DIGIT_2; + return S2N_RESULT_OK; + case ON_SECOND_DIGIT_2: + PARSE_DIGIT(current_char, args->current_digit); + args->time.tm_sec = args->time.tm_sec * 10 + args->current_digit; + + if (args->time.tm_sec < 0 || args->time.tm_sec > 59) { + return S2N_RESULT_ERROR; + } + + *state = ON_SUBSECOND; + return S2N_RESULT_OK; + case ON_SUBSECOND: + if (current_char == '.' || isdigit(current_char)) { + *state = ON_SUBSECOND; + return S2N_RESULT_OK; + } + FALL_THROUGH; + case ON_TIMEZONE: + if (current_char == 'Z' || current_char == 'z') { + args->local_time_assumed = 0; + *state = FINISHED; + return S2N_RESULT_OK; + } else if (current_char == '-') { + args->local_time_assumed = 0; + args->offset_negative = 1; + *state = ON_OFFSET_HOURS_DIGIT_1; + return S2N_RESULT_OK; + } else if (current_char == '+') { + args->local_time_assumed = 0; + args->offset_negative = 0; + *state = ON_OFFSET_HOURS_DIGIT_1; + return S2N_RESULT_OK; + } + + return S2N_RESULT_ERROR; + case ON_OFFSET_HOURS_DIGIT_1: + PARSE_DIGIT(current_char, args->current_digit); + args->offset_hours = args->current_digit; + *state = ON_OFFSET_HOURS_DIGIT_2; + return S2N_RESULT_OK; + case ON_OFFSET_HOURS_DIGIT_2: + PARSE_DIGIT(current_char, args->current_digit); + args->offset_hours = args->offset_hours * 10 + args->current_digit; + + if (args->offset_hours < 0 || args->offset_hours > 23) { + return S2N_RESULT_ERROR; + } + + *state = ON_OFFSET_MINUTES_DIGIT_1; + return S2N_RESULT_OK; + case ON_OFFSET_MINUTES_DIGIT_1: + PARSE_DIGIT(current_char, args->current_digit); + args->offset_minutes = args->current_digit; + *state = ON_OFFSET_MINUTES_DIGIT_2; + return S2N_RESULT_OK; + case ON_OFFSET_MINUTES_DIGIT_2: + PARSE_DIGIT(current_char, args->current_digit); + args->offset_minutes = args->offset_minutes * 10 + args->current_digit; + + if (args->offset_minutes < 0 || args->offset_minutes > 23) { + return S2N_RESULT_ERROR; + } + + *state = FINISHED; + return S2N_RESULT_OK; + default: + return S2N_RESULT_ERROR; + } +} + +S2N_RESULT s2n_asn1_time_to_nano_since_epoch_ticks(const char *asn1_time, uint32_t len, uint64_t *ticks) { + + /* figure out if we are on something other than UTC since timegm is not supported everywhere. */ + long gmt_offset_current = 0; + int is_dst = 0; + get_current_timesettings(&gmt_offset_current, &is_dst); + + uint32_t str_len = len; + parser_state state = ON_YEAR_DIGIT_1; + + struct parser_args args = { + .time = {.tm_hour = 0, .tm_isdst = -1, .tm_mday = 0, .tm_min = 0, .tm_mon = 0, + .tm_sec = 0, .tm_wday = 0, .tm_yday = 0, .tm_year = 0, + }, + .current_digit = 0, + .local_time_assumed = 1, + .offset_hours = 0, + .offset_minutes = 0, + .offset_negative = 0 + }; + + size_t current_pos = 0; + + while (state < FINISHED && current_pos < str_len) { + char current_char = asn1_time[current_pos]; + ENSURE_OK(process_state(&state, current_char, &args), S2N_ERR_INVALID_ARGUMENT); + current_pos++; + } + + /* state on subsecond means no timezone info was found and we assume local time */ + ENSURE(state == FINISHED || state == ON_SUBSECOND, S2N_ERR_INVALID_ARGUMENT); + + time_t clock_data = mktime(&args.time); + ENSURE_GTE(clock_data, 0); + + /* ASN1 + and - is in format HHMM. We need to convert it to seconds for the adjustment */ + long gmt_offset = (args.offset_hours * 3600) + (args.offset_minutes * 60); + + if (args.offset_negative) { + gmt_offset = 0 - gmt_offset; + } + + /* if we detected UTC is being used (please always use UTC), we need to add the detected timezone on the local + * machine back to the offset. Also, the offset includes an offset for daylight savings time. When the time being parsed + * and the local time are on different sides of the dst barrier, the offset has to be adjusted to account for it. */ + if (!args.local_time_assumed) { + gmt_offset -= gmt_offset_current; + gmt_offset -= args.time.tm_isdst != is_dst ? (args.time.tm_isdst - is_dst) * 3600 : 0; + } + + ENSURE_GTE(clock_data, gmt_offset); + + /* convert to nanoseconds and add the timezone offset. */ + *ticks = ((uint64_t) clock_data - gmt_offset) * 1000000000; + return S2N_RESULT_OK; +} + diff --git a/contrib/restricted/aws/s2n/utils/s2n_asn1_time.h b/contrib/restricted/aws/s2n/utils/s2n_asn1_time.h index e7f88a81b4..73318b28b1 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_asn1_time.h +++ b/contrib/restricted/aws/s2n/utils/s2n_asn1_time.h @@ -1,37 +1,37 @@ -/* - * 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 <stdint.h> -#include <time.h> - -#include "utils/s2n_result.h" - -struct parser_args { - uint8_t offset_negative; - uint8_t local_time_assumed; - uint8_t current_digit; - long offset_hours; - long offset_minutes; - struct tm time; -}; - -/** - * Converts an asn1 formatted time string to ticks since epoch in nanoseconds. - * ticks is an output parameter. Returns 0 on success and -1 on failure. - */ -S2N_RESULT s2n_asn1_time_to_nano_since_epoch_ticks(const char *asn1_time, uint32_t len, uint64_t *ticks); - +/* + * 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 <stdint.h> +#include <time.h> + +#include "utils/s2n_result.h" + +struct parser_args { + uint8_t offset_negative; + uint8_t local_time_assumed; + uint8_t current_digit; + long offset_hours; + long offset_minutes; + struct tm time; +}; + +/** + * Converts an asn1 formatted time string to ticks since epoch in nanoseconds. + * ticks is an output parameter. Returns 0 on success and -1 on failure. + */ +S2N_RESULT s2n_asn1_time_to_nano_since_epoch_ticks(const char *asn1_time, uint32_t len, uint64_t *ticks); + diff --git a/contrib/restricted/aws/s2n/utils/s2n_bitmap.h b/contrib/restricted/aws/s2n/utils/s2n_bitmap.h index f13a7fd911..9ee892fc14 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_bitmap.h +++ b/contrib/restricted/aws/s2n/utils/s2n_bitmap.h @@ -1,22 +1,22 @@ -/* - * 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 - -/* bit operations on a char[] mask of arbitrary length */ -#define S2N_CBIT_BIT(bit) (1 << ((bit) % 8)) -#define S2N_CBIT_BIN(mask, bit) (mask)[(bit) >> 3] -#define S2N_CBIT_SET(mask, bit) ((void)(S2N_CBIT_BIN(mask, bit) |= S2N_CBIT_BIT(bit))) -#define S2N_CBIT_CLR(mask, bit) ((void)(S2N_CBIT_BIN(mask, bit) &= ~S2N_CBIT_BIT(bit))) -#define S2N_CBIT_TEST(mask, bit) ((S2N_CBIT_BIN(mask, bit) & S2N_CBIT_BIT(bit)) != 0) +/* + * 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 + +/* bit operations on a char[] mask of arbitrary length */ +#define S2N_CBIT_BIT(bit) (1 << ((bit) % 8)) +#define S2N_CBIT_BIN(mask, bit) (mask)[(bit) >> 3] +#define S2N_CBIT_SET(mask, bit) ((void)(S2N_CBIT_BIN(mask, bit) |= S2N_CBIT_BIT(bit))) +#define S2N_CBIT_CLR(mask, bit) ((void)(S2N_CBIT_BIN(mask, bit) &= ~S2N_CBIT_BIT(bit))) +#define S2N_CBIT_TEST(mask, bit) ((S2N_CBIT_BIN(mask, bit) & S2N_CBIT_BIT(bit)) != 0) diff --git a/contrib/restricted/aws/s2n/utils/s2n_blob.c b/contrib/restricted/aws/s2n/utils/s2n_blob.c index 649fb55c0d..0704f730a3 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_blob.c +++ b/contrib/restricted/aws/s2n/utils/s2n_blob.c @@ -1,126 +1,126 @@ -/* - * 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 <ctype.h> -#include <sys/param.h> - -#include "error/s2n_errno.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" - -#include <s2n.h> - -S2N_RESULT s2n_blob_validate(const struct s2n_blob* b) -{ - ENSURE_REF(b); - DEBUG_ENSURE(S2N_IMPLIES(b->data == NULL, b->size == 0), S2N_ERR_SAFETY); - DEBUG_ENSURE(S2N_IMPLIES(b->data == NULL, b->allocated == 0), S2N_ERR_SAFETY); - DEBUG_ENSURE(S2N_IMPLIES(b->growable == 0, b->allocated == 0), S2N_ERR_SAFETY); - DEBUG_ENSURE(S2N_IMPLIES(b->growable != 0, b->size <= b->allocated), S2N_ERR_SAFETY); - DEBUG_ENSURE(S2N_MEM_IS_READABLE(b->data, b->allocated), S2N_ERR_SAFETY); - DEBUG_ENSURE(S2N_MEM_IS_READABLE(b->data, b->size), S2N_ERR_SAFETY); - return S2N_RESULT_OK; -} - -int s2n_blob_init(struct s2n_blob *b, uint8_t * data, uint32_t size) -{ - ENSURE_POSIX_REF(b); - ENSURE_POSIX(S2N_MEM_IS_READABLE(data, size), S2N_ERR_SAFETY); - *b = (struct s2n_blob) {.data = data, .size = size, .allocated = 0, .growable = 0}; - POSTCONDITION_POSIX(s2n_blob_validate(b)); - return S2N_SUCCESS; -} - -int s2n_blob_zero(struct s2n_blob *b) -{ - PRECONDITION_POSIX(s2n_blob_validate(b)); - memset_check(b->data, 0, MAX(b->allocated, b->size)); - POSTCONDITION_POSIX(s2n_blob_validate(b)); - return S2N_SUCCESS; -} - -int s2n_blob_slice(const struct s2n_blob *b, struct s2n_blob *slice, uint32_t offset, uint32_t size) -{ - PRECONDITION_POSIX(s2n_blob_validate(b)); - PRECONDITION_POSIX(s2n_blob_validate(slice)); - - uint32_t slice_size = 0; - GUARD(s2n_add_overflow(offset, size, &slice_size)); - ENSURE_POSIX(b->size >= slice_size, S2N_ERR_SIZE_MISMATCH); - slice->data = b->data + offset; - slice->size = size; - slice->growable = 0; - slice->allocated = 0; - - POSTCONDITION_POSIX(s2n_blob_validate(slice)); - return S2N_SUCCESS; -} - -int s2n_blob_char_to_lower(struct s2n_blob *b) -{ - PRECONDITION_POSIX(s2n_blob_validate(b)); - for (size_t i = 0; i < b->size; i++) { - b->data[i] = tolower(b->data[i]); - } - POSTCONDITION_POSIX(s2n_blob_validate(b)); - return S2N_SUCCESS; -} - -/* An inverse map from an ascii value to a hexidecimal nibble value - * accounts for all possible char values, where 255 is invalid value */ -static const uint8_t hex_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, 255, 255, 255, 255, 255, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 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, 10, 11, 12, 13, 14, 15, 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, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 -}; - -/* takes a hex string and writes values in the s2n_blob - * string needs to a valid hex and blob needs to be large enough */ -int s2n_hex_string_to_bytes(const uint8_t *str, struct s2n_blob *blob) -{ - ENSURE_POSIX_REF(str); - PRECONDITION_POSIX(s2n_blob_validate(blob)); - uint32_t len = strlen((const char*)str); - /* protects against overflows */ - gte_check(blob->size, len / 2); - S2N_ERROR_IF(len % 2 != 0, S2N_ERR_INVALID_HEX); - - for (size_t i = 0; i < len; i += 2) { - uint8_t high_nibble = hex_inverse[str[i]]; - S2N_ERROR_IF(high_nibble == 255, S2N_ERR_INVALID_HEX); - - uint8_t low_nibble = hex_inverse[str[i + 1]]; - S2N_ERROR_IF(low_nibble == 255, S2N_ERR_INVALID_HEX); - blob->data[i / 2] = high_nibble << 4 | low_nibble; - } - - POSTCONDITION_POSIX(s2n_blob_validate(blob)); - 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 <ctype.h> +#include <sys/param.h> + +#include "error/s2n_errno.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" + +#include <s2n.h> + +S2N_RESULT s2n_blob_validate(const struct s2n_blob* b) +{ + ENSURE_REF(b); + DEBUG_ENSURE(S2N_IMPLIES(b->data == NULL, b->size == 0), S2N_ERR_SAFETY); + DEBUG_ENSURE(S2N_IMPLIES(b->data == NULL, b->allocated == 0), S2N_ERR_SAFETY); + DEBUG_ENSURE(S2N_IMPLIES(b->growable == 0, b->allocated == 0), S2N_ERR_SAFETY); + DEBUG_ENSURE(S2N_IMPLIES(b->growable != 0, b->size <= b->allocated), S2N_ERR_SAFETY); + DEBUG_ENSURE(S2N_MEM_IS_READABLE(b->data, b->allocated), S2N_ERR_SAFETY); + DEBUG_ENSURE(S2N_MEM_IS_READABLE(b->data, b->size), S2N_ERR_SAFETY); + return S2N_RESULT_OK; +} + +int s2n_blob_init(struct s2n_blob *b, uint8_t * data, uint32_t size) +{ + ENSURE_POSIX_REF(b); + ENSURE_POSIX(S2N_MEM_IS_READABLE(data, size), S2N_ERR_SAFETY); + *b = (struct s2n_blob) {.data = data, .size = size, .allocated = 0, .growable = 0}; + POSTCONDITION_POSIX(s2n_blob_validate(b)); + return S2N_SUCCESS; +} + +int s2n_blob_zero(struct s2n_blob *b) +{ + PRECONDITION_POSIX(s2n_blob_validate(b)); + memset_check(b->data, 0, MAX(b->allocated, b->size)); + POSTCONDITION_POSIX(s2n_blob_validate(b)); + return S2N_SUCCESS; +} + +int s2n_blob_slice(const struct s2n_blob *b, struct s2n_blob *slice, uint32_t offset, uint32_t size) +{ + PRECONDITION_POSIX(s2n_blob_validate(b)); + PRECONDITION_POSIX(s2n_blob_validate(slice)); + + uint32_t slice_size = 0; + GUARD(s2n_add_overflow(offset, size, &slice_size)); + ENSURE_POSIX(b->size >= slice_size, S2N_ERR_SIZE_MISMATCH); + slice->data = b->data + offset; + slice->size = size; + slice->growable = 0; + slice->allocated = 0; + + POSTCONDITION_POSIX(s2n_blob_validate(slice)); + return S2N_SUCCESS; +} + +int s2n_blob_char_to_lower(struct s2n_blob *b) +{ + PRECONDITION_POSIX(s2n_blob_validate(b)); + for (size_t i = 0; i < b->size; i++) { + b->data[i] = tolower(b->data[i]); + } + POSTCONDITION_POSIX(s2n_blob_validate(b)); + return S2N_SUCCESS; +} + +/* An inverse map from an ascii value to a hexidecimal nibble value + * accounts for all possible char values, where 255 is invalid value */ +static const uint8_t hex_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, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 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, 10, 11, 12, 13, 14, 15, 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, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 +}; + +/* takes a hex string and writes values in the s2n_blob + * string needs to a valid hex and blob needs to be large enough */ +int s2n_hex_string_to_bytes(const uint8_t *str, struct s2n_blob *blob) +{ + ENSURE_POSIX_REF(str); + PRECONDITION_POSIX(s2n_blob_validate(blob)); + uint32_t len = strlen((const char*)str); + /* protects against overflows */ + gte_check(blob->size, len / 2); + S2N_ERROR_IF(len % 2 != 0, S2N_ERR_INVALID_HEX); + + for (size_t i = 0; i < len; i += 2) { + uint8_t high_nibble = hex_inverse[str[i]]; + S2N_ERROR_IF(high_nibble == 255, S2N_ERR_INVALID_HEX); + + uint8_t low_nibble = hex_inverse[str[i + 1]]; + S2N_ERROR_IF(low_nibble == 255, S2N_ERR_INVALID_HEX); + blob->data[i / 2] = high_nibble << 4 | low_nibble; + } + + POSTCONDITION_POSIX(s2n_blob_validate(blob)); + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_blob.h b/contrib/restricted/aws/s2n/utils/s2n_blob.h index 8391b3567f..5361ff2f32 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_blob.h +++ b/contrib/restricted/aws/s2n/utils/s2n_blob.h @@ -1,67 +1,67 @@ -/* - * 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 <stdbool.h> -#include <stdint.h> -#include <stdbool.h> -#include "utils/s2n_result.h" - -struct s2n_blob { - /* The data for the s2n_blob */ - uint8_t *data; - - /* The size of the data */ - uint32_t size; - - /* The amount of memory allocated for this blob (i.e. the amount of memory - * which needs to be freed when the blob is cleaned up). If this blob was - * created with s2n_blob_init(), this value is 0. If s2n_alloc() was called, - * this value will be greater than 0. - */ - uint32_t allocated; - - /* Can this blob be resized */ - unsigned growable :1; -}; - - -extern bool s2n_blob_is_growable(const struct s2n_blob* b); -extern S2N_RESULT s2n_blob_validate(const struct s2n_blob* b); -extern int s2n_blob_init(struct s2n_blob *b, uint8_t * data, uint32_t size); -extern int s2n_blob_zero(struct s2n_blob *b); -extern int s2n_blob_char_to_lower(struct s2n_blob *b); -extern int s2n_hex_string_to_bytes(const uint8_t *str, struct s2n_blob *blob); -extern int s2n_blob_slice(const struct s2n_blob *b, struct s2n_blob *slice, uint32_t offset, uint32_t size); - -#define s2n_stack_blob(name, requested_size, maximum) \ - size_t name ## _requested_size = (requested_size); \ - uint8_t name ## _buf[(maximum)] = {0}; \ - lte_check(name ## _requested_size, (maximum)); \ - struct s2n_blob name = {0}; \ - GUARD(s2n_blob_init(&name, name ## _buf, name ## _requested_size)) - -#define S2N_BLOB_LABEL(name, str) \ - static uint8_t name##_data[] = str; \ - const struct s2n_blob name = { .data = name##_data, .size = sizeof(name##_data) - 1 }; - -/* The S2N_BLOB_FROM_HEX macro creates a s2n_blob with the contents of a hex string. - * It is allocated on a stack so there no need to free after use. - * hex should be a const char[]. This function checks against using char*, - * because sizeof needs to refer to the buffer length rather than a pointer size */ -#define S2N_BLOB_FROM_HEX( name, hex ) \ - s2n_stack_blob(name, (sizeof(hex) - 1) / 2, (sizeof(hex) - 1) / 2); \ - GUARD(s2n_hex_string_to_bytes((const uint8_t*)hex, &name)); +/* + * 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 <stdbool.h> +#include <stdint.h> +#include <stdbool.h> +#include "utils/s2n_result.h" + +struct s2n_blob { + /* The data for the s2n_blob */ + uint8_t *data; + + /* The size of the data */ + uint32_t size; + + /* The amount of memory allocated for this blob (i.e. the amount of memory + * which needs to be freed when the blob is cleaned up). If this blob was + * created with s2n_blob_init(), this value is 0. If s2n_alloc() was called, + * this value will be greater than 0. + */ + uint32_t allocated; + + /* Can this blob be resized */ + unsigned growable :1; +}; + + +extern bool s2n_blob_is_growable(const struct s2n_blob* b); +extern S2N_RESULT s2n_blob_validate(const struct s2n_blob* b); +extern int s2n_blob_init(struct s2n_blob *b, uint8_t * data, uint32_t size); +extern int s2n_blob_zero(struct s2n_blob *b); +extern int s2n_blob_char_to_lower(struct s2n_blob *b); +extern int s2n_hex_string_to_bytes(const uint8_t *str, struct s2n_blob *blob); +extern int s2n_blob_slice(const struct s2n_blob *b, struct s2n_blob *slice, uint32_t offset, uint32_t size); + +#define s2n_stack_blob(name, requested_size, maximum) \ + size_t name ## _requested_size = (requested_size); \ + uint8_t name ## _buf[(maximum)] = {0}; \ + lte_check(name ## _requested_size, (maximum)); \ + struct s2n_blob name = {0}; \ + GUARD(s2n_blob_init(&name, name ## _buf, name ## _requested_size)) + +#define S2N_BLOB_LABEL(name, str) \ + static uint8_t name##_data[] = str; \ + const struct s2n_blob name = { .data = name##_data, .size = sizeof(name##_data) - 1 }; + +/* The S2N_BLOB_FROM_HEX macro creates a s2n_blob with the contents of a hex string. + * It is allocated on a stack so there no need to free after use. + * hex should be a const char[]. This function checks against using char*, + * because sizeof needs to refer to the buffer length rather than a pointer size */ +#define S2N_BLOB_FROM_HEX( name, hex ) \ + s2n_stack_blob(name, (sizeof(hex) - 1) / 2, (sizeof(hex) - 1) / 2); \ + GUARD(s2n_hex_string_to_bytes((const uint8_t*)hex, &name)); diff --git a/contrib/restricted/aws/s2n/utils/s2n_compiler.h b/contrib/restricted/aws/s2n/utils/s2n_compiler.h index 989fe266f2..4b91d0bbfc 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_compiler.h +++ b/contrib/restricted/aws/s2n/utils/s2n_compiler.h @@ -1,24 +1,24 @@ -/* - * 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 - -#define S2N_GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - -#define S2N_GCC_VERSION_AT_LEAST(major, minor, patch_level) \ - ((S2N_GCC_VERSION) >= ((major) * 10000 + (minor) * 100 + (patch_level))) - +/* + * 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 + +#define S2N_GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + +#define S2N_GCC_VERSION_AT_LEAST(major, minor, patch_level) \ + ((S2N_GCC_VERSION) >= ((major) * 10000 + (minor) * 100 + (patch_level))) + diff --git a/contrib/restricted/aws/s2n/utils/s2n_ensure.c b/contrib/restricted/aws/s2n/utils/s2n_ensure.c index 4cfe7e40c9..aa0b181c2b 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_ensure.c +++ b/contrib/restricted/aws/s2n/utils/s2n_ensure.c @@ -1,27 +1,27 @@ -/* - * 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 "utils/s2n_safety.h" - -void* s2n_ensure_memcpy_trace(void *restrict to, const void *restrict from, size_t size, const char *debug_str) -{ - if (to == NULL || from == NULL) { - s2n_errno = S2N_ERR_NULL; - s2n_debug_str = debug_str; - return NULL; - } - - return memcpy(to, from, 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 "utils/s2n_safety.h" + +void* s2n_ensure_memcpy_trace(void *restrict to, const void *restrict from, size_t size, const char *debug_str) +{ + if (to == NULL || from == NULL) { + s2n_errno = S2N_ERR_NULL; + s2n_debug_str = debug_str; + return NULL; + } + + return memcpy(to, from, size); +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_ensure.h b/contrib/restricted/aws/s2n/utils/s2n_ensure.h index 8949521e9a..a3e2286192 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_ensure.h +++ b/contrib/restricted/aws/s2n/utils/s2n_ensure.h @@ -1,70 +1,70 @@ -/* - * 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 - -#define s2n_likely(x) __builtin_expect(!!(x), 1) -#define s2n_unlikely(x) __builtin_expect(!!(x), 0) - -/** - * s2n_ensure provides low-level safety check functionality - * - * This should only consumed directly by s2n_safety. - * - * Note: This module can be replaced by static analyzer implementation - * to insert additional safety checks. - */ - -/** - * Ensures `cond` is true, otherwise `action` will be performed - */ -#define __S2N_ENSURE( cond, action ) do {if ( !(cond) ) { action; }} while (0) - -#define __S2N_ENSURE_LIKELY( cond, action ) do {if ( s2n_unlikely( !(cond) ) ) { action; }} while (0) - -#ifdef NDEBUG -#define __S2N_ENSURE_DEBUG( cond, action ) do {} while (0) -#else -#define __S2N_ENSURE_DEBUG( cond, action ) __S2N_ENSURE_LIKELY((cond), action) -#endif - -#define __S2N_ENSURE_PRECONDITION( result ) (s2n_likely(s2n_result_is_ok(result)) ? S2N_RESULT_OK : S2N_RESULT_ERROR) - -#ifdef NDEBUG -#define __S2N_ENSURE_POSTCONDITION( result ) (S2N_RESULT_OK) -#else -#define __S2N_ENSURE_POSTCONDITION( result ) (s2n_likely(s2n_result_is_ok(result)) ? S2N_RESULT_OK : S2N_RESULT_ERROR) -#endif - -#define __S2N_ENSURE_SAFE_MEMCPY( d , s , n , guard ) \ - do { \ - __typeof( n ) __tmp_n = ( n ); \ - if ( s2n_likely( __tmp_n ) ) { \ - void *r = s2n_ensure_memcpy_trace( (d), (s) , (__tmp_n), _S2N_DEBUG_LINE); \ - guard(r); \ - } \ - } while(0) - -#define __S2N_ENSURE_SAFE_MEMSET( d , c , n , guard ) \ - do { \ - __typeof( n ) __tmp_n = ( n ); \ - if ( s2n_likely( __tmp_n ) ) { \ - __typeof( d ) __tmp_d = ( d ); \ - guard( __tmp_d ); \ - memset( __tmp_d, (c), __tmp_n); \ - } \ - } while(0) - -extern void* s2n_ensure_memcpy_trace(void *restrict to, const void *restrict from, size_t size, const char *debug_str); +/* + * 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 + +#define s2n_likely(x) __builtin_expect(!!(x), 1) +#define s2n_unlikely(x) __builtin_expect(!!(x), 0) + +/** + * s2n_ensure provides low-level safety check functionality + * + * This should only consumed directly by s2n_safety. + * + * Note: This module can be replaced by static analyzer implementation + * to insert additional safety checks. + */ + +/** + * Ensures `cond` is true, otherwise `action` will be performed + */ +#define __S2N_ENSURE( cond, action ) do {if ( !(cond) ) { action; }} while (0) + +#define __S2N_ENSURE_LIKELY( cond, action ) do {if ( s2n_unlikely( !(cond) ) ) { action; }} while (0) + +#ifdef NDEBUG +#define __S2N_ENSURE_DEBUG( cond, action ) do {} while (0) +#else +#define __S2N_ENSURE_DEBUG( cond, action ) __S2N_ENSURE_LIKELY((cond), action) +#endif + +#define __S2N_ENSURE_PRECONDITION( result ) (s2n_likely(s2n_result_is_ok(result)) ? S2N_RESULT_OK : S2N_RESULT_ERROR) + +#ifdef NDEBUG +#define __S2N_ENSURE_POSTCONDITION( result ) (S2N_RESULT_OK) +#else +#define __S2N_ENSURE_POSTCONDITION( result ) (s2n_likely(s2n_result_is_ok(result)) ? S2N_RESULT_OK : S2N_RESULT_ERROR) +#endif + +#define __S2N_ENSURE_SAFE_MEMCPY( d , s , n , guard ) \ + do { \ + __typeof( n ) __tmp_n = ( n ); \ + if ( s2n_likely( __tmp_n ) ) { \ + void *r = s2n_ensure_memcpy_trace( (d), (s) , (__tmp_n), _S2N_DEBUG_LINE); \ + guard(r); \ + } \ + } while(0) + +#define __S2N_ENSURE_SAFE_MEMSET( d , c , n , guard ) \ + do { \ + __typeof( n ) __tmp_n = ( n ); \ + if ( s2n_likely( __tmp_n ) ) { \ + __typeof( d ) __tmp_d = ( d ); \ + guard( __tmp_d ); \ + memset( __tmp_d, (c), __tmp_n); \ + } \ + } while(0) + +extern void* s2n_ensure_memcpy_trace(void *restrict to, const void *restrict from, size_t size, const char *debug_str); diff --git a/contrib/restricted/aws/s2n/utils/s2n_init.c b/contrib/restricted/aws/s2n/utils/s2n_init.c index 0f79f959fb..2e3757742a 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_init.c +++ b/contrib/restricted/aws/s2n/utils/s2n_init.c @@ -1,83 +1,83 @@ -/* - * 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 "crypto/s2n_fips.h" - -#include "error/s2n_errno.h" - -#include "tls/s2n_cipher_suites.h" -#include "tls/extensions/s2n_extension_type.h" -#include "tls/s2n_security_policies.h" -#include "tls/extensions/s2n_client_key_share.h" - -#include "utils/s2n_mem.h" -#include "utils/s2n_random.h" -#include "utils/s2n_safety.h" - -#include "openssl/opensslv.h" - -#include "pq-crypto/s2n_pq.h" - -static void s2n_cleanup_atexit(void); - -unsigned long s2n_get_openssl_version(void) -{ - return OPENSSL_VERSION_NUMBER; -} - -int s2n_init(void) -{ - GUARD_POSIX(s2n_fips_init()); - GUARD_POSIX(s2n_mem_init()); - GUARD_AS_POSIX(s2n_rand_init()); - GUARD_POSIX(s2n_cipher_suites_init()); - GUARD_POSIX(s2n_security_policies_init()); - GUARD_POSIX(s2n_config_defaults_init()); - GUARD_POSIX(s2n_extension_type_init()); - GUARD_AS_POSIX(s2n_pq_init()); - - S2N_ERROR_IF(atexit(s2n_cleanup_atexit) != 0, S2N_ERR_ATEXIT); - - if (getenv("S2N_PRINT_STACKTRACE")) { - s2n_stack_traces_enabled_set(true); - } - - return 0; -} - -int s2n_cleanup(void) -{ - /* s2n_cleanup is supposed to be called from each thread before exiting, - * so ensure that whatever clean ups we have here are thread safe */ - GUARD_AS_POSIX(s2n_rand_cleanup_thread()); - return 0; -} - -static bool s2n_cleanup_atexit_impl(void) -{ - /* all of these should run, regardless of result, but the - * values to need to be consumed to prevent warnings */ - bool a = s2n_result_is_ok(s2n_rand_cleanup_thread()); - bool b = s2n_result_is_ok(s2n_rand_cleanup()); - bool c = s2n_mem_cleanup() == 0; - s2n_wipe_static_configs(); - - return a && b && c; -} - -static void s2n_cleanup_atexit(void) -{ - s2n_cleanup_atexit_impl(); -} - +/* + * 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 "crypto/s2n_fips.h" + +#include "error/s2n_errno.h" + +#include "tls/s2n_cipher_suites.h" +#include "tls/extensions/s2n_extension_type.h" +#include "tls/s2n_security_policies.h" +#include "tls/extensions/s2n_client_key_share.h" + +#include "utils/s2n_mem.h" +#include "utils/s2n_random.h" +#include "utils/s2n_safety.h" + +#include "openssl/opensslv.h" + +#include "pq-crypto/s2n_pq.h" + +static void s2n_cleanup_atexit(void); + +unsigned long s2n_get_openssl_version(void) +{ + return OPENSSL_VERSION_NUMBER; +} + +int s2n_init(void) +{ + GUARD_POSIX(s2n_fips_init()); + GUARD_POSIX(s2n_mem_init()); + GUARD_AS_POSIX(s2n_rand_init()); + GUARD_POSIX(s2n_cipher_suites_init()); + GUARD_POSIX(s2n_security_policies_init()); + GUARD_POSIX(s2n_config_defaults_init()); + GUARD_POSIX(s2n_extension_type_init()); + GUARD_AS_POSIX(s2n_pq_init()); + + S2N_ERROR_IF(atexit(s2n_cleanup_atexit) != 0, S2N_ERR_ATEXIT); + + if (getenv("S2N_PRINT_STACKTRACE")) { + s2n_stack_traces_enabled_set(true); + } + + return 0; +} + +int s2n_cleanup(void) +{ + /* s2n_cleanup is supposed to be called from each thread before exiting, + * so ensure that whatever clean ups we have here are thread safe */ + GUARD_AS_POSIX(s2n_rand_cleanup_thread()); + return 0; +} + +static bool s2n_cleanup_atexit_impl(void) +{ + /* all of these should run, regardless of result, but the + * values to need to be consumed to prevent warnings */ + bool a = s2n_result_is_ok(s2n_rand_cleanup_thread()); + bool b = s2n_result_is_ok(s2n_rand_cleanup()); + bool c = s2n_mem_cleanup() == 0; + s2n_wipe_static_configs(); + + return a && b && c; +} + +static void s2n_cleanup_atexit(void) +{ + s2n_cleanup_atexit_impl(); +} + diff --git a/contrib/restricted/aws/s2n/utils/s2n_map.c b/contrib/restricted/aws/s2n/utils/s2n_map.c index 8851b14e1b..3477a93bb7 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_map.c +++ b/contrib/restricted/aws/s2n/utils/s2n_map.c @@ -1,240 +1,240 @@ -/* - * 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 <stdio.h> - -#include "error/s2n_errno.h" - -#include "crypto/s2n_hash.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_result.h" -#include "utils/s2n_blob.h" -#include "utils/s2n_mem.h" -#include "utils/s2n_map.h" -#include "utils/s2n_map_internal.h" - -#include <s2n.h> - -#define S2N_INITIAL_TABLE_SIZE 1024 - -static S2N_RESULT s2n_map_slot(const struct s2n_map *map, struct s2n_blob *key, uint32_t *slot) -{ - union { - uint8_t u8[32]; - uint32_t u32[8]; - } digest; - - DEFER_CLEANUP(struct s2n_hash_state sha256 = {0}, s2n_hash_free); - GUARD_AS_RESULT(s2n_hash_new(&sha256)); - GUARD_AS_RESULT(s2n_hash_init(&sha256, S2N_HASH_SHA256)); - GUARD_AS_RESULT(s2n_hash_update(&sha256, key->data, key->size)); - GUARD_AS_RESULT(s2n_hash_digest(&sha256, digest.u8, sizeof(digest))); - - *slot = digest.u32[0] % map->capacity; - return S2N_RESULT_OK; -} - -static S2N_RESULT s2n_map_embiggen(struct s2n_map *map, uint32_t capacity) -{ - struct s2n_blob mem = {0}; - struct s2n_map tmp = {0}; - - ENSURE(!map->immutable, S2N_ERR_MAP_IMMUTABLE); - - GUARD_AS_RESULT(s2n_alloc(&mem, (capacity * sizeof(struct s2n_map_entry)))); - GUARD_AS_RESULT(s2n_blob_zero(&mem)); - - tmp.capacity = capacity; - tmp.size = 0; - tmp.table = (void *) mem.data; - tmp.immutable = 0; - - for (int i = 0; i < map->capacity; i++) { - if (map->table[i].key.size) { - GUARD_RESULT(s2n_map_add(&tmp, &map->table[i].key, &map->table[i].value)); - GUARD_AS_RESULT(s2n_free(&map->table[i].key)); - GUARD_AS_RESULT(s2n_free(&map->table[i].value)); - } - } - GUARD_AS_RESULT(s2n_free_object((uint8_t **)&map->table, map->capacity * sizeof(struct s2n_map_entry))); - - /* Clone the temporary map */ - map->capacity = tmp.capacity; - map->size = tmp.size; - map->table = tmp.table; - map->immutable = 0; - - return S2N_RESULT_OK; -} - -struct s2n_map *s2n_map_new() -{ - return s2n_map_new_with_initial_capacity(S2N_INITIAL_TABLE_SIZE); -} - -struct s2n_map *s2n_map_new_with_initial_capacity(uint32_t capacity) -{ - S2N_ERROR_IF_PTR(capacity == 0, S2N_ERR_MAP_INVALID_MAP_SIZE); - struct s2n_blob mem = {0}; - struct s2n_map *map; - - GUARD_POSIX_PTR(s2n_alloc(&mem, sizeof(struct s2n_map))); - - map = (void *) mem.data; - map->capacity = 0; - map->size = 0; - map->immutable = 0; - map->table = NULL; - - GUARD_RESULT_PTR(s2n_map_embiggen(map, capacity)); - - return map; -} - -S2N_RESULT s2n_map_add(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value) -{ - ENSURE(!map->immutable, S2N_ERR_MAP_IMMUTABLE); - - if (map->capacity < (map->size * 2)) { - /* Embiggen the map */ - GUARD_RESULT(s2n_map_embiggen(map, map->capacity * 2)); - } - - uint32_t slot = 0; - GUARD_RESULT(s2n_map_slot(map, key, &slot)); - - /* Linear probing until we find an empty slot */ - while(map->table[slot].key.size) { - if (key->size != map->table[slot].key.size || - memcmp(key->data, map->table[slot].key.data, key->size)) { - slot++; - slot %= map->capacity; - continue; - } - - /* We found a duplicate key */ - BAIL(S2N_ERR_MAP_DUPLICATE); - } - - GUARD_AS_RESULT(s2n_dup(key, &map->table[slot].key)); - GUARD_AS_RESULT(s2n_dup(value, &map->table[slot].value)); - map->size++; - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_map_put(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value) -{ - ENSURE(!map->immutable, S2N_ERR_MAP_IMMUTABLE); - - if (map->capacity < (map->size * 2)) { - /* Embiggen the map */ - GUARD_RESULT(s2n_map_embiggen(map, map->capacity * 2)); - } - - uint32_t slot = 0; - GUARD_RESULT(s2n_map_slot(map, key, &slot)); - - /* Linear probing until we find an empty slot */ - while(map->table[slot].key.size) { - if (key->size != map->table[slot].key.size || - memcmp(key->data, map->table[slot].key.data, key->size)) { - slot++; - slot %= map->capacity; - continue; - } - - /* We found a duplicate key that will be overwritten */ - GUARD_AS_RESULT(s2n_free(&map->table[slot].key)); - GUARD_AS_RESULT(s2n_free(&map->table[slot].value)); - map->size--; - break; - } - - GUARD_AS_RESULT(s2n_dup(key, &map->table[slot].key)); - GUARD_AS_RESULT(s2n_dup(value, &map->table[slot].value)); - map->size++; - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_map_complete(struct s2n_map *map) -{ - map->immutable = 1; - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_map_unlock(struct s2n_map *map) -{ - map->immutable = 0; - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_map_lookup(const struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value, bool *key_found) -{ - ENSURE(map->immutable, S2N_ERR_MAP_MUTABLE); - - uint32_t slot = 0; - GUARD_RESULT(s2n_map_slot(map, key, &slot)); - const uint32_t initial_slot = slot; - - while(map->table[slot].key.size) { - if (key->size != map->table[slot].key.size || - memcmp(key->data, map->table[slot].key.data, key->size)) { - slot++; - slot %= map->capacity; - /* We went over all the slots but found no match */ - if (slot == initial_slot) { - break; - } - continue; - } - - /* We found a match */ - value->data = map->table[slot].value.data; - value->size = map->table[slot].value.size; - - *key_found = true; - - return S2N_RESULT_OK; - } - - *key_found = false; - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_map_free(struct s2n_map *map) -{ - /* Free the keys and values */ - for (int i = 0; i < map->capacity; i++) { - if (map->table[i].key.size) { - GUARD_AS_RESULT(s2n_free(&map->table[i].key)); - GUARD_AS_RESULT(s2n_free(&map->table[i].value)); - } - } - - /* Free the table */ - GUARD_AS_RESULT(s2n_free_object((uint8_t **)&map->table, map->capacity * sizeof(struct s2n_map_entry))); - - /* And finally the map */ - GUARD_AS_RESULT(s2n_free_object((uint8_t **)&map, sizeof(struct s2n_map))); - - return S2N_RESULT_OK; -} +/* + * 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 <stdio.h> + +#include "error/s2n_errno.h" + +#include "crypto/s2n_hash.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_result.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_mem.h" +#include "utils/s2n_map.h" +#include "utils/s2n_map_internal.h" + +#include <s2n.h> + +#define S2N_INITIAL_TABLE_SIZE 1024 + +static S2N_RESULT s2n_map_slot(const struct s2n_map *map, struct s2n_blob *key, uint32_t *slot) +{ + union { + uint8_t u8[32]; + uint32_t u32[8]; + } digest; + + DEFER_CLEANUP(struct s2n_hash_state sha256 = {0}, s2n_hash_free); + GUARD_AS_RESULT(s2n_hash_new(&sha256)); + GUARD_AS_RESULT(s2n_hash_init(&sha256, S2N_HASH_SHA256)); + GUARD_AS_RESULT(s2n_hash_update(&sha256, key->data, key->size)); + GUARD_AS_RESULT(s2n_hash_digest(&sha256, digest.u8, sizeof(digest))); + + *slot = digest.u32[0] % map->capacity; + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_map_embiggen(struct s2n_map *map, uint32_t capacity) +{ + struct s2n_blob mem = {0}; + struct s2n_map tmp = {0}; + + ENSURE(!map->immutable, S2N_ERR_MAP_IMMUTABLE); + + GUARD_AS_RESULT(s2n_alloc(&mem, (capacity * sizeof(struct s2n_map_entry)))); + GUARD_AS_RESULT(s2n_blob_zero(&mem)); + + tmp.capacity = capacity; + tmp.size = 0; + tmp.table = (void *) mem.data; + tmp.immutable = 0; + + for (int i = 0; i < map->capacity; i++) { + if (map->table[i].key.size) { + GUARD_RESULT(s2n_map_add(&tmp, &map->table[i].key, &map->table[i].value)); + GUARD_AS_RESULT(s2n_free(&map->table[i].key)); + GUARD_AS_RESULT(s2n_free(&map->table[i].value)); + } + } + GUARD_AS_RESULT(s2n_free_object((uint8_t **)&map->table, map->capacity * sizeof(struct s2n_map_entry))); + + /* Clone the temporary map */ + map->capacity = tmp.capacity; + map->size = tmp.size; + map->table = tmp.table; + map->immutable = 0; + + return S2N_RESULT_OK; +} + +struct s2n_map *s2n_map_new() +{ + return s2n_map_new_with_initial_capacity(S2N_INITIAL_TABLE_SIZE); +} + +struct s2n_map *s2n_map_new_with_initial_capacity(uint32_t capacity) +{ + S2N_ERROR_IF_PTR(capacity == 0, S2N_ERR_MAP_INVALID_MAP_SIZE); + struct s2n_blob mem = {0}; + struct s2n_map *map; + + GUARD_POSIX_PTR(s2n_alloc(&mem, sizeof(struct s2n_map))); + + map = (void *) mem.data; + map->capacity = 0; + map->size = 0; + map->immutable = 0; + map->table = NULL; + + GUARD_RESULT_PTR(s2n_map_embiggen(map, capacity)); + + return map; +} + +S2N_RESULT s2n_map_add(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value) +{ + ENSURE(!map->immutable, S2N_ERR_MAP_IMMUTABLE); + + if (map->capacity < (map->size * 2)) { + /* Embiggen the map */ + GUARD_RESULT(s2n_map_embiggen(map, map->capacity * 2)); + } + + uint32_t slot = 0; + GUARD_RESULT(s2n_map_slot(map, key, &slot)); + + /* Linear probing until we find an empty slot */ + while(map->table[slot].key.size) { + if (key->size != map->table[slot].key.size || + memcmp(key->data, map->table[slot].key.data, key->size)) { + slot++; + slot %= map->capacity; + continue; + } + + /* We found a duplicate key */ + BAIL(S2N_ERR_MAP_DUPLICATE); + } + + GUARD_AS_RESULT(s2n_dup(key, &map->table[slot].key)); + GUARD_AS_RESULT(s2n_dup(value, &map->table[slot].value)); + map->size++; + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_map_put(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value) +{ + ENSURE(!map->immutable, S2N_ERR_MAP_IMMUTABLE); + + if (map->capacity < (map->size * 2)) { + /* Embiggen the map */ + GUARD_RESULT(s2n_map_embiggen(map, map->capacity * 2)); + } + + uint32_t slot = 0; + GUARD_RESULT(s2n_map_slot(map, key, &slot)); + + /* Linear probing until we find an empty slot */ + while(map->table[slot].key.size) { + if (key->size != map->table[slot].key.size || + memcmp(key->data, map->table[slot].key.data, key->size)) { + slot++; + slot %= map->capacity; + continue; + } + + /* We found a duplicate key that will be overwritten */ + GUARD_AS_RESULT(s2n_free(&map->table[slot].key)); + GUARD_AS_RESULT(s2n_free(&map->table[slot].value)); + map->size--; + break; + } + + GUARD_AS_RESULT(s2n_dup(key, &map->table[slot].key)); + GUARD_AS_RESULT(s2n_dup(value, &map->table[slot].value)); + map->size++; + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_map_complete(struct s2n_map *map) +{ + map->immutable = 1; + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_map_unlock(struct s2n_map *map) +{ + map->immutable = 0; + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_map_lookup(const struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value, bool *key_found) +{ + ENSURE(map->immutable, S2N_ERR_MAP_MUTABLE); + + uint32_t slot = 0; + GUARD_RESULT(s2n_map_slot(map, key, &slot)); + const uint32_t initial_slot = slot; + + while(map->table[slot].key.size) { + if (key->size != map->table[slot].key.size || + memcmp(key->data, map->table[slot].key.data, key->size)) { + slot++; + slot %= map->capacity; + /* We went over all the slots but found no match */ + if (slot == initial_slot) { + break; + } + continue; + } + + /* We found a match */ + value->data = map->table[slot].value.data; + value->size = map->table[slot].value.size; + + *key_found = true; + + return S2N_RESULT_OK; + } + + *key_found = false; + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_map_free(struct s2n_map *map) +{ + /* Free the keys and values */ + for (int i = 0; i < map->capacity; i++) { + if (map->table[i].key.size) { + GUARD_AS_RESULT(s2n_free(&map->table[i].key)); + GUARD_AS_RESULT(s2n_free(&map->table[i].value)); + } + } + + /* Free the table */ + GUARD_AS_RESULT(s2n_free_object((uint8_t **)&map->table, map->capacity * sizeof(struct s2n_map_entry))); + + /* And finally the map */ + GUARD_AS_RESULT(s2n_free_object((uint8_t **)&map, sizeof(struct s2n_map))); + + return S2N_RESULT_OK; +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_map.h b/contrib/restricted/aws/s2n/utils/s2n_map.h index afde6a8514..85186581bd 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_map.h +++ b/contrib/restricted/aws/s2n/utils/s2n_map.h @@ -1,33 +1,33 @@ -/* - * 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 <string.h> - -#include "crypto/s2n_hash.h" - -#include "utils/s2n_blob.h" -#include "utils/s2n_result.h" - -struct s2n_map; - -extern struct s2n_map *s2n_map_new(); -extern struct s2n_map *s2n_map_new_with_initial_capacity(uint32_t capacity); -extern S2N_RESULT s2n_map_add(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value); -extern S2N_RESULT s2n_map_put(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value); -extern S2N_RESULT s2n_map_complete(struct s2n_map *map); -extern S2N_RESULT s2n_map_unlock(struct s2n_map *map); -extern S2N_RESULT s2n_map_lookup(const struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value, bool *key_found); -extern S2N_RESULT s2n_map_free(struct s2n_map *map); +/* + * 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 <string.h> + +#include "crypto/s2n_hash.h" + +#include "utils/s2n_blob.h" +#include "utils/s2n_result.h" + +struct s2n_map; + +extern struct s2n_map *s2n_map_new(); +extern struct s2n_map *s2n_map_new_with_initial_capacity(uint32_t capacity); +extern S2N_RESULT s2n_map_add(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value); +extern S2N_RESULT s2n_map_put(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value); +extern S2N_RESULT s2n_map_complete(struct s2n_map *map); +extern S2N_RESULT s2n_map_unlock(struct s2n_map *map); +extern S2N_RESULT s2n_map_lookup(const struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value, bool *key_found); +extern S2N_RESULT s2n_map_free(struct s2n_map *map); diff --git a/contrib/restricted/aws/s2n/utils/s2n_map_internal.h b/contrib/restricted/aws/s2n/utils/s2n_map_internal.h index 01d629fb16..13191d70c4 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_map_internal.h +++ b/contrib/restricted/aws/s2n/utils/s2n_map_internal.h @@ -1,36 +1,36 @@ -/* - * 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 "utils/s2n_map.h" - -struct s2n_map_entry { - struct s2n_blob key; - struct s2n_blob value; -}; - -struct s2n_map { - /* The total capacity of the table, in number of elements. */ - uint32_t capacity; - - /* The total number of elements currently in the table. Used for measuring the load factor */ - uint32_t size; - - /* Once a map has been looked up, it is considered immutable */ - int immutable; - - /* Pointer to the hash-table, should be capacity * sizeof(struct s2n_map_entry) */ - struct s2n_map_entry *table; -}; +/* + * 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 "utils/s2n_map.h" + +struct s2n_map_entry { + struct s2n_blob key; + struct s2n_blob value; +}; + +struct s2n_map { + /* The total capacity of the table, in number of elements. */ + uint32_t capacity; + + /* The total number of elements currently in the table. Used for measuring the load factor */ + uint32_t size; + + /* Once a map has been looked up, it is considered immutable */ + int immutable; + + /* Pointer to the hash-table, should be capacity * sizeof(struct s2n_map_entry) */ + struct s2n_map_entry *table; +}; diff --git a/contrib/restricted/aws/s2n/utils/s2n_mem.c b/contrib/restricted/aws/s2n/utils/s2n_mem.c index dc14847851..abc9481fa6 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_mem.c +++ b/contrib/restricted/aws/s2n/utils/s2n_mem.c @@ -1,304 +1,304 @@ -/* - * 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. - */ - -#define _DEFAULT_SOURCE 1 -#if !defined(__APPLE__) && !defined(__FreeBSD__) -#include <features.h> -#endif - -#include <stdint.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/mman.h> - -#include "error/s2n_errno.h" - -#include "utils/s2n_blob.h" -#include "utils/s2n_mem.h" -#include "utils/s2n_safety.h" - -static uint32_t page_size = 4096; -static bool initialized = false; - -static int s2n_mem_init_impl(void); -static int s2n_mem_cleanup_impl(void); -static int s2n_mem_free_no_mlock_impl(void *ptr, uint32_t size); -static int s2n_mem_free_mlock_impl(void *ptr, uint32_t size); -static int s2n_mem_malloc_no_mlock_impl(void **ptr, uint32_t requested, uint32_t *allocated); -static int s2n_mem_malloc_mlock_impl(void **ptr, uint32_t requested, uint32_t *allocated); - -static s2n_mem_init_callback s2n_mem_init_cb = s2n_mem_init_impl; -static s2n_mem_cleanup_callback s2n_mem_cleanup_cb = s2n_mem_cleanup_impl; -static s2n_mem_malloc_callback s2n_mem_malloc_cb = s2n_mem_malloc_mlock_impl; -static s2n_mem_free_callback s2n_mem_free_cb = s2n_mem_free_mlock_impl; - -static int s2n_mem_init_impl(void) -{ - long sysconf_rc = sysconf(_SC_PAGESIZE); - - /* sysconf must not error, and page_size cannot be 0 */ - ENSURE_POSIX(sysconf_rc > 0, S2N_FAILURE); - - /* page_size must be a valid uint32 */ - ENSURE_POSIX(sysconf_rc <= UINT32_MAX, S2N_FAILURE); - - page_size = (uint32_t) sysconf_rc; - - if (getenv("S2N_DONT_MLOCK")) { - s2n_mem_malloc_cb = s2n_mem_malloc_no_mlock_impl; - s2n_mem_free_cb = s2n_mem_free_no_mlock_impl; - } - return S2N_SUCCESS; -} - -static int s2n_mem_cleanup_impl(void) -{ - page_size = 4096; - s2n_mem_malloc_cb = s2n_mem_malloc_no_mlock_impl; - s2n_mem_free_cb = s2n_mem_free_no_mlock_impl; - return S2N_SUCCESS; -} - -static int s2n_mem_free_mlock_impl(void *ptr, uint32_t size) -{ - int munlock_rc = munlock(ptr, size); - free(ptr); - GUARD(munlock_rc); - - return S2N_SUCCESS; -} - -static int s2n_mem_free_no_mlock_impl(void *ptr, uint32_t size) -{ - free(ptr); - - return S2N_SUCCESS; -} - -static int s2n_mem_malloc_mlock_impl(void **ptr, uint32_t requested, uint32_t *allocated) -{ - notnull_check(ptr); - - /* Page aligned allocation required for mlock */ - uint32_t allocate; - - GUARD(s2n_align_to(requested, page_size, &allocate)); - - *ptr = NULL; - S2N_ERROR_IF(posix_memalign(ptr, page_size, allocate) != 0, S2N_ERR_ALLOC); - *allocated = allocate; - -/* -** We disable MAD_DONTDUMP when fuzz-testing or using the address sanitizer because -** both need to be able to dump pages to function. It's how they map heap output. -*/ -#if defined(MADV_DONTDUMP) && !defined(S2N_ADDRESS_SANITIZER) && !defined(S2N_FUZZ_TESTING) - if (madvise(*ptr, *allocated, MADV_DONTDUMP) != 0) { - GUARD(s2n_mem_free_no_mlock_impl(*ptr, *allocated)); - S2N_ERROR(S2N_ERR_MADVISE); - } -#endif - - if (mlock(*ptr, *allocated) != 0) { - /* When mlock fails, no memory will be locked, so we don't use munlock on free */ - GUARD(s2n_mem_free_no_mlock_impl(*ptr, *allocated)); - S2N_ERROR(S2N_ERR_MLOCK); - } - - S2N_ERROR_IF(*ptr == NULL, S2N_ERR_ALLOC); - - return S2N_SUCCESS; -} - -static int s2n_mem_malloc_no_mlock_impl(void **ptr, uint32_t requested, uint32_t *allocated) -{ - *ptr = malloc(requested); - S2N_ERROR_IF(*ptr == NULL, S2N_ERR_ALLOC); - *allocated = requested; - - return S2N_SUCCESS; -} - -int s2n_mem_set_callbacks(s2n_mem_init_callback mem_init_callback, s2n_mem_cleanup_callback mem_cleanup_callback, - s2n_mem_malloc_callback mem_malloc_callback, s2n_mem_free_callback mem_free_callback) -{ - S2N_ERROR_IF(initialized == true, S2N_ERR_INITIALIZED); - - notnull_check(mem_init_callback); - notnull_check(mem_cleanup_callback); - notnull_check(mem_malloc_callback); - notnull_check(mem_free_callback); - - s2n_mem_init_cb = mem_init_callback; - s2n_mem_cleanup_cb = mem_cleanup_callback; - s2n_mem_malloc_cb = mem_malloc_callback; - s2n_mem_free_cb = mem_free_callback; - - return S2N_SUCCESS; -} - -int s2n_alloc(struct s2n_blob *b, uint32_t size) -{ - S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); - notnull_check(b); - const struct s2n_blob temp = {0}; - *b = temp; - GUARD(s2n_realloc(b, size)); - return S2N_SUCCESS; -} - -/* A blob is growable if it is either explicitly marked as such, or if it contains no data */ -bool s2n_blob_is_growable(const struct s2n_blob* b) -{ - return b && (b->growable || (b->data == NULL && b->size == 0 && b->allocated == 0)); -} - -/* Tries to realloc the requested bytes. - * If successful, updates *b. - * If failed, *b remains unchanged - */ -int s2n_realloc(struct s2n_blob *b, uint32_t size) -{ - S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); - notnull_check(b); - S2N_ERROR_IF(!s2n_blob_is_growable(b), S2N_ERR_RESIZE_STATIC_BLOB); - if (size == 0) { - return s2n_free(b); - } - - /* blob already has space for the request */ - if (size <= b->allocated) { - - if (size < b->size) { - /* Zero the existing blob memory before the we release it */ - struct s2n_blob slice = {0}; - GUARD(s2n_blob_slice(b, &slice, size, b->size - size)); - GUARD(s2n_blob_zero(&slice)); - } - - b->size = size; - return S2N_SUCCESS; - } - - struct s2n_blob new_memory = {.data = NULL, .size = size, .allocated = 0, .growable = 1}; - if(s2n_mem_malloc_cb((void **) &new_memory.data, new_memory.size, &new_memory.allocated) != 0) { - S2N_ERROR_PRESERVE_ERRNO(); - } - - S2N_ERROR_IF(new_memory.allocated < new_memory.size, S2N_ERR_ALLOC); - S2N_ERROR_IF(new_memory.data == NULL, S2N_ERR_ALLOC); - - if (b->size) { - memcpy_check(new_memory.data, b->data, b->size); - } - - if (b->allocated) { - GUARD(s2n_free(b)); - } - - *b = new_memory; - return S2N_SUCCESS; -} - -int s2n_free_object(uint8_t **p_data, uint32_t size) -{ - notnull_check(p_data); - - if (*p_data == NULL) { - return S2N_SUCCESS; - } - struct s2n_blob b = {.data = *p_data, .allocated = size, .size = size, .growable = 1}; - - /* s2n_free() will call free() even if it returns error (for a growable blob). - ** This makes sure *p_data is not used after free() */ - *p_data = NULL; - - return s2n_free(&b); -} - -int s2n_dup(struct s2n_blob *from, struct s2n_blob *to) -{ - S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); - eq_check(to->size, 0); - eq_check(to->data, NULL); - ne_check(from->size, 0); - ne_check(from->data, NULL); - - GUARD(s2n_alloc(to, from->size)); - - memcpy_check(to->data, from->data, to->size); - - return S2N_SUCCESS; -} - -int s2n_mem_init(void) -{ - GUARD(s2n_mem_init_cb()); - - initialized = true; - - return S2N_SUCCESS; -} - -bool s2n_mem_is_init(void) -{ - return initialized; -} - -uint32_t s2n_mem_get_page_size(void) -{ - return page_size; -} - -int s2n_mem_cleanup(void) -{ - S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); - GUARD(s2n_mem_cleanup_cb()); - - initialized = false; - - return S2N_SUCCESS; -} - -int s2n_free(struct s2n_blob *b) -{ - PRECONDITION_POSIX(s2n_blob_validate(b)); - - /* To avoid memory leaks, don't exit the function until the memory - has been freed */ - int zero_rc = s2n_blob_zero(b); - - S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); - S2N_ERROR_IF(!s2n_blob_is_growable(b), S2N_ERR_FREE_STATIC_BLOB); - - GUARD(s2n_mem_free_cb(b->data, b->allocated)); - - *b = (struct s2n_blob) {0}; - - GUARD(zero_rc); - - return S2N_SUCCESS; -} - -int s2n_blob_zeroize_free(struct s2n_blob *b) { - S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); - notnull_check(b); - - GUARD(s2n_blob_zero(b)); - if (b->allocated) { - GUARD(s2n_free(b)); - } - 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. + */ + +#define _DEFAULT_SOURCE 1 +#if !defined(__APPLE__) && !defined(__FreeBSD__) +#include <features.h> +#endif + +#include <stdint.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/mman.h> + +#include "error/s2n_errno.h" + +#include "utils/s2n_blob.h" +#include "utils/s2n_mem.h" +#include "utils/s2n_safety.h" + +static uint32_t page_size = 4096; +static bool initialized = false; + +static int s2n_mem_init_impl(void); +static int s2n_mem_cleanup_impl(void); +static int s2n_mem_free_no_mlock_impl(void *ptr, uint32_t size); +static int s2n_mem_free_mlock_impl(void *ptr, uint32_t size); +static int s2n_mem_malloc_no_mlock_impl(void **ptr, uint32_t requested, uint32_t *allocated); +static int s2n_mem_malloc_mlock_impl(void **ptr, uint32_t requested, uint32_t *allocated); + +static s2n_mem_init_callback s2n_mem_init_cb = s2n_mem_init_impl; +static s2n_mem_cleanup_callback s2n_mem_cleanup_cb = s2n_mem_cleanup_impl; +static s2n_mem_malloc_callback s2n_mem_malloc_cb = s2n_mem_malloc_mlock_impl; +static s2n_mem_free_callback s2n_mem_free_cb = s2n_mem_free_mlock_impl; + +static int s2n_mem_init_impl(void) +{ + long sysconf_rc = sysconf(_SC_PAGESIZE); + + /* sysconf must not error, and page_size cannot be 0 */ + ENSURE_POSIX(sysconf_rc > 0, S2N_FAILURE); + + /* page_size must be a valid uint32 */ + ENSURE_POSIX(sysconf_rc <= UINT32_MAX, S2N_FAILURE); + + page_size = (uint32_t) sysconf_rc; + + if (getenv("S2N_DONT_MLOCK")) { + s2n_mem_malloc_cb = s2n_mem_malloc_no_mlock_impl; + s2n_mem_free_cb = s2n_mem_free_no_mlock_impl; + } + return S2N_SUCCESS; +} + +static int s2n_mem_cleanup_impl(void) +{ + page_size = 4096; + s2n_mem_malloc_cb = s2n_mem_malloc_no_mlock_impl; + s2n_mem_free_cb = s2n_mem_free_no_mlock_impl; + return S2N_SUCCESS; +} + +static int s2n_mem_free_mlock_impl(void *ptr, uint32_t size) +{ + int munlock_rc = munlock(ptr, size); + free(ptr); + GUARD(munlock_rc); + + return S2N_SUCCESS; +} + +static int s2n_mem_free_no_mlock_impl(void *ptr, uint32_t size) +{ + free(ptr); + + return S2N_SUCCESS; +} + +static int s2n_mem_malloc_mlock_impl(void **ptr, uint32_t requested, uint32_t *allocated) +{ + notnull_check(ptr); + + /* Page aligned allocation required for mlock */ + uint32_t allocate; + + GUARD(s2n_align_to(requested, page_size, &allocate)); + + *ptr = NULL; + S2N_ERROR_IF(posix_memalign(ptr, page_size, allocate) != 0, S2N_ERR_ALLOC); + *allocated = allocate; + +/* +** We disable MAD_DONTDUMP when fuzz-testing or using the address sanitizer because +** both need to be able to dump pages to function. It's how they map heap output. +*/ +#if defined(MADV_DONTDUMP) && !defined(S2N_ADDRESS_SANITIZER) && !defined(S2N_FUZZ_TESTING) + if (madvise(*ptr, *allocated, MADV_DONTDUMP) != 0) { + GUARD(s2n_mem_free_no_mlock_impl(*ptr, *allocated)); + S2N_ERROR(S2N_ERR_MADVISE); + } +#endif + + if (mlock(*ptr, *allocated) != 0) { + /* When mlock fails, no memory will be locked, so we don't use munlock on free */ + GUARD(s2n_mem_free_no_mlock_impl(*ptr, *allocated)); + S2N_ERROR(S2N_ERR_MLOCK); + } + + S2N_ERROR_IF(*ptr == NULL, S2N_ERR_ALLOC); + + return S2N_SUCCESS; +} + +static int s2n_mem_malloc_no_mlock_impl(void **ptr, uint32_t requested, uint32_t *allocated) +{ + *ptr = malloc(requested); + S2N_ERROR_IF(*ptr == NULL, S2N_ERR_ALLOC); + *allocated = requested; + + return S2N_SUCCESS; +} + +int s2n_mem_set_callbacks(s2n_mem_init_callback mem_init_callback, s2n_mem_cleanup_callback mem_cleanup_callback, + s2n_mem_malloc_callback mem_malloc_callback, s2n_mem_free_callback mem_free_callback) +{ + S2N_ERROR_IF(initialized == true, S2N_ERR_INITIALIZED); + + notnull_check(mem_init_callback); + notnull_check(mem_cleanup_callback); + notnull_check(mem_malloc_callback); + notnull_check(mem_free_callback); + + s2n_mem_init_cb = mem_init_callback; + s2n_mem_cleanup_cb = mem_cleanup_callback; + s2n_mem_malloc_cb = mem_malloc_callback; + s2n_mem_free_cb = mem_free_callback; + + return S2N_SUCCESS; +} + +int s2n_alloc(struct s2n_blob *b, uint32_t size) +{ + S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); + notnull_check(b); + const struct s2n_blob temp = {0}; + *b = temp; + GUARD(s2n_realloc(b, size)); + return S2N_SUCCESS; +} + +/* A blob is growable if it is either explicitly marked as such, or if it contains no data */ +bool s2n_blob_is_growable(const struct s2n_blob* b) +{ + return b && (b->growable || (b->data == NULL && b->size == 0 && b->allocated == 0)); +} + +/* Tries to realloc the requested bytes. + * If successful, updates *b. + * If failed, *b remains unchanged + */ +int s2n_realloc(struct s2n_blob *b, uint32_t size) +{ + S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); + notnull_check(b); + S2N_ERROR_IF(!s2n_blob_is_growable(b), S2N_ERR_RESIZE_STATIC_BLOB); + if (size == 0) { + return s2n_free(b); + } + + /* blob already has space for the request */ + if (size <= b->allocated) { + + if (size < b->size) { + /* Zero the existing blob memory before the we release it */ + struct s2n_blob slice = {0}; + GUARD(s2n_blob_slice(b, &slice, size, b->size - size)); + GUARD(s2n_blob_zero(&slice)); + } + + b->size = size; + return S2N_SUCCESS; + } + + struct s2n_blob new_memory = {.data = NULL, .size = size, .allocated = 0, .growable = 1}; + if(s2n_mem_malloc_cb((void **) &new_memory.data, new_memory.size, &new_memory.allocated) != 0) { + S2N_ERROR_PRESERVE_ERRNO(); + } + + S2N_ERROR_IF(new_memory.allocated < new_memory.size, S2N_ERR_ALLOC); + S2N_ERROR_IF(new_memory.data == NULL, S2N_ERR_ALLOC); + + if (b->size) { + memcpy_check(new_memory.data, b->data, b->size); + } + + if (b->allocated) { + GUARD(s2n_free(b)); + } + + *b = new_memory; + return S2N_SUCCESS; +} + +int s2n_free_object(uint8_t **p_data, uint32_t size) +{ + notnull_check(p_data); + + if (*p_data == NULL) { + return S2N_SUCCESS; + } + struct s2n_blob b = {.data = *p_data, .allocated = size, .size = size, .growable = 1}; + + /* s2n_free() will call free() even if it returns error (for a growable blob). + ** This makes sure *p_data is not used after free() */ + *p_data = NULL; + + return s2n_free(&b); +} + +int s2n_dup(struct s2n_blob *from, struct s2n_blob *to) +{ + S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); + eq_check(to->size, 0); + eq_check(to->data, NULL); + ne_check(from->size, 0); + ne_check(from->data, NULL); + + GUARD(s2n_alloc(to, from->size)); + + memcpy_check(to->data, from->data, to->size); + + return S2N_SUCCESS; +} + +int s2n_mem_init(void) +{ + GUARD(s2n_mem_init_cb()); + + initialized = true; + + return S2N_SUCCESS; +} + +bool s2n_mem_is_init(void) +{ + return initialized; +} + +uint32_t s2n_mem_get_page_size(void) +{ + return page_size; +} + +int s2n_mem_cleanup(void) +{ + S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); + GUARD(s2n_mem_cleanup_cb()); + + initialized = false; + + return S2N_SUCCESS; +} + +int s2n_free(struct s2n_blob *b) +{ + PRECONDITION_POSIX(s2n_blob_validate(b)); + + /* To avoid memory leaks, don't exit the function until the memory + has been freed */ + int zero_rc = s2n_blob_zero(b); + + S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); + S2N_ERROR_IF(!s2n_blob_is_growable(b), S2N_ERR_FREE_STATIC_BLOB); + + GUARD(s2n_mem_free_cb(b->data, b->allocated)); + + *b = (struct s2n_blob) {0}; + + GUARD(zero_rc); + + return S2N_SUCCESS; +} + +int s2n_blob_zeroize_free(struct s2n_blob *b) { + S2N_ERROR_IF(initialized == false, S2N_ERR_NOT_INITIALIZED); + notnull_check(b); + + GUARD(s2n_blob_zero(b)); + if (b->allocated) { + GUARD(s2n_free(b)); + } + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_mem.h b/contrib/restricted/aws/s2n/utils/s2n_mem.h index 78d600db32..91c20871f6 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_mem.h +++ b/contrib/restricted/aws/s2n/utils/s2n_mem.h @@ -1,31 +1,31 @@ -/* - * 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 "utils/s2n_blob.h" - -#include <stdint.h> - -int s2n_mem_init(void); -bool s2n_mem_is_init(void); -uint32_t s2n_mem_get_page_size(void); -int s2n_mem_cleanup(void); -int s2n_alloc(struct s2n_blob *b, uint32_t size); -int s2n_realloc(struct s2n_blob *b, uint32_t size); -int s2n_free(struct s2n_blob *b); -int s2n_blob_zeroize_free(struct s2n_blob *b); -int s2n_free_object(uint8_t **p_data, uint32_t size); -int s2n_dup(struct s2n_blob *from, struct s2n_blob *to); +/* + * 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 "utils/s2n_blob.h" + +#include <stdint.h> + +int s2n_mem_init(void); +bool s2n_mem_is_init(void); +uint32_t s2n_mem_get_page_size(void); +int s2n_mem_cleanup(void); +int s2n_alloc(struct s2n_blob *b, uint32_t size); +int s2n_realloc(struct s2n_blob *b, uint32_t size); +int s2n_free(struct s2n_blob *b); +int s2n_blob_zeroize_free(struct s2n_blob *b); +int s2n_free_object(uint8_t **p_data, uint32_t size); +int s2n_dup(struct s2n_blob *from, struct s2n_blob *to); diff --git a/contrib/restricted/aws/s2n/utils/s2n_random.c b/contrib/restricted/aws/s2n/utils/s2n_random.c index be063883d0..e68dc14370 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_random.c +++ b/contrib/restricted/aws/s2n/utils/s2n_random.c @@ -1,548 +1,548 @@ -/* - * 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 <openssl/engine.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/param.h> -#include <unistd.h> -#include <pthread.h> -#include <limits.h> -#include <fcntl.h> -#include <string.h> -#include <stdint.h> -#include <stdlib.h> -#include <errno.h> -#include <time.h> - -#include "s2n.h" - -#if defined(S2N_CPUID_AVAILABLE) -#include <cpuid.h> -#endif - -#include "stuffer/s2n_stuffer.h" - -#include "crypto/s2n_drbg.h" - -#include "error/s2n_errno.h" - -#include "utils/s2n_result.h" -#include "utils/s2n_safety.h" -#include "utils/s2n_random.h" -#include "utils/s2n_mem.h" - -#include <openssl/rand.h> - -#define ENTROPY_SOURCE "/dev/urandom" - -/* See https://en.wikipedia.org/wiki/CPUID */ -#define RDRAND_ECX_FLAG 0x40000000 - -/* One second in nanoseconds */ -#define ONE_S INT64_C(1000000000) - -/* Placeholder value for an uninitialized entropy file descriptor */ -#define UNINITIALIZED_ENTROPY_FD -1 - -static int entropy_fd = UNINITIALIZED_ENTROPY_FD; - -static __thread struct s2n_drbg per_thread_private_drbg = {0}; -static __thread struct s2n_drbg per_thread_public_drbg = {0}; - -static void *zeroed_when_forked_page; -static int zero = 0; - -static __thread void *zero_if_forked_ptr = &zero; -#define zero_if_forked (* (int *) zero_if_forked_ptr) - -static int s2n_rand_init_impl(void); -static int s2n_rand_cleanup_impl(void); -static int s2n_rand_urandom_impl(void *ptr, uint32_t size); -static int s2n_rand_rdrand_impl(void *ptr, uint32_t size); - -static s2n_rand_init_callback s2n_rand_init_cb = s2n_rand_init_impl; -static s2n_rand_cleanup_callback s2n_rand_cleanup_cb = s2n_rand_cleanup_impl; -static s2n_rand_seed_callback s2n_rand_seed_cb = s2n_rand_urandom_impl; -static s2n_rand_mix_callback s2n_rand_mix_cb = s2n_rand_urandom_impl; - -bool s2n_cpu_supports_rdrand() { -#if defined(S2N_CPUID_AVAILABLE) - uint32_t eax, ebx, ecx, edx; - if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { - return false; - } - - if (ecx & RDRAND_ECX_FLAG) { - return true; - } -#endif - return false; -} - -int s2n_rand_set_callbacks(s2n_rand_init_callback rand_init_callback, - s2n_rand_cleanup_callback rand_cleanup_callback, - s2n_rand_seed_callback rand_seed_callback, - s2n_rand_mix_callback rand_mix_callback) -{ - s2n_rand_init_cb = rand_init_callback; - s2n_rand_cleanup_cb = rand_cleanup_callback; - s2n_rand_seed_cb = rand_seed_callback; - s2n_rand_mix_cb = rand_mix_callback; - - return S2N_SUCCESS; -} - -S2N_RESULT s2n_get_seed_entropy(struct s2n_blob *blob) -{ - ENSURE_REF(blob); - - GUARD_AS_RESULT(s2n_rand_seed_cb(blob->data, blob->size)); - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_get_mix_entropy(struct s2n_blob *blob) -{ - ENSURE_REF(blob); - - GUARD_AS_RESULT(s2n_rand_mix_cb(blob->data, blob->size)); - - return S2N_RESULT_OK; -} - -void s2n_on_fork(void) -{ - zero_if_forked = 0; -} - -static inline S2N_RESULT s2n_defend_if_forked(void) -{ - uint8_t s2n_public_drbg[] = "s2n public drbg"; - uint8_t s2n_private_drbg[] = "s2n private drbg"; - struct s2n_blob public = {.data = s2n_public_drbg,.size = sizeof(s2n_public_drbg) }; - struct s2n_blob private = {.data = s2n_private_drbg,.size = sizeof(s2n_private_drbg) }; - - if (zero_if_forked == 0) { - /* Clean up the old drbg first */ - GUARD_RESULT(s2n_rand_cleanup_thread()); - /* Instantiate the new ones */ - GUARD_AS_RESULT(s2n_drbg_instantiate(&per_thread_public_drbg, &public, S2N_AES_128_CTR_NO_DF_PR)); - GUARD_AS_RESULT(s2n_drbg_instantiate(&per_thread_private_drbg, &private, S2N_AES_128_CTR_NO_DF_PR)); - zero_if_forked_ptr = zeroed_when_forked_page; - zero_if_forked = 1; - } - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_get_public_random_data(struct s2n_blob *blob) -{ - GUARD_RESULT(s2n_defend_if_forked()); - - uint32_t offset = 0; - uint32_t remaining = blob->size; - - while(remaining) { - struct s2n_blob slice = { 0 }; - - GUARD_AS_RESULT(s2n_blob_slice(blob, &slice, offset, MIN(remaining, S2N_DRBG_GENERATE_LIMIT)));; - - GUARD_AS_RESULT(s2n_drbg_generate(&per_thread_public_drbg, &slice)); - - remaining -= slice.size; - offset += slice.size; - } - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_get_private_random_data(struct s2n_blob *blob) -{ - GUARD_RESULT(s2n_defend_if_forked()); - - uint32_t offset = 0; - uint32_t remaining = blob->size; - - while(remaining) { - struct s2n_blob slice = { 0 }; - - GUARD_AS_RESULT(s2n_blob_slice(blob, &slice, offset, MIN(remaining, S2N_DRBG_GENERATE_LIMIT)));; - - GUARD_AS_RESULT(s2n_drbg_generate(&per_thread_private_drbg, &slice)); - - remaining -= slice.size; - offset += slice.size; - } - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_get_public_random_bytes_used(uint64_t *bytes_used) -{ - GUARD_AS_RESULT(s2n_drbg_bytes_used(&per_thread_public_drbg, bytes_used)); - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_get_private_random_bytes_used(uint64_t *bytes_used) -{ - GUARD_AS_RESULT(s2n_drbg_bytes_used(&per_thread_private_drbg, bytes_used)); - return S2N_RESULT_OK; -} - -static int s2n_rand_urandom_impl(void *ptr, uint32_t size) -{ - ENSURE_POSIX(entropy_fd != UNINITIALIZED_ENTROPY_FD, S2N_ERR_NOT_INITIALIZED); - - uint8_t *data = ptr; - uint32_t n = size; - struct timespec sleep_time = {.tv_sec = 0, .tv_nsec = 0 }; - long backoff = 1; - - while (n) { - errno = 0; - int r = read(entropy_fd, data, n); - if (r <= 0) { - /* - * A non-blocking read() on /dev/urandom should "never" fail, - * except for EINTR. If it does, briefly pause and use - * exponential backoff to avoid creating a tight spinning loop. - * - * iteration delay - * --------- ----------------- - * 1 10 nsec - * 2 100 nsec - * 3 1,000 nsec - * 4 10,000 nsec - * 5 100,000 nsec - * 6 1,000,000 nsec - * 7 10,000,000 nsec - * 8 99,999,999 nsec - * 9 99,999,999 nsec - * ... - */ - if (errno != EINTR) { - backoff = MIN(backoff * 10, ONE_S - 1); - sleep_time.tv_nsec = backoff; - do { - r = nanosleep(&sleep_time, &sleep_time); - } - while (r != 0); - } - - continue; - } - - data += r; - n -= r; - } - - return S2N_SUCCESS; -} - -/* - * Return a random number in the range [0, bound) - */ -S2N_RESULT s2n_public_random(int64_t bound, uint64_t *output) -{ - uint64_t r; - - ENSURE_GT(bound, 0); - - while (1) { - struct s2n_blob blob = {.data = (void *)&r, sizeof(r) }; - GUARD_RESULT(s2n_get_public_random_data(&blob)); - - /* Imagine an int was one byte and UINT_MAX was 256. If the - * caller asked for s2n_random(129, ...) we'd end up in - * trouble. Each number in the range 0...127 would be twice - * as likely as 128. That's because r == 0 % 129 -> 0, and - * r == 129 % 129 -> 0, but only r == 128 returns 128, - * r == 257 is out of range. - * - * To de-bias the dice, we discard values of r that are higher - * that the highest multiple of 'bound' an int can support. If - * bound is a uint, then in the worst case we discard 50% - 1 r's. - * But since 'bound' is an int and INT_MAX is <= UINT_MAX / 2, - * in the worst case we discard 25% - 1 r's. - */ - if (r < (UINT64_MAX - (UINT64_MAX % bound))) { - *output = r % bound; - return S2N_RESULT_OK; - } - } -} - -#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND - -int s2n_openssl_compat_rand(unsigned char *buf, int num) -{ - struct s2n_blob out = {.data = buf,.size = num }; - - if (s2n_result_is_error(s2n_get_private_random_data(&out))) { - return 0; - } - return 1; -} - -int s2n_openssl_compat_status(void) -{ - return 1; -} - -int s2n_openssl_compat_init(ENGINE * unused) -{ - return 1; -} - -RAND_METHOD s2n_openssl_rand_method = { - .seed = NULL, - .bytes = s2n_openssl_compat_rand, - .cleanup = NULL, - .add = NULL, - .pseudorand = s2n_openssl_compat_rand, - .status = s2n_openssl_compat_status -}; -#endif - -static int s2n_rand_init_impl(void) -{ - OPEN: - entropy_fd = open(ENTROPY_SOURCE, O_RDONLY); - if (entropy_fd == S2N_FAILURE) { - if (errno == EINTR) { - goto OPEN; - } - S2N_ERROR(S2N_ERR_OPEN_RANDOM); - } - - if (s2n_cpu_supports_rdrand()) { - s2n_rand_mix_cb = s2n_rand_rdrand_impl; - } - - return S2N_SUCCESS; -} - -S2N_RESULT s2n_rand_init(void) -{ - uint32_t pagesize; - - GUARD_AS_RESULT(s2n_rand_init_cb()); - - pagesize = s2n_mem_get_page_size(); - - /* We need a single-aligned page for our protected memory region */ - ENSURE(posix_memalign(&zeroed_when_forked_page, pagesize, pagesize) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); - ENSURE(zeroed_when_forked_page != NULL, S2N_ERR_OPEN_RANDOM); - - /* Initialized to zero to ensure that we seed our DRBGs */ - zero_if_forked = 0; - - /* INHERIT_ZERO and WIPEONFORK reset a page to all-zeroes when a fork occurs */ -#if defined(MAP_INHERIT_ZERO) - ENSURE(minherit(zeroed_when_forked_page, pagesize, MAP_INHERIT_ZERO) != S2N_FAILURE, S2N_ERR_OPEN_RANDOM); -#endif - -#if defined(MADV_WIPEONFORK) - ENSURE(madvise(zeroed_when_forked_page, pagesize, MADV_WIPEONFORK) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); -#endif - - /* For defence in depth */ - ENSURE(pthread_atfork(NULL, NULL, s2n_on_fork) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); - - /* Seed everything */ - GUARD_RESULT(s2n_defend_if_forked()); - -#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND - /* Create an engine */ - ENGINE *e = ENGINE_new(); - - ENSURE(e != NULL, S2N_ERR_OPEN_RANDOM); - GUARD_RESULT_OSSL(ENGINE_set_id(e, "s2n_rand"), S2N_ERR_OPEN_RANDOM); - GUARD_RESULT_OSSL(ENGINE_set_name(e, "s2n entropy generator"), S2N_ERR_OPEN_RANDOM); - GUARD_RESULT_OSSL(ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL), S2N_ERR_OPEN_RANDOM); - GUARD_RESULT_OSSL(ENGINE_set_init_function(e, s2n_openssl_compat_init), S2N_ERR_OPEN_RANDOM); - GUARD_RESULT_OSSL(ENGINE_set_RAND(e, &s2n_openssl_rand_method), S2N_ERR_OPEN_RANDOM); - GUARD_RESULT_OSSL(ENGINE_add(e), S2N_ERR_OPEN_RANDOM); - GUARD_RESULT_OSSL(ENGINE_free(e) , S2N_ERR_OPEN_RANDOM); - - /* Use that engine for rand() */ - e = ENGINE_by_id("s2n_rand"); - ENSURE(e != NULL, S2N_ERR_OPEN_RANDOM); - GUARD_RESULT_OSSL(ENGINE_init(e), S2N_ERR_OPEN_RANDOM); - GUARD_RESULT_OSSL(ENGINE_set_default(e, ENGINE_METHOD_RAND), S2N_ERR_OPEN_RANDOM); - GUARD_RESULT_OSSL(ENGINE_free(e), S2N_ERR_OPEN_RANDOM); -#endif - - return S2N_RESULT_OK; -} - -static int s2n_rand_cleanup_impl(void) -{ - ENSURE_POSIX(entropy_fd != UNINITIALIZED_ENTROPY_FD, S2N_ERR_NOT_INITIALIZED); - - GUARD(close(entropy_fd)); - entropy_fd = UNINITIALIZED_ENTROPY_FD; - - return S2N_SUCCESS; -} - -S2N_RESULT s2n_rand_cleanup(void) -{ - GUARD_AS_RESULT(s2n_rand_cleanup_cb()); - -#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND - /* Cleanup our rand ENGINE in libcrypto */ - ENGINE *rand_engine = ENGINE_by_id("s2n_rand"); - if (rand_engine) { - ENGINE_finish(rand_engine); - ENGINE_free(rand_engine); - ENGINE_cleanup(); - } -#endif - - s2n_rand_init_cb = s2n_rand_init_impl; - s2n_rand_cleanup_cb = s2n_rand_cleanup_impl; - s2n_rand_seed_cb = s2n_rand_urandom_impl; - s2n_rand_mix_cb = s2n_rand_urandom_impl; - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_rand_cleanup_thread(void) -{ - GUARD_AS_RESULT(s2n_drbg_wipe(&per_thread_private_drbg)); - GUARD_AS_RESULT(s2n_drbg_wipe(&per_thread_public_drbg)); - - return S2N_RESULT_OK; -} - -/* - * This must only be used for unit tests. Any real use is dangerous and will be overwritten in s2n_defend_if_forked if - * it is forked. This was added to support known answer tests that use OpenSSL and s2n_get_private_random_data directly. - */ -S2N_RESULT s2n_set_private_drbg_for_test(struct s2n_drbg drbg) -{ - ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); - GUARD_AS_RESULT(s2n_drbg_wipe(&per_thread_private_drbg)); - - per_thread_private_drbg = drbg; - return S2N_RESULT_OK; -} - -/* - * volatile is important to prevent the compiler from - * re-ordering or optimizing the use of RDRAND. - */ -static int s2n_rand_rdrand_impl(void *data, uint32_t size) -{ -#if defined(__x86_64__) || defined(__i386__) - struct s2n_blob out = { .data = data, .size = size }; - int space_remaining = 0; - struct s2n_stuffer stuffer = {0}; - union { - uint64_t u64; -#if defined(__i386__) - struct { - /* since we check first that we're on intel, we can safely assume little endian. */ - uint32_t u_low; - uint32_t u_high; - } i386_fields; -#endif /* defined(__i386__) */ - uint8_t u8[8]; - } output; - - GUARD(s2n_stuffer_init(&stuffer, &out)); - while ((space_remaining = s2n_stuffer_space_remaining(&stuffer))) { - unsigned char success = 0; - output.u64 = 0; - - for (int tries = 0; tries < 10; tries++) { -#if defined(__i386__) - /* execute the rdrand instruction, store the result in a general purpose register (it's assigned to - * output.i386_fields.u_low). Check the carry bit, which will be set on success. Then clober the register and reset - * the carry bit. Due to needing to support an ancient assembler we use the opcode syntax. - * the %b1 is to force compilers to use c1 instead of ecx. - * Here's a description of how the opcode is encoded: - * 0x0fc7 (rdrand) - * 0xf0 (store the result in eax). - */ - unsigned char success_high = 0, success_low = 0; - __asm__ __volatile__(".byte 0x0f, 0xc7, 0xf0;\n" "setc %b1;\n": "=a"(output.i386_fields.u_low), "=qm"(success_low) - : - :"cc"); - - __asm__ __volatile__(".byte 0x0f, 0xc7, 0xf0;\n" "setc %b1;\n": "=a"(output.i386_fields.u_high), "=qm"(success_high) - : - :"cc"); - /* cppcheck-suppress knownConditionTrueFalse */ - success = success_high & success_low; - - /* Treat either all 1 or all 0 bits in either the high or low order - * bits as failure */ - if (output.i386_fields.u_low == 0 || - output.i386_fields.u_low == UINT32_MAX || - output.i386_fields.u_high == 0 || - output.i386_fields.u_high == UINT32_MAX) { - success = 0; - } -#else - /* execute the rdrand instruction, store the result in a general purpose register (it's assigned to - * output.u64). Check the carry bit, which will be set on success. Then clober the carry bit. - * Due to needing to support an ancient assembler we use the opcode syntax. - * the %b1 is to force compilers to use c1 instead of ecx. - * Here's a description of how the opcode is encoded: - * 0x48 (pick a 64-bit register it does more too, but that's all that matters there) - * 0x0fc7 (rdrand) - * 0xf0 (store the result in rax). */ - __asm__ __volatile__(".byte 0x48, 0x0f, 0xc7, 0xf0;\n" "setc %b1;\n": "=a"(output.u64), "=qm"(success) - : - :"cc"); -#endif /* defined(__i386__) */ - - /* Some AMD CPUs will find that RDRAND "sticks" on all 1s but still reports success. - * Some other very old CPUs use all 0s as an error condition while still reporting success. - * If we encounter either of these suspicious values (a 1/2^63 chance) we'll treat them as - * a failure and generate a new value. - * - * In the future we could add CPUID checks to detect processors with these known bugs, - * however it does not appear worth it. The entropy loss is negligible and the - * corresponding likelihood that a healthy CPU generates either of these values is also - * negligible (1/2^63). Finally, adding processor specific logic would greatly - * increase the complexity and would cause us to "miss" any unknown processors with - * similar bugs. */ - if (output.u64 == UINT64_MAX || - output.u64 == 0) { - success = 0; - } - - if (success) { - break; - } - } - - ENSURE_POSIX(success, S2N_ERR_RDRAND_FAILED); - - int data_to_fill = MIN(sizeof(output), space_remaining); - - GUARD_POSIX(s2n_stuffer_write_bytes(&stuffer, output.u8, data_to_fill)); - } - - return S2N_SUCCESS; -#else - BAIL_POSIX(S2N_ERR_UNSUPPORTED_CPU); -#endif -} +/* + * 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 <openssl/engine.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <unistd.h> +#include <pthread.h> +#include <limits.h> +#include <fcntl.h> +#include <string.h> +#include <stdint.h> +#include <stdlib.h> +#include <errno.h> +#include <time.h> + +#include "s2n.h" + +#if defined(S2N_CPUID_AVAILABLE) +#include <cpuid.h> +#endif + +#include "stuffer/s2n_stuffer.h" + +#include "crypto/s2n_drbg.h" + +#include "error/s2n_errno.h" + +#include "utils/s2n_result.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_random.h" +#include "utils/s2n_mem.h" + +#include <openssl/rand.h> + +#define ENTROPY_SOURCE "/dev/urandom" + +/* See https://en.wikipedia.org/wiki/CPUID */ +#define RDRAND_ECX_FLAG 0x40000000 + +/* One second in nanoseconds */ +#define ONE_S INT64_C(1000000000) + +/* Placeholder value for an uninitialized entropy file descriptor */ +#define UNINITIALIZED_ENTROPY_FD -1 + +static int entropy_fd = UNINITIALIZED_ENTROPY_FD; + +static __thread struct s2n_drbg per_thread_private_drbg = {0}; +static __thread struct s2n_drbg per_thread_public_drbg = {0}; + +static void *zeroed_when_forked_page; +static int zero = 0; + +static __thread void *zero_if_forked_ptr = &zero; +#define zero_if_forked (* (int *) zero_if_forked_ptr) + +static int s2n_rand_init_impl(void); +static int s2n_rand_cleanup_impl(void); +static int s2n_rand_urandom_impl(void *ptr, uint32_t size); +static int s2n_rand_rdrand_impl(void *ptr, uint32_t size); + +static s2n_rand_init_callback s2n_rand_init_cb = s2n_rand_init_impl; +static s2n_rand_cleanup_callback s2n_rand_cleanup_cb = s2n_rand_cleanup_impl; +static s2n_rand_seed_callback s2n_rand_seed_cb = s2n_rand_urandom_impl; +static s2n_rand_mix_callback s2n_rand_mix_cb = s2n_rand_urandom_impl; + +bool s2n_cpu_supports_rdrand() { +#if defined(S2N_CPUID_AVAILABLE) + uint32_t eax, ebx, ecx, edx; + if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { + return false; + } + + if (ecx & RDRAND_ECX_FLAG) { + return true; + } +#endif + return false; +} + +int s2n_rand_set_callbacks(s2n_rand_init_callback rand_init_callback, + s2n_rand_cleanup_callback rand_cleanup_callback, + s2n_rand_seed_callback rand_seed_callback, + s2n_rand_mix_callback rand_mix_callback) +{ + s2n_rand_init_cb = rand_init_callback; + s2n_rand_cleanup_cb = rand_cleanup_callback; + s2n_rand_seed_cb = rand_seed_callback; + s2n_rand_mix_cb = rand_mix_callback; + + return S2N_SUCCESS; +} + +S2N_RESULT s2n_get_seed_entropy(struct s2n_blob *blob) +{ + ENSURE_REF(blob); + + GUARD_AS_RESULT(s2n_rand_seed_cb(blob->data, blob->size)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_get_mix_entropy(struct s2n_blob *blob) +{ + ENSURE_REF(blob); + + GUARD_AS_RESULT(s2n_rand_mix_cb(blob->data, blob->size)); + + return S2N_RESULT_OK; +} + +void s2n_on_fork(void) +{ + zero_if_forked = 0; +} + +static inline S2N_RESULT s2n_defend_if_forked(void) +{ + uint8_t s2n_public_drbg[] = "s2n public drbg"; + uint8_t s2n_private_drbg[] = "s2n private drbg"; + struct s2n_blob public = {.data = s2n_public_drbg,.size = sizeof(s2n_public_drbg) }; + struct s2n_blob private = {.data = s2n_private_drbg,.size = sizeof(s2n_private_drbg) }; + + if (zero_if_forked == 0) { + /* Clean up the old drbg first */ + GUARD_RESULT(s2n_rand_cleanup_thread()); + /* Instantiate the new ones */ + GUARD_AS_RESULT(s2n_drbg_instantiate(&per_thread_public_drbg, &public, S2N_AES_128_CTR_NO_DF_PR)); + GUARD_AS_RESULT(s2n_drbg_instantiate(&per_thread_private_drbg, &private, S2N_AES_128_CTR_NO_DF_PR)); + zero_if_forked_ptr = zeroed_when_forked_page; + zero_if_forked = 1; + } + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_get_public_random_data(struct s2n_blob *blob) +{ + GUARD_RESULT(s2n_defend_if_forked()); + + uint32_t offset = 0; + uint32_t remaining = blob->size; + + while(remaining) { + struct s2n_blob slice = { 0 }; + + GUARD_AS_RESULT(s2n_blob_slice(blob, &slice, offset, MIN(remaining, S2N_DRBG_GENERATE_LIMIT)));; + + GUARD_AS_RESULT(s2n_drbg_generate(&per_thread_public_drbg, &slice)); + + remaining -= slice.size; + offset += slice.size; + } + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_get_private_random_data(struct s2n_blob *blob) +{ + GUARD_RESULT(s2n_defend_if_forked()); + + uint32_t offset = 0; + uint32_t remaining = blob->size; + + while(remaining) { + struct s2n_blob slice = { 0 }; + + GUARD_AS_RESULT(s2n_blob_slice(blob, &slice, offset, MIN(remaining, S2N_DRBG_GENERATE_LIMIT)));; + + GUARD_AS_RESULT(s2n_drbg_generate(&per_thread_private_drbg, &slice)); + + remaining -= slice.size; + offset += slice.size; + } + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_get_public_random_bytes_used(uint64_t *bytes_used) +{ + GUARD_AS_RESULT(s2n_drbg_bytes_used(&per_thread_public_drbg, bytes_used)); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_get_private_random_bytes_used(uint64_t *bytes_used) +{ + GUARD_AS_RESULT(s2n_drbg_bytes_used(&per_thread_private_drbg, bytes_used)); + return S2N_RESULT_OK; +} + +static int s2n_rand_urandom_impl(void *ptr, uint32_t size) +{ + ENSURE_POSIX(entropy_fd != UNINITIALIZED_ENTROPY_FD, S2N_ERR_NOT_INITIALIZED); + + uint8_t *data = ptr; + uint32_t n = size; + struct timespec sleep_time = {.tv_sec = 0, .tv_nsec = 0 }; + long backoff = 1; + + while (n) { + errno = 0; + int r = read(entropy_fd, data, n); + if (r <= 0) { + /* + * A non-blocking read() on /dev/urandom should "never" fail, + * except for EINTR. If it does, briefly pause and use + * exponential backoff to avoid creating a tight spinning loop. + * + * iteration delay + * --------- ----------------- + * 1 10 nsec + * 2 100 nsec + * 3 1,000 nsec + * 4 10,000 nsec + * 5 100,000 nsec + * 6 1,000,000 nsec + * 7 10,000,000 nsec + * 8 99,999,999 nsec + * 9 99,999,999 nsec + * ... + */ + if (errno != EINTR) { + backoff = MIN(backoff * 10, ONE_S - 1); + sleep_time.tv_nsec = backoff; + do { + r = nanosleep(&sleep_time, &sleep_time); + } + while (r != 0); + } + + continue; + } + + data += r; + n -= r; + } + + return S2N_SUCCESS; +} + +/* + * Return a random number in the range [0, bound) + */ +S2N_RESULT s2n_public_random(int64_t bound, uint64_t *output) +{ + uint64_t r; + + ENSURE_GT(bound, 0); + + while (1) { + struct s2n_blob blob = {.data = (void *)&r, sizeof(r) }; + GUARD_RESULT(s2n_get_public_random_data(&blob)); + + /* Imagine an int was one byte and UINT_MAX was 256. If the + * caller asked for s2n_random(129, ...) we'd end up in + * trouble. Each number in the range 0...127 would be twice + * as likely as 128. That's because r == 0 % 129 -> 0, and + * r == 129 % 129 -> 0, but only r == 128 returns 128, + * r == 257 is out of range. + * + * To de-bias the dice, we discard values of r that are higher + * that the highest multiple of 'bound' an int can support. If + * bound is a uint, then in the worst case we discard 50% - 1 r's. + * But since 'bound' is an int and INT_MAX is <= UINT_MAX / 2, + * in the worst case we discard 25% - 1 r's. + */ + if (r < (UINT64_MAX - (UINT64_MAX % bound))) { + *output = r % bound; + return S2N_RESULT_OK; + } + } +} + +#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND + +int s2n_openssl_compat_rand(unsigned char *buf, int num) +{ + struct s2n_blob out = {.data = buf,.size = num }; + + if (s2n_result_is_error(s2n_get_private_random_data(&out))) { + return 0; + } + return 1; +} + +int s2n_openssl_compat_status(void) +{ + return 1; +} + +int s2n_openssl_compat_init(ENGINE * unused) +{ + return 1; +} + +RAND_METHOD s2n_openssl_rand_method = { + .seed = NULL, + .bytes = s2n_openssl_compat_rand, + .cleanup = NULL, + .add = NULL, + .pseudorand = s2n_openssl_compat_rand, + .status = s2n_openssl_compat_status +}; +#endif + +static int s2n_rand_init_impl(void) +{ + OPEN: + entropy_fd = open(ENTROPY_SOURCE, O_RDONLY); + if (entropy_fd == S2N_FAILURE) { + if (errno == EINTR) { + goto OPEN; + } + S2N_ERROR(S2N_ERR_OPEN_RANDOM); + } + + if (s2n_cpu_supports_rdrand()) { + s2n_rand_mix_cb = s2n_rand_rdrand_impl; + } + + return S2N_SUCCESS; +} + +S2N_RESULT s2n_rand_init(void) +{ + uint32_t pagesize; + + GUARD_AS_RESULT(s2n_rand_init_cb()); + + pagesize = s2n_mem_get_page_size(); + + /* We need a single-aligned page for our protected memory region */ + ENSURE(posix_memalign(&zeroed_when_forked_page, pagesize, pagesize) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); + ENSURE(zeroed_when_forked_page != NULL, S2N_ERR_OPEN_RANDOM); + + /* Initialized to zero to ensure that we seed our DRBGs */ + zero_if_forked = 0; + + /* INHERIT_ZERO and WIPEONFORK reset a page to all-zeroes when a fork occurs */ +#if defined(MAP_INHERIT_ZERO) + ENSURE(minherit(zeroed_when_forked_page, pagesize, MAP_INHERIT_ZERO) != S2N_FAILURE, S2N_ERR_OPEN_RANDOM); +#endif + +#if defined(MADV_WIPEONFORK) + ENSURE(madvise(zeroed_when_forked_page, pagesize, MADV_WIPEONFORK) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); +#endif + + /* For defence in depth */ + ENSURE(pthread_atfork(NULL, NULL, s2n_on_fork) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); + + /* Seed everything */ + GUARD_RESULT(s2n_defend_if_forked()); + +#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND + /* Create an engine */ + ENGINE *e = ENGINE_new(); + + ENSURE(e != NULL, S2N_ERR_OPEN_RANDOM); + GUARD_RESULT_OSSL(ENGINE_set_id(e, "s2n_rand"), S2N_ERR_OPEN_RANDOM); + GUARD_RESULT_OSSL(ENGINE_set_name(e, "s2n entropy generator"), S2N_ERR_OPEN_RANDOM); + GUARD_RESULT_OSSL(ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL), S2N_ERR_OPEN_RANDOM); + GUARD_RESULT_OSSL(ENGINE_set_init_function(e, s2n_openssl_compat_init), S2N_ERR_OPEN_RANDOM); + GUARD_RESULT_OSSL(ENGINE_set_RAND(e, &s2n_openssl_rand_method), S2N_ERR_OPEN_RANDOM); + GUARD_RESULT_OSSL(ENGINE_add(e), S2N_ERR_OPEN_RANDOM); + GUARD_RESULT_OSSL(ENGINE_free(e) , S2N_ERR_OPEN_RANDOM); + + /* Use that engine for rand() */ + e = ENGINE_by_id("s2n_rand"); + ENSURE(e != NULL, S2N_ERR_OPEN_RANDOM); + GUARD_RESULT_OSSL(ENGINE_init(e), S2N_ERR_OPEN_RANDOM); + GUARD_RESULT_OSSL(ENGINE_set_default(e, ENGINE_METHOD_RAND), S2N_ERR_OPEN_RANDOM); + GUARD_RESULT_OSSL(ENGINE_free(e), S2N_ERR_OPEN_RANDOM); +#endif + + return S2N_RESULT_OK; +} + +static int s2n_rand_cleanup_impl(void) +{ + ENSURE_POSIX(entropy_fd != UNINITIALIZED_ENTROPY_FD, S2N_ERR_NOT_INITIALIZED); + + GUARD(close(entropy_fd)); + entropy_fd = UNINITIALIZED_ENTROPY_FD; + + return S2N_SUCCESS; +} + +S2N_RESULT s2n_rand_cleanup(void) +{ + GUARD_AS_RESULT(s2n_rand_cleanup_cb()); + +#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND + /* Cleanup our rand ENGINE in libcrypto */ + ENGINE *rand_engine = ENGINE_by_id("s2n_rand"); + if (rand_engine) { + ENGINE_finish(rand_engine); + ENGINE_free(rand_engine); + ENGINE_cleanup(); + } +#endif + + s2n_rand_init_cb = s2n_rand_init_impl; + s2n_rand_cleanup_cb = s2n_rand_cleanup_impl; + s2n_rand_seed_cb = s2n_rand_urandom_impl; + s2n_rand_mix_cb = s2n_rand_urandom_impl; + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_rand_cleanup_thread(void) +{ + GUARD_AS_RESULT(s2n_drbg_wipe(&per_thread_private_drbg)); + GUARD_AS_RESULT(s2n_drbg_wipe(&per_thread_public_drbg)); + + return S2N_RESULT_OK; +} + +/* + * This must only be used for unit tests. Any real use is dangerous and will be overwritten in s2n_defend_if_forked if + * it is forked. This was added to support known answer tests that use OpenSSL and s2n_get_private_random_data directly. + */ +S2N_RESULT s2n_set_private_drbg_for_test(struct s2n_drbg drbg) +{ + ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); + GUARD_AS_RESULT(s2n_drbg_wipe(&per_thread_private_drbg)); + + per_thread_private_drbg = drbg; + return S2N_RESULT_OK; +} + +/* + * volatile is important to prevent the compiler from + * re-ordering or optimizing the use of RDRAND. + */ +static int s2n_rand_rdrand_impl(void *data, uint32_t size) +{ +#if defined(__x86_64__) || defined(__i386__) + struct s2n_blob out = { .data = data, .size = size }; + int space_remaining = 0; + struct s2n_stuffer stuffer = {0}; + union { + uint64_t u64; +#if defined(__i386__) + struct { + /* since we check first that we're on intel, we can safely assume little endian. */ + uint32_t u_low; + uint32_t u_high; + } i386_fields; +#endif /* defined(__i386__) */ + uint8_t u8[8]; + } output; + + GUARD(s2n_stuffer_init(&stuffer, &out)); + while ((space_remaining = s2n_stuffer_space_remaining(&stuffer))) { + unsigned char success = 0; + output.u64 = 0; + + for (int tries = 0; tries < 10; tries++) { +#if defined(__i386__) + /* execute the rdrand instruction, store the result in a general purpose register (it's assigned to + * output.i386_fields.u_low). Check the carry bit, which will be set on success. Then clober the register and reset + * the carry bit. Due to needing to support an ancient assembler we use the opcode syntax. + * the %b1 is to force compilers to use c1 instead of ecx. + * Here's a description of how the opcode is encoded: + * 0x0fc7 (rdrand) + * 0xf0 (store the result in eax). + */ + unsigned char success_high = 0, success_low = 0; + __asm__ __volatile__(".byte 0x0f, 0xc7, 0xf0;\n" "setc %b1;\n": "=a"(output.i386_fields.u_low), "=qm"(success_low) + : + :"cc"); + + __asm__ __volatile__(".byte 0x0f, 0xc7, 0xf0;\n" "setc %b1;\n": "=a"(output.i386_fields.u_high), "=qm"(success_high) + : + :"cc"); + /* cppcheck-suppress knownConditionTrueFalse */ + success = success_high & success_low; + + /* Treat either all 1 or all 0 bits in either the high or low order + * bits as failure */ + if (output.i386_fields.u_low == 0 || + output.i386_fields.u_low == UINT32_MAX || + output.i386_fields.u_high == 0 || + output.i386_fields.u_high == UINT32_MAX) { + success = 0; + } +#else + /* execute the rdrand instruction, store the result in a general purpose register (it's assigned to + * output.u64). Check the carry bit, which will be set on success. Then clober the carry bit. + * Due to needing to support an ancient assembler we use the opcode syntax. + * the %b1 is to force compilers to use c1 instead of ecx. + * Here's a description of how the opcode is encoded: + * 0x48 (pick a 64-bit register it does more too, but that's all that matters there) + * 0x0fc7 (rdrand) + * 0xf0 (store the result in rax). */ + __asm__ __volatile__(".byte 0x48, 0x0f, 0xc7, 0xf0;\n" "setc %b1;\n": "=a"(output.u64), "=qm"(success) + : + :"cc"); +#endif /* defined(__i386__) */ + + /* Some AMD CPUs will find that RDRAND "sticks" on all 1s but still reports success. + * Some other very old CPUs use all 0s as an error condition while still reporting success. + * If we encounter either of these suspicious values (a 1/2^63 chance) we'll treat them as + * a failure and generate a new value. + * + * In the future we could add CPUID checks to detect processors with these known bugs, + * however it does not appear worth it. The entropy loss is negligible and the + * corresponding likelihood that a healthy CPU generates either of these values is also + * negligible (1/2^63). Finally, adding processor specific logic would greatly + * increase the complexity and would cause us to "miss" any unknown processors with + * similar bugs. */ + if (output.u64 == UINT64_MAX || + output.u64 == 0) { + success = 0; + } + + if (success) { + break; + } + } + + ENSURE_POSIX(success, S2N_ERR_RDRAND_FAILED); + + int data_to_fill = MIN(sizeof(output), space_remaining); + + GUARD_POSIX(s2n_stuffer_write_bytes(&stuffer, output.u8, data_to_fill)); + } + + return S2N_SUCCESS; +#else + BAIL_POSIX(S2N_ERR_UNSUPPORTED_CPU); +#endif +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_random.h b/contrib/restricted/aws/s2n/utils/s2n_random.h index 1d316328b9..15efe7cd10 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_random.h +++ b/contrib/restricted/aws/s2n/utils/s2n_random.h @@ -1,34 +1,34 @@ -/* - * 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 "crypto/s2n_drbg.h" - -#include "utils/s2n_blob.h" -#include "utils/s2n_result.h" - -extern S2N_RESULT s2n_rand_init(void); -extern S2N_RESULT s2n_rand_cleanup(void); -extern S2N_RESULT s2n_get_seed_entropy(struct s2n_blob *blob); -extern S2N_RESULT s2n_get_mix_entropy(struct s2n_blob *blob); - -extern S2N_RESULT s2n_rand_cleanup_thread(void); -extern S2N_RESULT s2n_set_private_drbg_for_test(struct s2n_drbg drbg); -extern S2N_RESULT s2n_get_public_random_data(struct s2n_blob *blob); -extern S2N_RESULT s2n_get_public_random_bytes_used(uint64_t *bytes_used); -extern S2N_RESULT s2n_get_private_random_data(struct s2n_blob *blob); -extern S2N_RESULT s2n_get_private_random_bytes_used(uint64_t *bytes_used); -extern S2N_RESULT s2n_public_random(int64_t max, uint64_t *output); +/* + * 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 "crypto/s2n_drbg.h" + +#include "utils/s2n_blob.h" +#include "utils/s2n_result.h" + +extern S2N_RESULT s2n_rand_init(void); +extern S2N_RESULT s2n_rand_cleanup(void); +extern S2N_RESULT s2n_get_seed_entropy(struct s2n_blob *blob); +extern S2N_RESULT s2n_get_mix_entropy(struct s2n_blob *blob); + +extern S2N_RESULT s2n_rand_cleanup_thread(void); +extern S2N_RESULT s2n_set_private_drbg_for_test(struct s2n_drbg drbg); +extern S2N_RESULT s2n_get_public_random_data(struct s2n_blob *blob); +extern S2N_RESULT s2n_get_public_random_bytes_used(uint64_t *bytes_used); +extern S2N_RESULT s2n_get_private_random_data(struct s2n_blob *blob); +extern S2N_RESULT s2n_get_private_random_bytes_used(uint64_t *bytes_used); +extern S2N_RESULT s2n_public_random(int64_t max, uint64_t *output); diff --git a/contrib/restricted/aws/s2n/utils/s2n_result.c b/contrib/restricted/aws/s2n/utils/s2n_result.c index 022fcc3711..3f851a0697 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_result.c +++ b/contrib/restricted/aws/s2n/utils/s2n_result.c @@ -1,93 +1,93 @@ -/* - * 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. - */ - -/* - * The goal of s2n_result is to provide a strongly-typed error - * signal value, which provides the compiler with enough information - * to catch bugs. - * - * Historically, s2n has used int to signal errors. This has caused a few issues: - * - * ## GUARD in a function returning integer types - * - * There is no compiler error if `GUARD(nested_call());` is used in a function - * that is meant to return integer type - not a error signal. - * - * ```c - * uint8_t s2n_answer_to_the_ultimate_question() { - * GUARD(s2n_sleep_for_years(7500000)); - * return 42; - * } - * ``` - * - * In this function we intended to return a `uint8_t` but used a - * `GUARD` which will return -1 if the call fails. This can lead to - * very subtle bugs. - * - * ## `GUARD`ing a function returning any integer type - * - * There is no compiler error if `GUARD(nested_call());` is used - * on a function that doesn't actually return an error signal - * - * ```c - * int s2n_deep_thought() { - * GUARD(s2n_answer_to_the_ultimate_question()); - * return 0; - * } - * ``` - * - * In this function we intended guard against a failure of - * `s2n_answer_to_the_ultimate_question` but that function doesn't - * actually return an error signal. Again, this can lead to sublte - * bugs. - * - * ## Ignored error signals - * - * Without the `warn_unused_result` function attribute, the compiler - * provides no warning when forgetting to `GUARD` a function. Missing - * a `GUARD` can lead to subtle bugs. - * - * ```c - * int s2n_answer_to_the_ultimate_question() { - * s2n_sleep_for_years(7500000); // <- THIS SHOULD BE GUARDED!!! - * return 42; - * } - * ``` - * - * # Solution - * - * s2n_result provides a newtype declaration, which is popular in - * languages like [Haskell](https://wiki.haskell.org/Newtype) and - * [Rust](https://doc.rust-lang.org/rust-by-example/generics/new_types.html). - * - * Functions that return S2N_RESULT are automatically marked with the - * `warn_unused_result` attribute, which ensures they are GUARDed. - */ - -#include <s2n.h> -#include <stdbool.h> -#include "utils/s2n_result.h" - -/* returns true when the result is S2N_RESULT_OK */ -inline bool s2n_result_is_ok(s2n_result result) -{ - return result.__error_signal == S2N_SUCCESS; -} - -/* returns true when the result is S2N_RESULT_ERROR */ -inline bool s2n_result_is_error(s2n_result result) -{ - return result.__error_signal == S2N_FAILURE; -} +/* + * 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. + */ + +/* + * The goal of s2n_result is to provide a strongly-typed error + * signal value, which provides the compiler with enough information + * to catch bugs. + * + * Historically, s2n has used int to signal errors. This has caused a few issues: + * + * ## GUARD in a function returning integer types + * + * There is no compiler error if `GUARD(nested_call());` is used in a function + * that is meant to return integer type - not a error signal. + * + * ```c + * uint8_t s2n_answer_to_the_ultimate_question() { + * GUARD(s2n_sleep_for_years(7500000)); + * return 42; + * } + * ``` + * + * In this function we intended to return a `uint8_t` but used a + * `GUARD` which will return -1 if the call fails. This can lead to + * very subtle bugs. + * + * ## `GUARD`ing a function returning any integer type + * + * There is no compiler error if `GUARD(nested_call());` is used + * on a function that doesn't actually return an error signal + * + * ```c + * int s2n_deep_thought() { + * GUARD(s2n_answer_to_the_ultimate_question()); + * return 0; + * } + * ``` + * + * In this function we intended guard against a failure of + * `s2n_answer_to_the_ultimate_question` but that function doesn't + * actually return an error signal. Again, this can lead to sublte + * bugs. + * + * ## Ignored error signals + * + * Without the `warn_unused_result` function attribute, the compiler + * provides no warning when forgetting to `GUARD` a function. Missing + * a `GUARD` can lead to subtle bugs. + * + * ```c + * int s2n_answer_to_the_ultimate_question() { + * s2n_sleep_for_years(7500000); // <- THIS SHOULD BE GUARDED!!! + * return 42; + * } + * ``` + * + * # Solution + * + * s2n_result provides a newtype declaration, which is popular in + * languages like [Haskell](https://wiki.haskell.org/Newtype) and + * [Rust](https://doc.rust-lang.org/rust-by-example/generics/new_types.html). + * + * Functions that return S2N_RESULT are automatically marked with the + * `warn_unused_result` attribute, which ensures they are GUARDed. + */ + +#include <s2n.h> +#include <stdbool.h> +#include "utils/s2n_result.h" + +/* returns true when the result is S2N_RESULT_OK */ +inline bool s2n_result_is_ok(s2n_result result) +{ + return result.__error_signal == S2N_SUCCESS; +} + +/* returns true when the result is S2N_RESULT_ERROR */ +inline bool s2n_result_is_error(s2n_result result) +{ + return result.__error_signal == S2N_FAILURE; +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_result.h b/contrib/restricted/aws/s2n/utils/s2n_result.h index 9a1b3ed13a..a0e38a8468 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_result.h +++ b/contrib/restricted/aws/s2n/utils/s2n_result.h @@ -1,48 +1,48 @@ -/* - * 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 <s2n.h> -#include <stdbool.h> - -/* A value which indicates the outcome of a function */ -typedef struct { - int __error_signal; -} s2n_result; - -/* used to signal a successful function return */ -#define S2N_RESULT_OK ((s2n_result) { S2N_SUCCESS }) - -/* used to signal an error while executing a function */ -#define S2N_RESULT_ERROR ((s2n_result) { S2N_FAILURE }) - -#if defined(__clang__) || defined(__GNUC__) -#define S2N_RESULT_MUST_USE __attribute__((warn_unused_result)) -#else -#define S2N_RESULT_MUST_USE -#endif - -/* returns true when the result is S2N_RESULT_OK */ -S2N_RESULT_MUST_USE bool s2n_result_is_ok(s2n_result result); - -/* returns true when the result is S2N_RESULT_ERROR */ -S2N_RESULT_MUST_USE bool s2n_result_is_error(s2n_result result); - -/* used in function declarations to signal function fallibility */ -#define S2N_RESULT S2N_RESULT_MUST_USE s2n_result - -/* converts the S2N_RESULT into posix error codes */ -#define S2N_RESULT_TO_POSIX( x ) (s2n_result_is_ok(x) ? S2N_SUCCESS : S2N_FAILURE) +/* + * 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 <s2n.h> +#include <stdbool.h> + +/* A value which indicates the outcome of a function */ +typedef struct { + int __error_signal; +} s2n_result; + +/* used to signal a successful function return */ +#define S2N_RESULT_OK ((s2n_result) { S2N_SUCCESS }) + +/* used to signal an error while executing a function */ +#define S2N_RESULT_ERROR ((s2n_result) { S2N_FAILURE }) + +#if defined(__clang__) || defined(__GNUC__) +#define S2N_RESULT_MUST_USE __attribute__((warn_unused_result)) +#else +#define S2N_RESULT_MUST_USE +#endif + +/* returns true when the result is S2N_RESULT_OK */ +S2N_RESULT_MUST_USE bool s2n_result_is_ok(s2n_result result); + +/* returns true when the result is S2N_RESULT_ERROR */ +S2N_RESULT_MUST_USE bool s2n_result_is_error(s2n_result result); + +/* used in function declarations to signal function fallibility */ +#define S2N_RESULT S2N_RESULT_MUST_USE s2n_result + +/* converts the S2N_RESULT into posix error codes */ +#define S2N_RESULT_TO_POSIX( x ) (s2n_result_is_ok(x) ? S2N_SUCCESS : S2N_FAILURE) diff --git a/contrib/restricted/aws/s2n/utils/s2n_rfc5952.c b/contrib/restricted/aws/s2n/utils/s2n_rfc5952.c index cab0464a6f..4640fe72fc 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_rfc5952.c +++ b/contrib/restricted/aws/s2n/utils/s2n_rfc5952.c @@ -1,135 +1,135 @@ -/* - * 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/socket.h> -#include <stdio.h> - -#include <error/s2n_errno.h> - -#include "utils/s2n_rfc5952.h" -#include "utils/s2n_safety.h" - -static uint8_t dec[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; -static uint8_t hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - -S2N_RESULT s2n_inet_ntop(int af, const void *addr, struct s2n_blob *dst) -{ - const uint8_t *bytes = addr; - uint8_t *cursor = dst->data; - - if (af == AF_INET) { - ENSURE(dst->size >= sizeof("111.222.333.444"), S2N_ERR_SIZE_MISMATCH); - - for (int i = 0; i < 4; i++) { - if (bytes[i] / 100) { - *cursor++ = dec[bytes[i] / 100]; - } - if (bytes[i] >= 10) { - *cursor++ = dec[(bytes[i] % 100) / 10]; - } - *cursor++ = dec[(bytes[i] % 10)]; - *cursor++ = '.'; - } - - *--cursor = '\0'; - - return S2N_RESULT_OK; - } - - if (af == AF_INET6) { - ENSURE(dst->size >= sizeof("1111:2222:3333:4444:5555:6666:7777:8888"), S2N_ERR_SIZE_MISMATCH); - - /* See Section 4 of RFC5952 for the rules we are going to follow here - * - * Here's the general algorithm: - * - * 1/ Treat the bytes as 8 16-bit fields - * 2/ Find the longest run of 16-bit fields. - * 3/ or if there are two or more equal length longest runs, go with the left-most run - * 4/ Make that run :: - * 5/ Print the remaining 16-bit fields in lowercase hex, no leading zeroes - */ - - uint16_t octets[8] = { 0 }; - - int longest_run_start = 0; - int longest_run_length = 0; - int current_run_length = 0; - - /* 2001:db8::1:0:0:1 */ - - /* Find the longest run of zeroes */ - for (int i = 0; i < 8; i++) { - octets[i] = (bytes[i * 2] << 8) + bytes[(i * 2) + 1]; - - if (octets[i]) { - current_run_length = 0; - } - else { - current_run_length++; - } - - if (current_run_length > longest_run_length) { - longest_run_length = current_run_length; - longest_run_start = (i - current_run_length) + 1; - } - } - - - for (int i = 0; i < 8; i++) { - if (i == longest_run_start && longest_run_length > 1) { - - if (i == 0) { - *cursor++ = ':'; - } - - if (longest_run_length == 8) { - *cursor++ = ':'; - } - - i += longest_run_length - 1; - - } - else { - uint8_t nibbles[4] = { (octets[i] & 0xF000) >> 12, - (octets[i] & 0x0F00) >> 8, - (octets[i] & 0x00F0) >> 4, - (octets[i] & 0x000F) }; - - /* Skip up to three leading zeroes */ - int j; - for (j = 0; j < 3; j++) { - if (nibbles[j]) { - break; - } - } - - for (; j < 4; j++) { - *cursor++ = hex[ nibbles[j] ]; - } - - } - - *cursor++ = ':'; - } - - *--cursor = '\0'; - - return S2N_RESULT_OK; - } - - BAIL(S2N_ERR_INVALID_ARGUMENT); -} +/* + * 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/socket.h> +#include <stdio.h> + +#include <error/s2n_errno.h> + +#include "utils/s2n_rfc5952.h" +#include "utils/s2n_safety.h" + +static uint8_t dec[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; +static uint8_t hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + +S2N_RESULT s2n_inet_ntop(int af, const void *addr, struct s2n_blob *dst) +{ + const uint8_t *bytes = addr; + uint8_t *cursor = dst->data; + + if (af == AF_INET) { + ENSURE(dst->size >= sizeof("111.222.333.444"), S2N_ERR_SIZE_MISMATCH); + + for (int i = 0; i < 4; i++) { + if (bytes[i] / 100) { + *cursor++ = dec[bytes[i] / 100]; + } + if (bytes[i] >= 10) { + *cursor++ = dec[(bytes[i] % 100) / 10]; + } + *cursor++ = dec[(bytes[i] % 10)]; + *cursor++ = '.'; + } + + *--cursor = '\0'; + + return S2N_RESULT_OK; + } + + if (af == AF_INET6) { + ENSURE(dst->size >= sizeof("1111:2222:3333:4444:5555:6666:7777:8888"), S2N_ERR_SIZE_MISMATCH); + + /* See Section 4 of RFC5952 for the rules we are going to follow here + * + * Here's the general algorithm: + * + * 1/ Treat the bytes as 8 16-bit fields + * 2/ Find the longest run of 16-bit fields. + * 3/ or if there are two or more equal length longest runs, go with the left-most run + * 4/ Make that run :: + * 5/ Print the remaining 16-bit fields in lowercase hex, no leading zeroes + */ + + uint16_t octets[8] = { 0 }; + + int longest_run_start = 0; + int longest_run_length = 0; + int current_run_length = 0; + + /* 2001:db8::1:0:0:1 */ + + /* Find the longest run of zeroes */ + for (int i = 0; i < 8; i++) { + octets[i] = (bytes[i * 2] << 8) + bytes[(i * 2) + 1]; + + if (octets[i]) { + current_run_length = 0; + } + else { + current_run_length++; + } + + if (current_run_length > longest_run_length) { + longest_run_length = current_run_length; + longest_run_start = (i - current_run_length) + 1; + } + } + + + for (int i = 0; i < 8; i++) { + if (i == longest_run_start && longest_run_length > 1) { + + if (i == 0) { + *cursor++ = ':'; + } + + if (longest_run_length == 8) { + *cursor++ = ':'; + } + + i += longest_run_length - 1; + + } + else { + uint8_t nibbles[4] = { (octets[i] & 0xF000) >> 12, + (octets[i] & 0x0F00) >> 8, + (octets[i] & 0x00F0) >> 4, + (octets[i] & 0x000F) }; + + /* Skip up to three leading zeroes */ + int j; + for (j = 0; j < 3; j++) { + if (nibbles[j]) { + break; + } + } + + for (; j < 4; j++) { + *cursor++ = hex[ nibbles[j] ]; + } + + } + + *cursor++ = ':'; + } + + *--cursor = '\0'; + + return S2N_RESULT_OK; + } + + BAIL(S2N_ERR_INVALID_ARGUMENT); +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_rfc5952.h b/contrib/restricted/aws/s2n/utils/s2n_rfc5952.h index 724c923128..bc0681afb7 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_rfc5952.h +++ b/contrib/restricted/aws/s2n/utils/s2n_rfc5952.h @@ -1,24 +1,24 @@ -#pragma once -/* - * 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 - */ - -#include "utils/s2n_blob.h" -#include "utils/s2n_result.h" - -/** - * Converts a binary representation of an ip address into its canonical string - * representation. Returns 0 on success and -1 on failure. - */ -extern S2N_RESULT s2n_inet_ntop(int af, const void *addr, struct s2n_blob *dst); - +#pragma once +/* + * 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 + */ + +#include "utils/s2n_blob.h" +#include "utils/s2n_result.h" + +/** + * Converts a binary representation of an ip address into its canonical string + * representation. Returns 0 on success and -1 on failure. + */ +extern S2N_RESULT s2n_inet_ntop(int af, const void *addr, struct s2n_blob *dst); + diff --git a/contrib/restricted/aws/s2n/utils/s2n_safety.c b/contrib/restricted/aws/s2n/utils/s2n_safety.c index d786c4d852..87fb1059d1 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_safety.c +++ b/contrib/restricted/aws/s2n/utils/s2n_safety.c @@ -1,234 +1,234 @@ -/* - * 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. - */ - -#define _GNU_SOURCE /* For syscall on Linux */ -#undef _POSIX_C_SOURCE /* For syscall() on Mac OS X */ - -#include <unistd.h> -#include <sys/syscall.h> -#include <sys/types.h> -#include <stdint.h> -#include <stdio.h> - -#include "utils/s2n_annotations.h" -#include "utils/s2n_safety.h" - -/** - * Get the process id - * - * Returns: - * The process ID of the current process - */ -pid_t s2n_actual_getpid() -{ -#if defined(__GNUC__) && defined(SYS_getpid) - /* http://yarchive.net/comp/linux/getpid_caching.html */ - return (pid_t) syscall(SYS_getpid); -#else - return getpid(); -#endif -} - -/** - * Given arrays "a" and "b" of length "len", determine whether they - * hold equal contents. - * - * The execution time of this function is independent of the values - * stored in the arrays. - * - * Timing may depend on the length of the arrays, and on the location - * of the arrays in memory (e.g. if a buffer has been paged out, this - * will affect the timing of this function). - * - * Returns: - * Whether all bytes in arrays "a" and "b" are identical - */ -bool s2n_constant_time_equals(const uint8_t * a, const uint8_t * b, const uint32_t len) -{ - S2N_PUBLIC_INPUT(a); - S2N_PUBLIC_INPUT(b); - S2N_PUBLIC_INPUT(len); - - if (len != 0 && (a == NULL || b == NULL)) { - return false; - } - - uint8_t xor = 0; - for (int i = 0; i < len; i++) { - /* Invariants must hold for each execution of the loop - * and at loop exit, hence the <= */ - S2N_INVARIENT(i <= len); - xor |= a[i] ^ b[i]; - } - - return !xor; -} - -/** - * Given arrays "dest" and "src" of length "len", conditionally copy "src" to "dest" - * The execution time of this function is independent of the values - * stored in the arrays, and of whether the copy occurs. - * - * Timing may depend on the length of the arrays, and on the location - * of the arrays in memory (e.g. if a buffer has been paged out, this - * will affect the timing of this function). - * - */ -int s2n_constant_time_copy_or_dont(uint8_t * dest, const uint8_t * src, uint32_t len, uint8_t dont) -{ - S2N_PUBLIC_INPUT(dest); - S2N_PUBLIC_INPUT(src); - S2N_PUBLIC_INPUT(len); - -/* This underflows a value of 0 to the maximum value via arithmetic underflow, - * so the check for arithmetic overflow/underflow needs to be disabled for CBMC. - * Additionally, uint_fast16_t is defined as the fastest available unsigned - * integer with 16 bits or greater, and is not guaranteed to be 16 bits long. - * To handle this, the conversion overflow check also needs to be enabled. */ -#pragma CPROVER check push -#pragma CPROVER check disable "conversion" -#pragma CPROVER check disable "unsigned-overflow" - uint8_t mask = ((uint_fast16_t)((uint_fast16_t)(dont) - 1)) >> 8; -#pragma CPROVER check pop - - /* dont = 0 : mask = 0xff */ - /* dont > 0 : mask = 0x00 */ - - for (uint32_t i = 0; i < len; i++) { - uint8_t old = dest[i]; - uint8_t diff = (old ^ src[i]) & mask; - dest[i] = old ^ diff; - } - - return 0; -} - -/* If src contains valid PKCS#1 v1.5 padding of exactly expectlen bytes, decode - * it into dst, otherwise leave dst alone. Execution time is independent of the - * content of src, but may depend on srclen/expectlen. - * - * Normally, one would fill dst with random bytes before calling this function. - */ -int s2n_constant_time_pkcs1_unpad_or_dont(uint8_t * dst, const uint8_t * src, uint32_t srclen, uint32_t expectlen) -{ - S2N_PUBLIC_INPUT(dst); - S2N_PUBLIC_INPUT(src); - S2N_PUBLIC_INPUT(srclen); - S2N_PUBLIC_INPUT(expectlen); - - /* Before doing anything else, some basic sanity checks on input lengths */ - if (srclen < expectlen + 3) { - /* Not enough room for PKCS#1v1.5 padding, so treat it as bad padding */ - return 0; - } - - /* First, determine (in constant time) whether the padding is valid. - * If the padding is valid we expect that: - * Bytes 0 and 1 will equal 0x00 and 0x02 - * Bytes (srclen-expectlen-1) will be zero - * Bytes 2 through (srclen-expectlen-1) will be nonzero - */ - uint8_t dont_copy = 0; - const uint8_t *start_of_data = src + srclen - expectlen; - - dont_copy |= src[0] ^ 0x00; - dont_copy |= src[1] ^ 0x02; - -/* Since -1 is being used, we need to disable the pointer overflow check for CBMC. */ -#pragma CPROVER check push -#pragma CPROVER check disable "pointer-overflow" - dont_copy |= start_of_data[-1] ^ 0x00; -#pragma CPROVER check pop - -/* This underflows a value of 0 to the maximum value via arithmetic underflow, - * so the check for arithmetic overflow/underflow needs to be disabled for CBMC. - * Additionally, uint_fast16_t is defined as the fastest available unsigned - * integer with 16 bits or greater, and is not guaranteed to be 16 bits long. - * To handle this, the conversion overflow check also needs to be enabled. */ -#pragma CPROVER check push -#pragma CPROVER check disable "conversion" -#pragma CPROVER check disable "unsigned-overflow" - for (uint32_t i = 2; i < srclen - expectlen - 1; i++) { - /* Note! We avoid using logical NOT (!) here; while in practice - * many compilers will use constant-time sequences for this operator, - * at least on x86 (e.g. cmp -> setcc, or vectorized pcmpeq), this is - * not guaranteed to hold, and some architectures might not have a - * convenient mechanism for generating a branchless logical not. */ - uint8_t mask = ((uint_fast16_t)((uint_fast16_t)(src[i]) - 1)) >> 8; - /* src[i] = 0 : mask = 0xff */ - /* src[i] > 0 : mask = 0x00 */ - dont_copy |= mask; - } -#pragma CPROVER check pop - - s2n_constant_time_copy_or_dont(dst, start_of_data, expectlen, dont_copy); - - return 0; -} - -static bool s_s2n_in_unit_test = false; - -bool s2n_in_unit_test() -{ - return s_s2n_in_unit_test; -} - -int s2n_in_unit_test_set(bool newval) -{ - s_s2n_in_unit_test = newval; - return S2N_SUCCESS; -} - -int s2n_align_to(uint32_t initial, uint32_t alignment, uint32_t* out) -{ - notnull_check(out); - ENSURE_POSIX(alignment != 0, S2N_ERR_SAFETY); - if (initial == 0) { - *out = 0; - return S2N_SUCCESS; - } - const uint64_t i = initial; - const uint64_t a = alignment; - const uint64_t result = a * (((i - 1) / a) + 1); - S2N_ERROR_IF(result > UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW); - *out = (uint32_t) result; - return S2N_SUCCESS; -} - -int s2n_mul_overflow(uint32_t a, uint32_t b, uint32_t* out) -{ - notnull_check(out); - const uint64_t result = ((uint64_t) a) * ((uint64_t) b); - S2N_ERROR_IF(result > UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW); - *out = (uint32_t) result; - return S2N_SUCCESS; -} - -int s2n_add_overflow(uint32_t a, uint32_t b, uint32_t* out) -{ - notnull_check(out); - uint64_t result = ((uint64_t) a) + ((uint64_t) b); - S2N_ERROR_IF(result > UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW); - *out = (uint32_t) result; - return S2N_SUCCESS; -} - -int s2n_sub_overflow(uint32_t a, uint32_t b, uint32_t* out) -{ - notnull_check(out); - S2N_ERROR_IF(a < b, S2N_ERR_INTEGER_OVERFLOW); - *out = a - b; - 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. + */ + +#define _GNU_SOURCE /* For syscall on Linux */ +#undef _POSIX_C_SOURCE /* For syscall() on Mac OS X */ + +#include <unistd.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <stdint.h> +#include <stdio.h> + +#include "utils/s2n_annotations.h" +#include "utils/s2n_safety.h" + +/** + * Get the process id + * + * Returns: + * The process ID of the current process + */ +pid_t s2n_actual_getpid() +{ +#if defined(__GNUC__) && defined(SYS_getpid) + /* http://yarchive.net/comp/linux/getpid_caching.html */ + return (pid_t) syscall(SYS_getpid); +#else + return getpid(); +#endif +} + +/** + * Given arrays "a" and "b" of length "len", determine whether they + * hold equal contents. + * + * The execution time of this function is independent of the values + * stored in the arrays. + * + * Timing may depend on the length of the arrays, and on the location + * of the arrays in memory (e.g. if a buffer has been paged out, this + * will affect the timing of this function). + * + * Returns: + * Whether all bytes in arrays "a" and "b" are identical + */ +bool s2n_constant_time_equals(const uint8_t * a, const uint8_t * b, const uint32_t len) +{ + S2N_PUBLIC_INPUT(a); + S2N_PUBLIC_INPUT(b); + S2N_PUBLIC_INPUT(len); + + if (len != 0 && (a == NULL || b == NULL)) { + return false; + } + + uint8_t xor = 0; + for (int i = 0; i < len; i++) { + /* Invariants must hold for each execution of the loop + * and at loop exit, hence the <= */ + S2N_INVARIENT(i <= len); + xor |= a[i] ^ b[i]; + } + + return !xor; +} + +/** + * Given arrays "dest" and "src" of length "len", conditionally copy "src" to "dest" + * The execution time of this function is independent of the values + * stored in the arrays, and of whether the copy occurs. + * + * Timing may depend on the length of the arrays, and on the location + * of the arrays in memory (e.g. if a buffer has been paged out, this + * will affect the timing of this function). + * + */ +int s2n_constant_time_copy_or_dont(uint8_t * dest, const uint8_t * src, uint32_t len, uint8_t dont) +{ + S2N_PUBLIC_INPUT(dest); + S2N_PUBLIC_INPUT(src); + S2N_PUBLIC_INPUT(len); + +/* This underflows a value of 0 to the maximum value via arithmetic underflow, + * so the check for arithmetic overflow/underflow needs to be disabled for CBMC. + * Additionally, uint_fast16_t is defined as the fastest available unsigned + * integer with 16 bits or greater, and is not guaranteed to be 16 bits long. + * To handle this, the conversion overflow check also needs to be enabled. */ +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#pragma CPROVER check disable "unsigned-overflow" + uint8_t mask = ((uint_fast16_t)((uint_fast16_t)(dont) - 1)) >> 8; +#pragma CPROVER check pop + + /* dont = 0 : mask = 0xff */ + /* dont > 0 : mask = 0x00 */ + + for (uint32_t i = 0; i < len; i++) { + uint8_t old = dest[i]; + uint8_t diff = (old ^ src[i]) & mask; + dest[i] = old ^ diff; + } + + return 0; +} + +/* If src contains valid PKCS#1 v1.5 padding of exactly expectlen bytes, decode + * it into dst, otherwise leave dst alone. Execution time is independent of the + * content of src, but may depend on srclen/expectlen. + * + * Normally, one would fill dst with random bytes before calling this function. + */ +int s2n_constant_time_pkcs1_unpad_or_dont(uint8_t * dst, const uint8_t * src, uint32_t srclen, uint32_t expectlen) +{ + S2N_PUBLIC_INPUT(dst); + S2N_PUBLIC_INPUT(src); + S2N_PUBLIC_INPUT(srclen); + S2N_PUBLIC_INPUT(expectlen); + + /* Before doing anything else, some basic sanity checks on input lengths */ + if (srclen < expectlen + 3) { + /* Not enough room for PKCS#1v1.5 padding, so treat it as bad padding */ + return 0; + } + + /* First, determine (in constant time) whether the padding is valid. + * If the padding is valid we expect that: + * Bytes 0 and 1 will equal 0x00 and 0x02 + * Bytes (srclen-expectlen-1) will be zero + * Bytes 2 through (srclen-expectlen-1) will be nonzero + */ + uint8_t dont_copy = 0; + const uint8_t *start_of_data = src + srclen - expectlen; + + dont_copy |= src[0] ^ 0x00; + dont_copy |= src[1] ^ 0x02; + +/* Since -1 is being used, we need to disable the pointer overflow check for CBMC. */ +#pragma CPROVER check push +#pragma CPROVER check disable "pointer-overflow" + dont_copy |= start_of_data[-1] ^ 0x00; +#pragma CPROVER check pop + +/* This underflows a value of 0 to the maximum value via arithmetic underflow, + * so the check for arithmetic overflow/underflow needs to be disabled for CBMC. + * Additionally, uint_fast16_t is defined as the fastest available unsigned + * integer with 16 bits or greater, and is not guaranteed to be 16 bits long. + * To handle this, the conversion overflow check also needs to be enabled. */ +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#pragma CPROVER check disable "unsigned-overflow" + for (uint32_t i = 2; i < srclen - expectlen - 1; i++) { + /* Note! We avoid using logical NOT (!) here; while in practice + * many compilers will use constant-time sequences for this operator, + * at least on x86 (e.g. cmp -> setcc, or vectorized pcmpeq), this is + * not guaranteed to hold, and some architectures might not have a + * convenient mechanism for generating a branchless logical not. */ + uint8_t mask = ((uint_fast16_t)((uint_fast16_t)(src[i]) - 1)) >> 8; + /* src[i] = 0 : mask = 0xff */ + /* src[i] > 0 : mask = 0x00 */ + dont_copy |= mask; + } +#pragma CPROVER check pop + + s2n_constant_time_copy_or_dont(dst, start_of_data, expectlen, dont_copy); + + return 0; +} + +static bool s_s2n_in_unit_test = false; + +bool s2n_in_unit_test() +{ + return s_s2n_in_unit_test; +} + +int s2n_in_unit_test_set(bool newval) +{ + s_s2n_in_unit_test = newval; + return S2N_SUCCESS; +} + +int s2n_align_to(uint32_t initial, uint32_t alignment, uint32_t* out) +{ + notnull_check(out); + ENSURE_POSIX(alignment != 0, S2N_ERR_SAFETY); + if (initial == 0) { + *out = 0; + return S2N_SUCCESS; + } + const uint64_t i = initial; + const uint64_t a = alignment; + const uint64_t result = a * (((i - 1) / a) + 1); + S2N_ERROR_IF(result > UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW); + *out = (uint32_t) result; + return S2N_SUCCESS; +} + +int s2n_mul_overflow(uint32_t a, uint32_t b, uint32_t* out) +{ + notnull_check(out); + const uint64_t result = ((uint64_t) a) * ((uint64_t) b); + S2N_ERROR_IF(result > UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW); + *out = (uint32_t) result; + return S2N_SUCCESS; +} + +int s2n_add_overflow(uint32_t a, uint32_t b, uint32_t* out) +{ + notnull_check(out); + uint64_t result = ((uint64_t) a) + ((uint64_t) b); + S2N_ERROR_IF(result > UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW); + *out = (uint32_t) result; + return S2N_SUCCESS; +} + +int s2n_sub_overflow(uint32_t a, uint32_t b, uint32_t* out) +{ + notnull_check(out); + S2N_ERROR_IF(a < b, S2N_ERR_INTEGER_OVERFLOW); + *out = a - b; + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_safety.h b/contrib/restricted/aws/s2n/utils/s2n_safety.h index 67a0328901..5dbc505d47 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_safety.h +++ b/contrib/restricted/aws/s2n/utils/s2n_safety.h @@ -1,408 +1,408 @@ -/* - * 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 <string.h> -#include <sys/types.h> -#include <stdint.h> -#include <stdbool.h> -#include <stdlib.h> - -#include "error/s2n_errno.h" -#include "utils/s2n_ensure.h" -#include "utils/s2n_result.h" - -/* Success signal value for OpenSSL functions */ -#define _OSSL_SUCCESS 1 - -/** - * The goal of s2n_safety is to provide helpers to perform common - * checks, which help with code readability. - */ - -/** - * Sets the global `errno` and returns with a `S2N_RESULT_ERROR` - */ -#define BAIL( x ) do { _S2N_ERROR( ( x ) ); return S2N_RESULT_ERROR; } while (0) - -/** - * Sets the global `errno` and returns with a POSIX error (`-1`) - */ -#define BAIL_POSIX( x ) do { _S2N_ERROR( ( x ) ); return S2N_FAILURE; } while (0) - -/** - * Sets the global `errno` and returns with a `NULL` pointer value - */ -#define BAIL_PTR( x ) do { _S2N_ERROR( ( x ) ); return NULL; } while (0) - -/** - * Ensures the `condition` is `true`, otherwise the function will `BAIL` with an `error` - */ -#define ENSURE( condition , error ) __S2N_ENSURE((condition), BAIL(error)) - -/** - * Ensures the `result` is OK, otherwise the function will `BAIL` with an `error` - */ -#define ENSURE_OK( result , error ) __S2N_ENSURE(s2n_result_is_ok(result), BAIL(error)) - -/** - * Ensures `n` is greater than or equal to `min`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error - */ -#define ENSURE_GTE( n , min ) ENSURE((n) >= (min), S2N_ERR_SAFETY) - -/** - * Ensures `n` is less than or equal to `max`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error - */ -#define ENSURE_LTE( n , max ) ENSURE((n) <= (max), S2N_ERR_SAFETY) - -/** - * Ensures `n` is greater than `min`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error - */ -#define ENSURE_GT( n , min ) ENSURE((n) > (min), S2N_ERR_SAFETY) - -/** - * Ensures `n` is less than `min`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error - */ -#define ENSURE_LT( n , max ) ENSURE((n) < (max), S2N_ERR_SAFETY) - -/** - * Ensures `a` is equal to `b`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error - */ -#define ENSURE_EQ( a , b ) ENSURE((a) == (b), S2N_ERR_SAFETY) - -/** - * Ensures `a` is not equal to `b`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error - */ -#define ENSURE_NE( a , b ) ENSURE((a) != (b), S2N_ERR_SAFETY) - -/** - * Ensures the `condition` is `true`, otherwise the function will `BAIL_POSIX` with an `error` - */ -#define ENSURE_POSIX( condition , error ) __S2N_ENSURE((condition), BAIL_POSIX(error)) - -/** - * Ensures the `condition` is `true`, otherwise the function will `BAIL_PTR` with an `error` - */ -#define ENSURE_PTR( condition , error ) __S2N_ENSURE((condition), BAIL_PTR(error)) - -/** - * Ensures `x` is not `NULL`, otherwise the function will `BAIL_PTR` with an `error` - */ -#define ENSURE_REF_PTR( x ) ENSURE_PTR(S2N_OBJECT_PTR_IS_READABLE(x), S2N_ERR_NULL) - -/** - * Ensures `x` is a readable reference, otherwise the function will `BAIL` with `S2N_ERR_NULL` - */ -#define ENSURE_REF( x ) ENSURE(S2N_OBJECT_PTR_IS_READABLE(x), S2N_ERR_NULL) - -/** - * Ensures `x` is a readable reference, otherwise the function will `BAIL_POSIX` with `S2N_ERR_NULL` - */ -#define ENSURE_POSIX_REF( x ) ENSURE_POSIX(S2N_OBJECT_PTR_IS_READABLE(x), S2N_ERR_NULL) - -/** - * Ensures `x` is a mutable reference, otherwise the function will `BAIL` with `S2N_ERR_NULL` - */ -#define ENSURE_MUT( x ) ENSURE(S2N_OBJECT_PTR_IS_WRITABLE(x), S2N_ERR_NULL) - -/** - * Ensures `x` is a mutable reference, otherwise the function will `BAIL_POSIX` with `S2N_ERR_NULL` - */ -#define ENSURE_POSIX_MUT( x ) ENSURE_POSIX(S2N_OBJECT_PTR_IS_WRITABLE(x), S2N_ERR_NULL) - -/** - * Ensures `min <= n <= max` - */ -#define ENSURE_INCLUSIVE_RANGE( min , n , max ) \ - do { \ - __typeof( n ) __tmp_n = ( n ); \ - ENSURE_GTE(__tmp_n, min); \ - ENSURE_LTE(__tmp_n, max); \ - } while(0) - -/** - * Ensures `min < n < max` - */ -#define ENSURE_EXCLUSIVE_RANGE( min , n , max ) \ - do { \ - __typeof( n ) __tmp_n = ( n ); \ - ENSURE_GT(__tmp_n, min); \ - ENSURE_LT(__tmp_n, max); \ - } while(0) - -/** - * Ensures the `result` is `S2N_RESULT_OK`, otherwise the function will return an error signal - */ -#define PRECONDITION( result ) GUARD_RESULT(__S2N_ENSURE_PRECONDITION(result)) - -/** - * Ensures the `result` is `S2N_RESULT_OK`, otherwise the function will return an error signal - */ -#define POSTCONDITION( result ) GUARD_RESULT(__S2N_ENSURE_POSTCONDITION(result)) - -/** - * Ensures the `result` is `S2N_RESULT_OK`, otherwise the function will return an error signal - */ -#define PRECONDITION_POSIX( result ) GUARD_AS_POSIX(__S2N_ENSURE_PRECONDITION(result)) - -/** - * Ensures the `result` is `S2N_RESULT_OK`, otherwise the function will return an error signal - */ -#define POSTCONDITION_POSIX( result ) GUARD_AS_POSIX(__S2N_ENSURE_POSTCONDITION(result)) - -/** - * Ensures the `condition` is `true`, otherwise the function will `BAIL` with an `error`. - * When the code is built in debug mode, they are checked. - * When the code is built in production mode, they are ignored. - */ -#define DEBUG_ENSURE( condition, error ) __S2N_ENSURE_DEBUG((condition), BAIL(error)) - -/** - * Ensures the `condition` is `true`, otherwise the function will `BAIL_POSIX` with an `error`. - * When the code is built in debug mode, they are checked. - * When the code is built in production mode, they are ignored. - */ -#define DEBUG_ENSURE_POSIX( condition, error ) __S2N_ENSURE_DEBUG((condition), BAIL_POSIX(error)) - -/** - * Ensures `x` is not an error, otherwise the function will return an error signal - * - * Note: this currently accepts POSIX error signals but will transition to accept s2n_result - */ -#define GUARD( x ) GUARD_POSIX(x) - -/** - * Ensures `x` is not an error, otherwise goto `label` - * - * Note: this currently accepts POSIX error signals but will transition to accept s2n_result - */ -#define GUARD_GOTO( x , label ) GUARD_POSIX_GOTO((x), (label)) - -/** - * Ensures `x` is not an error, otherwise the function will return `NULL` - * - * Note: this currently accepts POSIX error signals but will transition to accept s2n_result - */ -#define GUARD_PTR( x ) GUARD_POSIX_PTR(x) - -/** - * Ensures `x` is not `NULL`, otherwise the function will return an error signal - * - * Note: this currently accepts POSIX error signals but will transition to accept s2n_result - */ -#define GUARD_NONNULL( x ) GUARD_POSIX_NONNULL(x) - -/** - * Ensures `x` is not `NULL`, otherwise goto `label` - * - * Note: this currently accepts POSIX error signals but will transition to accept s2n_result - */ -#define GUARD_NONNULL_GOTO( x , label ) __S2N_ENSURE((x) != NULL, goto label) - -/** - * Ensures `x` is not `NULL`, otherwise the function will return `NULL` - * - * Note: this currently accepts POSIX error signals but will transition to accept s2n_result - */ -#define GUARD_NONNULL_PTR( x ) __S2N_ENSURE((x) != NULL, return NULL) - -/** - * Ensures `x` is not a OpenSSL error, otherwise the function will return an error signal - * - * Note: this currently accepts POSIX error signals but will transition to accept s2n_result - */ -#define GUARD_OSSL( x, error ) GUARD_POSIX_OSSL((x), (error)) - -/** - * Ensures `x` is ok, otherwise the function will return an `S2N_RESULT_ERROR` - */ -#define GUARD_RESULT( x ) __S2N_ENSURE(s2n_result_is_ok(x), return S2N_RESULT_ERROR) - -/** - * Ensures `x` is ok, otherwise goto `label` - */ -#define GUARD_RESULT_GOTO( x, label ) __S2N_ENSURE(s2n_result_is_ok(x), goto label) - -/** - * Ensures `x` is ok, otherwise the function will return `NULL` - */ -#define GUARD_RESULT_PTR( x ) __S2N_ENSURE(s2n_result_is_ok(x), return NULL) - -/** - * Ensures `x` is not `NULL`, otherwise the function will return an `S2N_RESULT_ERROR` - */ -#define GUARD_RESULT_NONNULL( x ) __S2N_ENSURE((x) != NULL, return S2N_RESULT_ERROR) - -/** - * Ensures `x` is not a OpenSSL error, otherwise the function will `BAIL` with `error` - */ -/* TODO: use the OSSL error code in error reporting https://github.com/awslabs/s2n/issues/705 */ -#define GUARD_RESULT_OSSL( x , error ) ENSURE((x) == _OSSL_SUCCESS, error) - -/** - * Ensures `x` is not a POSIX error, otherwise return a POSIX error - */ -#define GUARD_POSIX( x ) __S2N_ENSURE((x) >= S2N_SUCCESS, return S2N_FAILURE) - -/** - * Ensures `x` is strictly not a POSIX error (`-1`), otherwise goto `label` - */ -#define GUARD_POSIX_STRICT( x ) __S2N_ENSURE((x) == S2N_SUCCESS, return S2N_FAILURE) - -/** - * Ensures `x` is not a POSIX error, otherwise goto `label` - */ -#define GUARD_POSIX_GOTO( x , label ) __S2N_ENSURE((x) >= S2N_SUCCESS, goto label) - -/** - * Ensures `x` is not a POSIX error, otherwise the function will return `NULL` - */ -#define GUARD_POSIX_PTR( x ) __S2N_ENSURE((x) >= S2N_SUCCESS, return NULL) - -/** - * Ensures `x` is not `NULL`, otherwise the function will return a POSIX error (`-1`) - */ -#define GUARD_POSIX_NONNULL( x ) __S2N_ENSURE((x) != NULL, return S2N_FAILURE) - -/** - * Ensures `x` is not a OpenSSL error, otherwise the function will `BAIL` with `error` - */ -/* TODO: use the OSSL error code in error reporting https://github.com/awslabs/s2n/issues/705 */ -#define GUARD_POSIX_OSSL( x , error ) ENSURE_POSIX((x) == _OSSL_SUCCESS, error) - -/** - * Ensures `x` is not a POSIX error, otherwise the function will return a `S2N_RESULT_ERROR` - */ -#define GUARD_AS_RESULT( x ) __S2N_ENSURE((x) >= S2N_SUCCESS, return S2N_RESULT_ERROR) - -/** - * Ensures `x` is OK (S2N_RESULT), otherwise the function will return a POSIX error (`-1`) - */ -#define GUARD_AS_POSIX( x ) __S2N_ENSURE(s2n_result_is_ok(x), return S2N_FAILURE) - -/** - * Performs a safe memcpy - */ -#define CHECKED_MEMCPY( d , s , n ) __S2N_ENSURE_SAFE_MEMCPY((d), (s), (n), GUARD_RESULT_NONNULL) - -/** - * Performs a safe memset - */ -#define CHECKED_MEMSET( d , c , n ) __S2N_ENSURE_SAFE_MEMSET((d), (c), (n), ENSURE_REF) - -/** - * Marks a case of a switch statement as able to fall through to the next case - */ -#if (defined(__clang__) && __clang_major__ >= 10) || (defined(__GNUC__) && __GNUC__ >= 7) -# define FALL_THROUGH __attribute__((fallthrough)) -#else -# define FALL_THROUGH ((void)0) -#endif - -/* Returns `true` if s2n is in unit test mode, `false` otherwise */ -bool s2n_in_unit_test(); - -/* Sets whether s2n is in unit test mode */ -int s2n_in_unit_test_set(bool newval); - -#define S2N_IN_INTEG_TEST ( getenv("S2N_INTEG_TEST") != NULL ) -#define S2N_IN_TEST ( s2n_in_unit_test() || S2N_IN_INTEG_TEST ) - -/** - * Get the process id - * - * Returns: - * The process ID of the current process - */ -extern pid_t s2n_actual_getpid(); - -/* Returns 1 if a and b are equal, in constant time */ -extern bool s2n_constant_time_equals(const uint8_t * a, const uint8_t * b, const uint32_t len); - -/* Copy src to dst, or don't copy it, in constant time */ -extern int s2n_constant_time_copy_or_dont(uint8_t * dst, const uint8_t * src, uint32_t len, uint8_t dont); - -/* If src contains valid PKCS#1 v1.5 padding of exactly expectlen bytes, decode - * it into dst, otherwise leave dst alone, in constant time. - * Always returns zero. */ -extern int s2n_constant_time_pkcs1_unpad_or_dont(uint8_t * dst, const uint8_t * src, uint32_t srclen, uint32_t expectlen); - -/** - * Runs _thecleanup function on _thealloc once _thealloc went out of scope - */ -#define DEFER_CLEANUP(_thealloc, _thecleanup) \ - __attribute__((cleanup(_thecleanup))) _thealloc - -/* Creates cleanup function for pointers from function func which accepts a pointer. - * This is useful for DEFER_CLEANUP as it passes &_thealloc into _thecleanup function, - * so if _thealloc is a pointer _thecleanup will receive a pointer to a pointer.*/ -#define DEFINE_POINTER_CLEANUP_FUNC(type, func) \ - static inline void func##_pointer(type *p) { \ - if (p && *p) \ - func(*p); \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define s2n_array_len(array) ((array != NULL) ? (sizeof(array) / sizeof(array[0])) : 0) - -extern int s2n_mul_overflow(uint32_t a, uint32_t b, uint32_t* out); - -/** - * Rounds "initial" up to a multiple of "alignment", and stores the result in "out". - * Raises an error if overflow would occur. - * NOT CONSTANT TIME. - */ -extern int s2n_align_to(uint32_t initial, uint32_t alignment, uint32_t* out); -extern int s2n_add_overflow(uint32_t a, uint32_t b, uint32_t* out); -extern int s2n_sub_overflow(uint32_t a, uint32_t b, uint32_t* out); -/* START COMPATIBILITY LAYER */ - -/** - * NOTE: This will be removed once everything is using s2n_result - */ - -/* `NULL` check a pointer */ - -/* Note: this macro is replaced by ENSURE_POSIX_REF */ -#define notnull_check(ptr) ENSURE_POSIX_REF(ptr) -/* Note: this macro is replaced by ENSURE_REF_PTR */ -#define notnull_check_ptr(ptr) ENSURE_REF_PTR(ptr) - -/* Range check a number */ -#define gte_check( n , min ) ENSURE_POSIX((n) >= (min), S2N_ERR_SAFETY) -#define lte_check( n , max ) ENSURE_POSIX((n) <= (max), S2N_ERR_SAFETY) -#define gt_check( n , min ) ENSURE_POSIX((n) > (min), S2N_ERR_SAFETY) -#define lt_check( n , max ) ENSURE_POSIX((n) < (max), S2N_ERR_SAFETY) -#define eq_check( a , b ) ENSURE_POSIX((a) == (b), S2N_ERR_SAFETY) -#define ne_check( a , b ) ENSURE_POSIX((a) != (b), S2N_ERR_SAFETY) -#define inclusive_range_check( low, n, high ) \ - do { \ - __typeof( n ) __tmp_n = ( n ); \ - gte_check(__tmp_n, low); \ - lte_check(__tmp_n, high); \ - } while (0) -#define exclusive_range_check( low, n, high ) \ - do { \ - __typeof( n ) __tmp_n = ( n ); \ - gt_check(__tmp_n, low); \ - lt_check(__tmp_n, high); \ - } while (0) - -#define memcpy_check( d , s , n ) __S2N_ENSURE_SAFE_MEMCPY((d), (s), (n), GUARD_POSIX_NONNULL) -/* This will fail to build if d is an array. Cast the array to a pointer first! */ -#define memset_check( d , c , n ) __S2N_ENSURE_SAFE_MEMSET((d), (c), (n), ENSURE_POSIX_REF) - -/* END COMPATIBILITY LAYER */ +/* + * 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 <string.h> +#include <sys/types.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> + +#include "error/s2n_errno.h" +#include "utils/s2n_ensure.h" +#include "utils/s2n_result.h" + +/* Success signal value for OpenSSL functions */ +#define _OSSL_SUCCESS 1 + +/** + * The goal of s2n_safety is to provide helpers to perform common + * checks, which help with code readability. + */ + +/** + * Sets the global `errno` and returns with a `S2N_RESULT_ERROR` + */ +#define BAIL( x ) do { _S2N_ERROR( ( x ) ); return S2N_RESULT_ERROR; } while (0) + +/** + * Sets the global `errno` and returns with a POSIX error (`-1`) + */ +#define BAIL_POSIX( x ) do { _S2N_ERROR( ( x ) ); return S2N_FAILURE; } while (0) + +/** + * Sets the global `errno` and returns with a `NULL` pointer value + */ +#define BAIL_PTR( x ) do { _S2N_ERROR( ( x ) ); return NULL; } while (0) + +/** + * Ensures the `condition` is `true`, otherwise the function will `BAIL` with an `error` + */ +#define ENSURE( condition , error ) __S2N_ENSURE((condition), BAIL(error)) + +/** + * Ensures the `result` is OK, otherwise the function will `BAIL` with an `error` + */ +#define ENSURE_OK( result , error ) __S2N_ENSURE(s2n_result_is_ok(result), BAIL(error)) + +/** + * Ensures `n` is greater than or equal to `min`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error + */ +#define ENSURE_GTE( n , min ) ENSURE((n) >= (min), S2N_ERR_SAFETY) + +/** + * Ensures `n` is less than or equal to `max`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error + */ +#define ENSURE_LTE( n , max ) ENSURE((n) <= (max), S2N_ERR_SAFETY) + +/** + * Ensures `n` is greater than `min`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error + */ +#define ENSURE_GT( n , min ) ENSURE((n) > (min), S2N_ERR_SAFETY) + +/** + * Ensures `n` is less than `min`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error + */ +#define ENSURE_LT( n , max ) ENSURE((n) < (max), S2N_ERR_SAFETY) + +/** + * Ensures `a` is equal to `b`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error + */ +#define ENSURE_EQ( a , b ) ENSURE((a) == (b), S2N_ERR_SAFETY) + +/** + * Ensures `a` is not equal to `b`, otherwise the function will `BAIL` with a `S2N_ERR_SAFETY` error + */ +#define ENSURE_NE( a , b ) ENSURE((a) != (b), S2N_ERR_SAFETY) + +/** + * Ensures the `condition` is `true`, otherwise the function will `BAIL_POSIX` with an `error` + */ +#define ENSURE_POSIX( condition , error ) __S2N_ENSURE((condition), BAIL_POSIX(error)) + +/** + * Ensures the `condition` is `true`, otherwise the function will `BAIL_PTR` with an `error` + */ +#define ENSURE_PTR( condition , error ) __S2N_ENSURE((condition), BAIL_PTR(error)) + +/** + * Ensures `x` is not `NULL`, otherwise the function will `BAIL_PTR` with an `error` + */ +#define ENSURE_REF_PTR( x ) ENSURE_PTR(S2N_OBJECT_PTR_IS_READABLE(x), S2N_ERR_NULL) + +/** + * Ensures `x` is a readable reference, otherwise the function will `BAIL` with `S2N_ERR_NULL` + */ +#define ENSURE_REF( x ) ENSURE(S2N_OBJECT_PTR_IS_READABLE(x), S2N_ERR_NULL) + +/** + * Ensures `x` is a readable reference, otherwise the function will `BAIL_POSIX` with `S2N_ERR_NULL` + */ +#define ENSURE_POSIX_REF( x ) ENSURE_POSIX(S2N_OBJECT_PTR_IS_READABLE(x), S2N_ERR_NULL) + +/** + * Ensures `x` is a mutable reference, otherwise the function will `BAIL` with `S2N_ERR_NULL` + */ +#define ENSURE_MUT( x ) ENSURE(S2N_OBJECT_PTR_IS_WRITABLE(x), S2N_ERR_NULL) + +/** + * Ensures `x` is a mutable reference, otherwise the function will `BAIL_POSIX` with `S2N_ERR_NULL` + */ +#define ENSURE_POSIX_MUT( x ) ENSURE_POSIX(S2N_OBJECT_PTR_IS_WRITABLE(x), S2N_ERR_NULL) + +/** + * Ensures `min <= n <= max` + */ +#define ENSURE_INCLUSIVE_RANGE( min , n , max ) \ + do { \ + __typeof( n ) __tmp_n = ( n ); \ + ENSURE_GTE(__tmp_n, min); \ + ENSURE_LTE(__tmp_n, max); \ + } while(0) + +/** + * Ensures `min < n < max` + */ +#define ENSURE_EXCLUSIVE_RANGE( min , n , max ) \ + do { \ + __typeof( n ) __tmp_n = ( n ); \ + ENSURE_GT(__tmp_n, min); \ + ENSURE_LT(__tmp_n, max); \ + } while(0) + +/** + * Ensures the `result` is `S2N_RESULT_OK`, otherwise the function will return an error signal + */ +#define PRECONDITION( result ) GUARD_RESULT(__S2N_ENSURE_PRECONDITION(result)) + +/** + * Ensures the `result` is `S2N_RESULT_OK`, otherwise the function will return an error signal + */ +#define POSTCONDITION( result ) GUARD_RESULT(__S2N_ENSURE_POSTCONDITION(result)) + +/** + * Ensures the `result` is `S2N_RESULT_OK`, otherwise the function will return an error signal + */ +#define PRECONDITION_POSIX( result ) GUARD_AS_POSIX(__S2N_ENSURE_PRECONDITION(result)) + +/** + * Ensures the `result` is `S2N_RESULT_OK`, otherwise the function will return an error signal + */ +#define POSTCONDITION_POSIX( result ) GUARD_AS_POSIX(__S2N_ENSURE_POSTCONDITION(result)) + +/** + * Ensures the `condition` is `true`, otherwise the function will `BAIL` with an `error`. + * When the code is built in debug mode, they are checked. + * When the code is built in production mode, they are ignored. + */ +#define DEBUG_ENSURE( condition, error ) __S2N_ENSURE_DEBUG((condition), BAIL(error)) + +/** + * Ensures the `condition` is `true`, otherwise the function will `BAIL_POSIX` with an `error`. + * When the code is built in debug mode, they are checked. + * When the code is built in production mode, they are ignored. + */ +#define DEBUG_ENSURE_POSIX( condition, error ) __S2N_ENSURE_DEBUG((condition), BAIL_POSIX(error)) + +/** + * Ensures `x` is not an error, otherwise the function will return an error signal + * + * Note: this currently accepts POSIX error signals but will transition to accept s2n_result + */ +#define GUARD( x ) GUARD_POSIX(x) + +/** + * Ensures `x` is not an error, otherwise goto `label` + * + * Note: this currently accepts POSIX error signals but will transition to accept s2n_result + */ +#define GUARD_GOTO( x , label ) GUARD_POSIX_GOTO((x), (label)) + +/** + * Ensures `x` is not an error, otherwise the function will return `NULL` + * + * Note: this currently accepts POSIX error signals but will transition to accept s2n_result + */ +#define GUARD_PTR( x ) GUARD_POSIX_PTR(x) + +/** + * Ensures `x` is not `NULL`, otherwise the function will return an error signal + * + * Note: this currently accepts POSIX error signals but will transition to accept s2n_result + */ +#define GUARD_NONNULL( x ) GUARD_POSIX_NONNULL(x) + +/** + * Ensures `x` is not `NULL`, otherwise goto `label` + * + * Note: this currently accepts POSIX error signals but will transition to accept s2n_result + */ +#define GUARD_NONNULL_GOTO( x , label ) __S2N_ENSURE((x) != NULL, goto label) + +/** + * Ensures `x` is not `NULL`, otherwise the function will return `NULL` + * + * Note: this currently accepts POSIX error signals but will transition to accept s2n_result + */ +#define GUARD_NONNULL_PTR( x ) __S2N_ENSURE((x) != NULL, return NULL) + +/** + * Ensures `x` is not a OpenSSL error, otherwise the function will return an error signal + * + * Note: this currently accepts POSIX error signals but will transition to accept s2n_result + */ +#define GUARD_OSSL( x, error ) GUARD_POSIX_OSSL((x), (error)) + +/** + * Ensures `x` is ok, otherwise the function will return an `S2N_RESULT_ERROR` + */ +#define GUARD_RESULT( x ) __S2N_ENSURE(s2n_result_is_ok(x), return S2N_RESULT_ERROR) + +/** + * Ensures `x` is ok, otherwise goto `label` + */ +#define GUARD_RESULT_GOTO( x, label ) __S2N_ENSURE(s2n_result_is_ok(x), goto label) + +/** + * Ensures `x` is ok, otherwise the function will return `NULL` + */ +#define GUARD_RESULT_PTR( x ) __S2N_ENSURE(s2n_result_is_ok(x), return NULL) + +/** + * Ensures `x` is not `NULL`, otherwise the function will return an `S2N_RESULT_ERROR` + */ +#define GUARD_RESULT_NONNULL( x ) __S2N_ENSURE((x) != NULL, return S2N_RESULT_ERROR) + +/** + * Ensures `x` is not a OpenSSL error, otherwise the function will `BAIL` with `error` + */ +/* TODO: use the OSSL error code in error reporting https://github.com/awslabs/s2n/issues/705 */ +#define GUARD_RESULT_OSSL( x , error ) ENSURE((x) == _OSSL_SUCCESS, error) + +/** + * Ensures `x` is not a POSIX error, otherwise return a POSIX error + */ +#define GUARD_POSIX( x ) __S2N_ENSURE((x) >= S2N_SUCCESS, return S2N_FAILURE) + +/** + * Ensures `x` is strictly not a POSIX error (`-1`), otherwise goto `label` + */ +#define GUARD_POSIX_STRICT( x ) __S2N_ENSURE((x) == S2N_SUCCESS, return S2N_FAILURE) + +/** + * Ensures `x` is not a POSIX error, otherwise goto `label` + */ +#define GUARD_POSIX_GOTO( x , label ) __S2N_ENSURE((x) >= S2N_SUCCESS, goto label) + +/** + * Ensures `x` is not a POSIX error, otherwise the function will return `NULL` + */ +#define GUARD_POSIX_PTR( x ) __S2N_ENSURE((x) >= S2N_SUCCESS, return NULL) + +/** + * Ensures `x` is not `NULL`, otherwise the function will return a POSIX error (`-1`) + */ +#define GUARD_POSIX_NONNULL( x ) __S2N_ENSURE((x) != NULL, return S2N_FAILURE) + +/** + * Ensures `x` is not a OpenSSL error, otherwise the function will `BAIL` with `error` + */ +/* TODO: use the OSSL error code in error reporting https://github.com/awslabs/s2n/issues/705 */ +#define GUARD_POSIX_OSSL( x , error ) ENSURE_POSIX((x) == _OSSL_SUCCESS, error) + +/** + * Ensures `x` is not a POSIX error, otherwise the function will return a `S2N_RESULT_ERROR` + */ +#define GUARD_AS_RESULT( x ) __S2N_ENSURE((x) >= S2N_SUCCESS, return S2N_RESULT_ERROR) + +/** + * Ensures `x` is OK (S2N_RESULT), otherwise the function will return a POSIX error (`-1`) + */ +#define GUARD_AS_POSIX( x ) __S2N_ENSURE(s2n_result_is_ok(x), return S2N_FAILURE) + +/** + * Performs a safe memcpy + */ +#define CHECKED_MEMCPY( d , s , n ) __S2N_ENSURE_SAFE_MEMCPY((d), (s), (n), GUARD_RESULT_NONNULL) + +/** + * Performs a safe memset + */ +#define CHECKED_MEMSET( d , c , n ) __S2N_ENSURE_SAFE_MEMSET((d), (c), (n), ENSURE_REF) + +/** + * Marks a case of a switch statement as able to fall through to the next case + */ +#if (defined(__clang__) && __clang_major__ >= 10) || (defined(__GNUC__) && __GNUC__ >= 7) +# define FALL_THROUGH __attribute__((fallthrough)) +#else +# define FALL_THROUGH ((void)0) +#endif + +/* Returns `true` if s2n is in unit test mode, `false` otherwise */ +bool s2n_in_unit_test(); + +/* Sets whether s2n is in unit test mode */ +int s2n_in_unit_test_set(bool newval); + +#define S2N_IN_INTEG_TEST ( getenv("S2N_INTEG_TEST") != NULL ) +#define S2N_IN_TEST ( s2n_in_unit_test() || S2N_IN_INTEG_TEST ) + +/** + * Get the process id + * + * Returns: + * The process ID of the current process + */ +extern pid_t s2n_actual_getpid(); + +/* Returns 1 if a and b are equal, in constant time */ +extern bool s2n_constant_time_equals(const uint8_t * a, const uint8_t * b, const uint32_t len); + +/* Copy src to dst, or don't copy it, in constant time */ +extern int s2n_constant_time_copy_or_dont(uint8_t * dst, const uint8_t * src, uint32_t len, uint8_t dont); + +/* If src contains valid PKCS#1 v1.5 padding of exactly expectlen bytes, decode + * it into dst, otherwise leave dst alone, in constant time. + * Always returns zero. */ +extern int s2n_constant_time_pkcs1_unpad_or_dont(uint8_t * dst, const uint8_t * src, uint32_t srclen, uint32_t expectlen); + +/** + * Runs _thecleanup function on _thealloc once _thealloc went out of scope + */ +#define DEFER_CLEANUP(_thealloc, _thecleanup) \ + __attribute__((cleanup(_thecleanup))) _thealloc + +/* Creates cleanup function for pointers from function func which accepts a pointer. + * This is useful for DEFER_CLEANUP as it passes &_thealloc into _thecleanup function, + * so if _thealloc is a pointer _thecleanup will receive a pointer to a pointer.*/ +#define DEFINE_POINTER_CLEANUP_FUNC(type, func) \ + static inline void func##_pointer(type *p) { \ + if (p && *p) \ + func(*p); \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define s2n_array_len(array) ((array != NULL) ? (sizeof(array) / sizeof(array[0])) : 0) + +extern int s2n_mul_overflow(uint32_t a, uint32_t b, uint32_t* out); + +/** + * Rounds "initial" up to a multiple of "alignment", and stores the result in "out". + * Raises an error if overflow would occur. + * NOT CONSTANT TIME. + */ +extern int s2n_align_to(uint32_t initial, uint32_t alignment, uint32_t* out); +extern int s2n_add_overflow(uint32_t a, uint32_t b, uint32_t* out); +extern int s2n_sub_overflow(uint32_t a, uint32_t b, uint32_t* out); +/* START COMPATIBILITY LAYER */ + +/** + * NOTE: This will be removed once everything is using s2n_result + */ + +/* `NULL` check a pointer */ + +/* Note: this macro is replaced by ENSURE_POSIX_REF */ +#define notnull_check(ptr) ENSURE_POSIX_REF(ptr) +/* Note: this macro is replaced by ENSURE_REF_PTR */ +#define notnull_check_ptr(ptr) ENSURE_REF_PTR(ptr) + +/* Range check a number */ +#define gte_check( n , min ) ENSURE_POSIX((n) >= (min), S2N_ERR_SAFETY) +#define lte_check( n , max ) ENSURE_POSIX((n) <= (max), S2N_ERR_SAFETY) +#define gt_check( n , min ) ENSURE_POSIX((n) > (min), S2N_ERR_SAFETY) +#define lt_check( n , max ) ENSURE_POSIX((n) < (max), S2N_ERR_SAFETY) +#define eq_check( a , b ) ENSURE_POSIX((a) == (b), S2N_ERR_SAFETY) +#define ne_check( a , b ) ENSURE_POSIX((a) != (b), S2N_ERR_SAFETY) +#define inclusive_range_check( low, n, high ) \ + do { \ + __typeof( n ) __tmp_n = ( n ); \ + gte_check(__tmp_n, low); \ + lte_check(__tmp_n, high); \ + } while (0) +#define exclusive_range_check( low, n, high ) \ + do { \ + __typeof( n ) __tmp_n = ( n ); \ + gt_check(__tmp_n, low); \ + lt_check(__tmp_n, high); \ + } while (0) + +#define memcpy_check( d , s , n ) __S2N_ENSURE_SAFE_MEMCPY((d), (s), (n), GUARD_POSIX_NONNULL) +/* This will fail to build if d is an array. Cast the array to a pointer first! */ +#define memset_check( d , c , n ) __S2N_ENSURE_SAFE_MEMSET((d), (c), (n), ENSURE_POSIX_REF) + +/* END COMPATIBILITY LAYER */ diff --git a/contrib/restricted/aws/s2n/utils/s2n_set.c b/contrib/restricted/aws/s2n/utils/s2n_set.c index 4073a4cc5d..9c5d5769fa 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_set.c +++ b/contrib/restricted/aws/s2n/utils/s2n_set.c @@ -1,147 +1,147 @@ -/* - * 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 "utils/s2n_blob.h" -#include "utils/s2n_mem.h" -#include "utils/s2n_result.h" -#include "utils/s2n_safety.h" -#include "utils/s2n_set.h" -#include "utils/s2n_array.h" - -#define S2N_INITIAL_SET_SIZE 16 - -S2N_RESULT s2n_set_validate(const struct s2n_set *set) -{ - ENSURE_REF(set); - GUARD_RESULT(s2n_array_validate(set->data)); - return S2N_RESULT_OK; -} - -/* Sets "out" to the index at which the element should be inserted. - * Returns an error if the element already exists */ -static S2N_RESULT s2n_set_binary_search(struct s2n_set *set, void *element, uint32_t* out) -{ - GUARD_RESULT(s2n_set_validate(set)); - ENSURE(S2N_MEM_IS_READABLE(element, set->data->element_size), S2N_ERR_NULL); - ENSURE_REF(out); - struct s2n_array *array = set->data; - int (*comparator)(const void*, const void*) = set->comparator; - - uint32_t len = 0; - GUARD_RESULT(s2n_array_num_elements(array, &len)); - - if (len == 0) { - *out = 0; - return S2N_RESULT_OK; - } - - /* Use 64 bit ints to avoid possibility of overflow */ - int64_t low = 0; - int64_t top = len - 1; - - while (low <= top) { - int64_t mid = low + ((top - low) / 2); - void* array_element = NULL; - GUARD_RESULT(s2n_array_get(array, mid, &array_element)); - int m = comparator(array_element, element); - - /* the element is already in the set */ - if (m == 0) { - BAIL(S2N_ERR_SET_DUPLICATE_VALUE); - } - - if (m > 0) { - top = mid - 1; - } else { - low = mid + 1; - } - } - - *out = low; - return S2N_RESULT_OK; -} - -struct s2n_set *s2n_set_new(uint32_t element_size, int (*comparator)(const void*, const void*)) -{ - notnull_check_ptr(comparator); - struct s2n_blob mem = {0}; - GUARD_POSIX_PTR(s2n_alloc(&mem, sizeof(struct s2n_set))); - struct s2n_set *set = (void *) mem.data; - *set = (struct s2n_set) {.data = s2n_array_new(element_size), .comparator = comparator}; - if(set->data == NULL) { - GUARD_POSIX_PTR(s2n_free(&mem)); - return NULL; - } - return set; -} - -S2N_RESULT s2n_set_add(struct s2n_set *set, void *element) -{ - GUARD_RESULT(s2n_set_validate(set)); - - uint32_t index = 0; - GUARD_RESULT(s2n_set_binary_search(set, element, &index)); - GUARD_RESULT(s2n_array_insert_and_copy(set->data, index, element)); - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_set_get(struct s2n_set *set, uint32_t index, void **element) -{ - GUARD_RESULT(s2n_set_validate(set)); - ENSURE_REF(element); - - GUARD_RESULT(s2n_array_get(set->data, index, element)); - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_set_remove(struct s2n_set *set, uint32_t index) -{ - GUARD_RESULT(s2n_set_validate(set)); - GUARD_RESULT(s2n_array_remove(set->data, index)); - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_set_free_p(struct s2n_set **pset) -{ - ENSURE_REF(pset); - struct s2n_set *set = *pset; - - ENSURE_REF(set); - GUARD_RESULT(s2n_array_free(set->data)); - - /* And finally the set object. */ - GUARD_AS_RESULT(s2n_free_object((uint8_t **)pset, sizeof(struct s2n_set))); - - return S2N_RESULT_OK; - -} - -S2N_RESULT s2n_set_free(struct s2n_set *set) -{ - ENSURE_REF(set); - return s2n_set_free_p(&set); -} - - -S2N_RESULT s2n_set_len(struct s2n_set *set, uint32_t *len) -{ - GUARD_RESULT(s2n_set_validate(set)); - - GUARD_RESULT(s2n_array_num_elements(set->data, len)); - - return S2N_RESULT_OK; -} +/* + * 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 "utils/s2n_blob.h" +#include "utils/s2n_mem.h" +#include "utils/s2n_result.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_set.h" +#include "utils/s2n_array.h" + +#define S2N_INITIAL_SET_SIZE 16 + +S2N_RESULT s2n_set_validate(const struct s2n_set *set) +{ + ENSURE_REF(set); + GUARD_RESULT(s2n_array_validate(set->data)); + return S2N_RESULT_OK; +} + +/* Sets "out" to the index at which the element should be inserted. + * Returns an error if the element already exists */ +static S2N_RESULT s2n_set_binary_search(struct s2n_set *set, void *element, uint32_t* out) +{ + GUARD_RESULT(s2n_set_validate(set)); + ENSURE(S2N_MEM_IS_READABLE(element, set->data->element_size), S2N_ERR_NULL); + ENSURE_REF(out); + struct s2n_array *array = set->data; + int (*comparator)(const void*, const void*) = set->comparator; + + uint32_t len = 0; + GUARD_RESULT(s2n_array_num_elements(array, &len)); + + if (len == 0) { + *out = 0; + return S2N_RESULT_OK; + } + + /* Use 64 bit ints to avoid possibility of overflow */ + int64_t low = 0; + int64_t top = len - 1; + + while (low <= top) { + int64_t mid = low + ((top - low) / 2); + void* array_element = NULL; + GUARD_RESULT(s2n_array_get(array, mid, &array_element)); + int m = comparator(array_element, element); + + /* the element is already in the set */ + if (m == 0) { + BAIL(S2N_ERR_SET_DUPLICATE_VALUE); + } + + if (m > 0) { + top = mid - 1; + } else { + low = mid + 1; + } + } + + *out = low; + return S2N_RESULT_OK; +} + +struct s2n_set *s2n_set_new(uint32_t element_size, int (*comparator)(const void*, const void*)) +{ + notnull_check_ptr(comparator); + struct s2n_blob mem = {0}; + GUARD_POSIX_PTR(s2n_alloc(&mem, sizeof(struct s2n_set))); + struct s2n_set *set = (void *) mem.data; + *set = (struct s2n_set) {.data = s2n_array_new(element_size), .comparator = comparator}; + if(set->data == NULL) { + GUARD_POSIX_PTR(s2n_free(&mem)); + return NULL; + } + return set; +} + +S2N_RESULT s2n_set_add(struct s2n_set *set, void *element) +{ + GUARD_RESULT(s2n_set_validate(set)); + + uint32_t index = 0; + GUARD_RESULT(s2n_set_binary_search(set, element, &index)); + GUARD_RESULT(s2n_array_insert_and_copy(set->data, index, element)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_set_get(struct s2n_set *set, uint32_t index, void **element) +{ + GUARD_RESULT(s2n_set_validate(set)); + ENSURE_REF(element); + + GUARD_RESULT(s2n_array_get(set->data, index, element)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_set_remove(struct s2n_set *set, uint32_t index) +{ + GUARD_RESULT(s2n_set_validate(set)); + GUARD_RESULT(s2n_array_remove(set->data, index)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_set_free_p(struct s2n_set **pset) +{ + ENSURE_REF(pset); + struct s2n_set *set = *pset; + + ENSURE_REF(set); + GUARD_RESULT(s2n_array_free(set->data)); + + /* And finally the set object. */ + GUARD_AS_RESULT(s2n_free_object((uint8_t **)pset, sizeof(struct s2n_set))); + + return S2N_RESULT_OK; + +} + +S2N_RESULT s2n_set_free(struct s2n_set *set) +{ + ENSURE_REF(set); + return s2n_set_free_p(&set); +} + + +S2N_RESULT s2n_set_len(struct s2n_set *set, uint32_t *len) +{ + GUARD_RESULT(s2n_set_validate(set)); + + GUARD_RESULT(s2n_array_num_elements(set->data, len)); + + return S2N_RESULT_OK; +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_set.h b/contrib/restricted/aws/s2n/utils/s2n_set.h index b3dba15453..508663a19d 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_set.h +++ b/contrib/restricted/aws/s2n/utils/s2n_set.h @@ -1,33 +1,33 @@ -/* - * 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 <s2n.h> -#include "utils/s2n_result.h" -#include "utils/s2n_array.h" - -struct s2n_set { - struct s2n_array *data; - int (*comparator)(const void*, const void*); -}; - -extern S2N_RESULT s2n_set_validate(const struct s2n_set *set); -extern struct s2n_set *s2n_set_new(uint32_t element_size, int (*comparator)(const void*, const void*)); -extern S2N_RESULT s2n_set_add(struct s2n_set *set, void *element); -extern S2N_RESULT s2n_set_get(struct s2n_set *set, uint32_t index, void **element); -extern S2N_RESULT s2n_set_remove(struct s2n_set *set, uint32_t index); -extern S2N_RESULT s2n_set_free_p(struct s2n_set **pset); -extern S2N_RESULT s2n_set_free(struct s2n_set *set); -extern S2N_RESULT s2n_set_len(struct s2n_set *set, uint32_t *len); +/* + * 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 <s2n.h> +#include "utils/s2n_result.h" +#include "utils/s2n_array.h" + +struct s2n_set { + struct s2n_array *data; + int (*comparator)(const void*, const void*); +}; + +extern S2N_RESULT s2n_set_validate(const struct s2n_set *set); +extern struct s2n_set *s2n_set_new(uint32_t element_size, int (*comparator)(const void*, const void*)); +extern S2N_RESULT s2n_set_add(struct s2n_set *set, void *element); +extern S2N_RESULT s2n_set_get(struct s2n_set *set, uint32_t index, void **element); +extern S2N_RESULT s2n_set_remove(struct s2n_set *set, uint32_t index); +extern S2N_RESULT s2n_set_free_p(struct s2n_set **pset); +extern S2N_RESULT s2n_set_free(struct s2n_set *set); +extern S2N_RESULT s2n_set_len(struct s2n_set *set, uint32_t *len); diff --git a/contrib/restricted/aws/s2n/utils/s2n_socket.c b/contrib/restricted/aws/s2n/utils/s2n_socket.c index daefd1168a..faef725624 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_socket.c +++ b/contrib/restricted/aws/s2n/utils/s2n_socket.c @@ -1,226 +1,226 @@ -/* - * 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 <tls/s2n_connection.h> - -#include <utils/s2n_socket.h> -#include <utils/s2n_safety.h> - -#include <netinet/tcp.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <unistd.h> - -#if TCP_CORK - #define S2N_CORK TCP_CORK - #define S2N_CORK_ON 1 - #define S2N_CORK_OFF 0 -#elif TCP_NOPUSH - #define S2N_CORK TCP_NOPUSH - #define S2N_CORK_ON 1 - #define S2N_CORK_OFF 0 -#elif TCP_NODELAY - #define S2N_CORK TCP_NODELAY - #define S2N_CORK_ON 0 - #define S2N_CORK_OFF 1 -#endif - -int s2n_socket_quickack(struct s2n_connection *conn) -{ -#ifdef TCP_QUICKACK - if (!conn->managed_io) { - return 0; - } - - struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context; - if (r_io_ctx->tcp_quickack_set) { - return 0; - } - - /* Ignore the return value, if it fails it fails */ - int optval = 1; - if (setsockopt(r_io_ctx->fd, IPPROTO_TCP, TCP_QUICKACK, &optval, sizeof(optval)) == 0) { - r_io_ctx->tcp_quickack_set = 1; - } -#endif - - return 0; -} - -int s2n_socket_write_snapshot(struct s2n_connection *conn) -{ -#ifdef S2N_CORK - socklen_t corklen = sizeof(int); - - struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context; - notnull_check(w_io_ctx); - - getsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &w_io_ctx->original_cork_val, &corklen); - eq_check(corklen, sizeof(int)); - w_io_ctx->original_cork_is_set = 1; -#endif - - return 0; -} - - -int s2n_socket_read_snapshot(struct s2n_connection *conn) -{ -#ifdef SO_RCVLOWAT - socklen_t watlen = sizeof(int); - - struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context; - notnull_check(r_io_ctx); - - getsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &r_io_ctx->original_rcvlowat_val, &watlen); - eq_check(watlen, sizeof(int)); - r_io_ctx->original_rcvlowat_is_set = 1; -#endif - - return 0; -} - -int s2n_socket_write_restore(struct s2n_connection *conn) -{ -#ifdef S2N_CORK - struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context; - notnull_check(w_io_ctx); - - if (!w_io_ctx->original_cork_is_set) { - return 0; - } - setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &w_io_ctx->original_cork_val, sizeof(w_io_ctx->original_cork_val)); - w_io_ctx->original_cork_is_set = 0; -#endif - - return 0; -} - -int s2n_socket_read_restore(struct s2n_connection *conn) -{ -#ifdef SO_RCVLOWAT - struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context; - notnull_check(r_io_ctx); - - if (!r_io_ctx->original_rcvlowat_is_set) { - return 0; - } - setsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &r_io_ctx->original_rcvlowat_val, sizeof(r_io_ctx->original_rcvlowat_val)); - r_io_ctx->original_rcvlowat_is_set = 0; -#endif - - return 0; -} - -int s2n_socket_was_corked(struct s2n_connection *conn) -{ - /* If we're not using custom I/O and a send fd has not been set yet, return false*/ - if (!conn->managed_io || !conn->send) { - return 0; - } - - struct s2n_socket_write_io_context *io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context; - notnull_check(io_ctx); - - return io_ctx->original_cork_val; -} - -int s2n_socket_write_cork(struct s2n_connection *conn) -{ -#ifdef S2N_CORK - int optval = S2N_CORK_ON; - - struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context; - notnull_check(w_io_ctx); - - /* Ignore the return value, if it fails it fails */ - setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &optval, sizeof(optval)); -#endif - - return 0; -} - -int s2n_socket_write_uncork(struct s2n_connection *conn) -{ -#ifdef S2N_CORK - int optval = S2N_CORK_OFF; - - struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context; - notnull_check(w_io_ctx); - - /* Ignore the return value, if it fails it fails */ - setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &optval, sizeof(optval)); -#endif - - return 0; -} - -int s2n_socket_set_read_size(struct s2n_connection *conn, int size) -{ -#ifdef SO_RCVLOWAT - struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context; - notnull_check(r_io_ctx); - - setsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &size, sizeof(size)); -#endif - - return 0; -} - -int s2n_socket_read(void *io_context, uint8_t *buf, uint32_t len) -{ - int rfd = ((struct s2n_socket_read_io_context*) io_context)->fd; - if (rfd < 0) { - errno = EBADF; - S2N_ERROR(S2N_ERR_BAD_FD); - } - - /* Clear the quickack flag so we know to reset it */ - ((struct s2n_socket_read_io_context*) io_context)->tcp_quickack_set = 0; - - /* On success, the number of bytes read is returned. On failure, -1 is - * returned and errno is set appropriately. */ - return read(rfd, buf, len); -} - -int s2n_socket_write(void *io_context, const uint8_t *buf, uint32_t len) -{ - int wfd = ((struct s2n_socket_write_io_context*) io_context)->fd; - if (wfd < 0) { - errno = EBADF; - S2N_ERROR(S2N_ERR_BAD_FD); - } - - /* On success, the number of bytes written is returned. On failure, -1 is - * returned and errno is set appropriately. */ - return write(wfd, buf, len); -} - -int s2n_socket_is_ipv6(int fd, uint8_t *ipv6) -{ - notnull_check(ipv6); - - socklen_t len; - struct sockaddr_storage addr; - len = sizeof (addr); - GUARD(getpeername(fd, (struct sockaddr*)&addr, &len)); - - *ipv6 = 0; - if (AF_INET6 == addr.ss_family) { - *ipv6 = 1; - } - - return 0; -} +/* + * 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 <tls/s2n_connection.h> + +#include <utils/s2n_socket.h> +#include <utils/s2n_safety.h> + +#include <netinet/tcp.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <unistd.h> + +#if TCP_CORK + #define S2N_CORK TCP_CORK + #define S2N_CORK_ON 1 + #define S2N_CORK_OFF 0 +#elif TCP_NOPUSH + #define S2N_CORK TCP_NOPUSH + #define S2N_CORK_ON 1 + #define S2N_CORK_OFF 0 +#elif TCP_NODELAY + #define S2N_CORK TCP_NODELAY + #define S2N_CORK_ON 0 + #define S2N_CORK_OFF 1 +#endif + +int s2n_socket_quickack(struct s2n_connection *conn) +{ +#ifdef TCP_QUICKACK + if (!conn->managed_io) { + return 0; + } + + struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context; + if (r_io_ctx->tcp_quickack_set) { + return 0; + } + + /* Ignore the return value, if it fails it fails */ + int optval = 1; + if (setsockopt(r_io_ctx->fd, IPPROTO_TCP, TCP_QUICKACK, &optval, sizeof(optval)) == 0) { + r_io_ctx->tcp_quickack_set = 1; + } +#endif + + return 0; +} + +int s2n_socket_write_snapshot(struct s2n_connection *conn) +{ +#ifdef S2N_CORK + socklen_t corklen = sizeof(int); + + struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context; + notnull_check(w_io_ctx); + + getsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &w_io_ctx->original_cork_val, &corklen); + eq_check(corklen, sizeof(int)); + w_io_ctx->original_cork_is_set = 1; +#endif + + return 0; +} + + +int s2n_socket_read_snapshot(struct s2n_connection *conn) +{ +#ifdef SO_RCVLOWAT + socklen_t watlen = sizeof(int); + + struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context; + notnull_check(r_io_ctx); + + getsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &r_io_ctx->original_rcvlowat_val, &watlen); + eq_check(watlen, sizeof(int)); + r_io_ctx->original_rcvlowat_is_set = 1; +#endif + + return 0; +} + +int s2n_socket_write_restore(struct s2n_connection *conn) +{ +#ifdef S2N_CORK + struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context; + notnull_check(w_io_ctx); + + if (!w_io_ctx->original_cork_is_set) { + return 0; + } + setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &w_io_ctx->original_cork_val, sizeof(w_io_ctx->original_cork_val)); + w_io_ctx->original_cork_is_set = 0; +#endif + + return 0; +} + +int s2n_socket_read_restore(struct s2n_connection *conn) +{ +#ifdef SO_RCVLOWAT + struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context; + notnull_check(r_io_ctx); + + if (!r_io_ctx->original_rcvlowat_is_set) { + return 0; + } + setsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &r_io_ctx->original_rcvlowat_val, sizeof(r_io_ctx->original_rcvlowat_val)); + r_io_ctx->original_rcvlowat_is_set = 0; +#endif + + return 0; +} + +int s2n_socket_was_corked(struct s2n_connection *conn) +{ + /* If we're not using custom I/O and a send fd has not been set yet, return false*/ + if (!conn->managed_io || !conn->send) { + return 0; + } + + struct s2n_socket_write_io_context *io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context; + notnull_check(io_ctx); + + return io_ctx->original_cork_val; +} + +int s2n_socket_write_cork(struct s2n_connection *conn) +{ +#ifdef S2N_CORK + int optval = S2N_CORK_ON; + + struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context; + notnull_check(w_io_ctx); + + /* Ignore the return value, if it fails it fails */ + setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &optval, sizeof(optval)); +#endif + + return 0; +} + +int s2n_socket_write_uncork(struct s2n_connection *conn) +{ +#ifdef S2N_CORK + int optval = S2N_CORK_OFF; + + struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context; + notnull_check(w_io_ctx); + + /* Ignore the return value, if it fails it fails */ + setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &optval, sizeof(optval)); +#endif + + return 0; +} + +int s2n_socket_set_read_size(struct s2n_connection *conn, int size) +{ +#ifdef SO_RCVLOWAT + struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context; + notnull_check(r_io_ctx); + + setsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &size, sizeof(size)); +#endif + + return 0; +} + +int s2n_socket_read(void *io_context, uint8_t *buf, uint32_t len) +{ + int rfd = ((struct s2n_socket_read_io_context*) io_context)->fd; + if (rfd < 0) { + errno = EBADF; + S2N_ERROR(S2N_ERR_BAD_FD); + } + + /* Clear the quickack flag so we know to reset it */ + ((struct s2n_socket_read_io_context*) io_context)->tcp_quickack_set = 0; + + /* On success, the number of bytes read is returned. On failure, -1 is + * returned and errno is set appropriately. */ + return read(rfd, buf, len); +} + +int s2n_socket_write(void *io_context, const uint8_t *buf, uint32_t len) +{ + int wfd = ((struct s2n_socket_write_io_context*) io_context)->fd; + if (wfd < 0) { + errno = EBADF; + S2N_ERROR(S2N_ERR_BAD_FD); + } + + /* On success, the number of bytes written is returned. On failure, -1 is + * returned and errno is set appropriately. */ + return write(wfd, buf, len); +} + +int s2n_socket_is_ipv6(int fd, uint8_t *ipv6) +{ + notnull_check(ipv6); + + socklen_t len; + struct sockaddr_storage addr; + len = sizeof (addr); + GUARD(getpeername(fd, (struct sockaddr*)&addr, &len)); + + *ipv6 = 0; + if (AF_INET6 == addr.ss_family) { + *ipv6 = 1; + } + + return 0; +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_socket.h b/contrib/restricted/aws/s2n/utils/s2n_socket.h index 693ac758a3..12cd05c7b8 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_socket.h +++ b/contrib/restricted/aws/s2n/utils/s2n_socket.h @@ -1,53 +1,53 @@ -/* - * 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 "tls/s2n_connection.h" - -/* The default read I/O context for communication over a socket */ -struct s2n_socket_read_io_context { - /* The peer's fd */ - int fd; - - /* Has TCP_QUICKACK been set since the last read */ - unsigned int tcp_quickack_set:1; - /* Original SO_RCVLOWAT socket option settings before s2n takes over the fd */ - unsigned int original_rcvlowat_is_set:1; - int original_rcvlowat_val; -}; - -/* The default write I/O context for communication over a socket */ -struct s2n_socket_write_io_context { - /* The peer's fd */ - int fd; - - /* Original TCP_CORK socket option settings before s2n takes over the fd */ - unsigned int original_cork_is_set:1; - int original_cork_val; -}; - -extern int s2n_socket_quickack(struct s2n_connection *conn); -extern int s2n_socket_read_snapshot(struct s2n_connection *conn); -extern int s2n_socket_write_snapshot(struct s2n_connection *conn); -extern int s2n_socket_read_restore(struct s2n_connection *conn); -extern int s2n_socket_write_restore(struct s2n_connection *conn); -extern int s2n_socket_was_corked(struct s2n_connection *conn); -extern int s2n_socket_write_cork(struct s2n_connection *conn); -extern int s2n_socket_write_uncork(struct s2n_connection *conn); -extern int s2n_socket_set_read_size(struct s2n_connection *conn, int size); -extern int s2n_socket_read(void *io_context, uint8_t *buf, uint32_t len); -extern int s2n_socket_write(void *io_context, const uint8_t *buf, uint32_t len); -extern int s2n_socket_is_ipv6(int fd, uint8_t *ipv6); +/* + * 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 "tls/s2n_connection.h" + +/* The default read I/O context for communication over a socket */ +struct s2n_socket_read_io_context { + /* The peer's fd */ + int fd; + + /* Has TCP_QUICKACK been set since the last read */ + unsigned int tcp_quickack_set:1; + /* Original SO_RCVLOWAT socket option settings before s2n takes over the fd */ + unsigned int original_rcvlowat_is_set:1; + int original_rcvlowat_val; +}; + +/* The default write I/O context for communication over a socket */ +struct s2n_socket_write_io_context { + /* The peer's fd */ + int fd; + + /* Original TCP_CORK socket option settings before s2n takes over the fd */ + unsigned int original_cork_is_set:1; + int original_cork_val; +}; + +extern int s2n_socket_quickack(struct s2n_connection *conn); +extern int s2n_socket_read_snapshot(struct s2n_connection *conn); +extern int s2n_socket_write_snapshot(struct s2n_connection *conn); +extern int s2n_socket_read_restore(struct s2n_connection *conn); +extern int s2n_socket_write_restore(struct s2n_connection *conn); +extern int s2n_socket_was_corked(struct s2n_connection *conn); +extern int s2n_socket_write_cork(struct s2n_connection *conn); +extern int s2n_socket_write_uncork(struct s2n_connection *conn); +extern int s2n_socket_set_read_size(struct s2n_connection *conn, int size); +extern int s2n_socket_read(void *io_context, uint8_t *buf, uint32_t len); +extern int s2n_socket_write(void *io_context, const uint8_t *buf, uint32_t len); +extern int s2n_socket_is_ipv6(int fd, uint8_t *ipv6); diff --git a/contrib/restricted/aws/s2n/utils/s2n_str.c b/contrib/restricted/aws/s2n/utils/s2n_str.c index a1be56b427..a80e7a2ed8 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_str.c +++ b/contrib/restricted/aws/s2n/utils/s2n_str.c @@ -1,49 +1,49 @@ -/* - * 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 <sys/param.h> -#include "utils/s2n_str.h" - -char *s2n_strcpy(char *buf, char *last, const char *str) { - -/* CBMC pointer checks need to be disabled to compare buf and last for - * the case where they are the same. */ -#pragma CPROVER check push -#pragma CPROVER check disable "pointer" - - if (buf >= last) { - return buf; - } - -#pragma CPROVER check pop - - if (NULL == str) { - *buf = '\0'; - return buf; - } - - /* Free bytes needs to be one byte smaller than size of a storage, - * as strncpy always writes '\0', but doesn't include it in n - */ - size_t bytes_to_copy = MIN(last - buf - 1, strlen(str)); - - char *p = buf; - if (bytes_to_copy > 0) { - p = (char *)memcpy(buf, str, bytes_to_copy) + bytes_to_copy; - } - *p = '\0'; - - return p; -} +/* + * 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 <sys/param.h> +#include "utils/s2n_str.h" + +char *s2n_strcpy(char *buf, char *last, const char *str) { + +/* CBMC pointer checks need to be disabled to compare buf and last for + * the case where they are the same. */ +#pragma CPROVER check push +#pragma CPROVER check disable "pointer" + + if (buf >= last) { + return buf; + } + +#pragma CPROVER check pop + + if (NULL == str) { + *buf = '\0'; + return buf; + } + + /* Free bytes needs to be one byte smaller than size of a storage, + * as strncpy always writes '\0', but doesn't include it in n + */ + size_t bytes_to_copy = MIN(last - buf - 1, strlen(str)); + + char *p = buf; + if (bytes_to_copy > 0) { + p = (char *)memcpy(buf, str, bytes_to_copy) + bytes_to_copy; + } + *p = '\0'; + + return p; +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_str.h b/contrib/restricted/aws/s2n/utils/s2n_str.h index a0ca67c3ba..415891a274 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_str.h +++ b/contrib/restricted/aws/s2n/utils/s2n_str.h @@ -1,17 +1,17 @@ -/* - * 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 - -extern char *s2n_strcpy(char *buf, char *last, const char *str); +/* + * 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 + +extern char *s2n_strcpy(char *buf, char *last, const char *str); diff --git a/contrib/restricted/aws/s2n/utils/s2n_timer.c b/contrib/restricted/aws/s2n/utils/s2n_timer.c index e1766ce1e3..9a26278a4a 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_timer.c +++ b/contrib/restricted/aws/s2n/utils/s2n_timer.c @@ -1,49 +1,49 @@ -/* - * 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 "utils/s2n_result.h" -#include "utils/s2n_safety.h" -#include "utils/s2n_timer.h" - -#include "tls/s2n_config.h" - -S2N_RESULT s2n_timer_start(struct s2n_config *config, struct s2n_timer *timer) -{ - GUARD_AS_RESULT(config->monotonic_clock(config->monotonic_clock_ctx, &timer->time)); - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_timer_elapsed(struct s2n_config *config, struct s2n_timer *timer, uint64_t * nanoseconds) -{ - uint64_t current_time; - - GUARD_AS_RESULT(config->monotonic_clock(config->monotonic_clock_ctx, ¤t_time)); - - *nanoseconds = current_time - timer->time; - - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_timer_reset(struct s2n_config *config, struct s2n_timer *timer, uint64_t * nanoseconds) -{ - uint64_t previous_time = timer->time; - - GUARD_RESULT(s2n_timer_start(config, timer)); - - *nanoseconds = timer->time - previous_time; - - return S2N_RESULT_OK; -} +/* + * 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 "utils/s2n_result.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_timer.h" + +#include "tls/s2n_config.h" + +S2N_RESULT s2n_timer_start(struct s2n_config *config, struct s2n_timer *timer) +{ + GUARD_AS_RESULT(config->monotonic_clock(config->monotonic_clock_ctx, &timer->time)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_timer_elapsed(struct s2n_config *config, struct s2n_timer *timer, uint64_t * nanoseconds) +{ + uint64_t current_time; + + GUARD_AS_RESULT(config->monotonic_clock(config->monotonic_clock_ctx, ¤t_time)); + + *nanoseconds = current_time - timer->time; + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_timer_reset(struct s2n_config *config, struct s2n_timer *timer, uint64_t * nanoseconds) +{ + uint64_t previous_time = timer->time; + + GUARD_RESULT(s2n_timer_start(config, timer)); + + *nanoseconds = timer->time - previous_time; + + return S2N_RESULT_OK; +} diff --git a/contrib/restricted/aws/s2n/utils/s2n_timer.h b/contrib/restricted/aws/s2n/utils/s2n_timer.h index 8bd2b262c3..5532578720 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_timer.h +++ b/contrib/restricted/aws/s2n/utils/s2n_timer.h @@ -1,27 +1,27 @@ -/* - * 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 <stdint.h> -#include "utils/s2n_result.h" - -struct s2n_timer { - uint64_t time; -}; - -extern S2N_RESULT s2n_timer_start(struct s2n_config *config, struct s2n_timer *timer); -extern S2N_RESULT s2n_timer_elapsed(struct s2n_config *config, struct s2n_timer *timer, uint64_t * nanoseconds); -extern S2N_RESULT s2n_timer_reset(struct s2n_config *config, struct s2n_timer *timer, uint64_t * nanoseconds); +/* + * 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 <stdint.h> +#include "utils/s2n_result.h" + +struct s2n_timer { + uint64_t time; +}; + +extern S2N_RESULT s2n_timer_start(struct s2n_config *config, struct s2n_timer *timer); +extern S2N_RESULT s2n_timer_elapsed(struct s2n_config *config, struct s2n_timer *timer, uint64_t * nanoseconds); +extern S2N_RESULT s2n_timer_reset(struct s2n_config *config, struct s2n_timer *timer, uint64_t * nanoseconds); |