aws-crt 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/VERSION +1 -1
- data/aws-crt-ffi/crt/aws-c-cal/CMakeLists.txt +2 -0
- data/aws-crt-ffi/crt/aws-c-cal/bin/produce_x_platform_fuzz_corpus/CMakeLists.txt +30 -0
- data/aws-crt-ffi/crt/aws-c-cal/bin/produce_x_platform_fuzz_corpus/main.c +208 -0
- data/aws-crt-ffi/crt/aws-c-cal/bin/run_x_platform_fuzz_corpus/CMakeLists.txt +30 -0
- data/aws-crt-ffi/crt/aws-c-cal/bin/run_x_platform_fuzz_corpus/main.c +244 -0
- data/aws-crt-ffi/crt/aws-c-cal/ecdsa-fuzz-corpus/darwin/p256_sig_corpus.txt +10000 -0
- data/aws-crt-ffi/crt/aws-c-cal/ecdsa-fuzz-corpus/windows/p256_sig_corpus.txt +10000 -0
- data/aws-crt-ffi/crt/aws-c-cal/source/windows/bcrypt_ecc.c +8 -0
- data/aws-crt-ffi/crt/aws-c-http/tests/CMakeLists.txt +11 -10
- data/aws-crt-ffi/crt/aws-c-io/include/aws/io/tls_channel_handler.h +2 -0
- data/aws-crt-ffi/crt/aws-c-io/source/darwin/darwin_pki_utils.c +8 -0
- data/aws-crt-ffi/crt/aws-c-io/source/tls_channel_handler.c +2 -0
- data/aws-crt-ffi/crt/aws-c-io/source/windows/windows_pki_utils.c +65 -35
- data/aws-crt-ffi/crt/s2n/CMakeLists.txt +67 -21
- data/aws-crt-ffi/crt/s2n/Makefile +10 -0
- data/aws-crt-ffi/crt/s2n/bin/Makefile +9 -0
- data/aws-crt-ffi/crt/s2n/bindings/rust/Makefile +14 -0
- data/aws-crt-ffi/crt/s2n/bindings/rust/integration/Cargo.toml +2 -2
- data/aws-crt-ffi/crt/s2n/bindings/rust/s2n-tls/Cargo.toml +3 -2
- data/aws-crt-ffi/crt/s2n/bindings/rust/s2n-tls/src/raw/config.rs +265 -39
- data/aws-crt-ffi/crt/s2n/bindings/rust/s2n-tls/src/raw/connection.rs +170 -20
- data/aws-crt-ffi/crt/s2n/bindings/rust/s2n-tls/src/testing/s2n_tls.rs +120 -0
- data/aws-crt-ffi/crt/s2n/bindings/rust/s2n-tls/src/testing.rs +58 -23
- data/aws-crt-ffi/crt/s2n/bindings/rust/s2n-tls-sys/Cargo.toml +1 -1
- data/aws-crt-ffi/crt/s2n/bindings/rust/s2n-tls-sys/src/internal.rs +3 -0
- data/aws-crt-ffi/crt/s2n/crypto/s2n_composite_cipher_aes_sha.c +1 -1
- data/aws-crt-ffi/crt/s2n/crypto/s2n_drbg.c +8 -3
- data/aws-crt-ffi/crt/s2n/error/s2n_errno.c +3 -0
- data/aws-crt-ffi/crt/s2n/error/s2n_errno.h +2 -0
- data/aws-crt-ffi/crt/s2n/lib/Makefile +11 -0
- data/aws-crt-ffi/crt/s2n/pq-crypto/kyber_90s_r2/ntt.h +2 -2
- data/aws-crt-ffi/crt/s2n/pq-crypto/kyber_r2/ntt.h +2 -2
- data/aws-crt-ffi/crt/s2n/pq-crypto/kyber_r3/kyber512r3_poly_avx2.h +2 -2
- data/aws-crt-ffi/crt/s2n/pq-crypto/kyber_r3/kyber512r3_polyvec_avx2.h +2 -2
- data/aws-crt-ffi/crt/s2n/pq-crypto/sike_r1/P503_internal_r1.h +1 -1
- data/aws-crt-ffi/crt/s2n/pq-crypto/sike_r1/fips202_r1.h +1 -1
- data/aws-crt-ffi/crt/s2n/pq-crypto/sike_r3/sikep434r3_fp_x64_asm.S +4 -0
- data/aws-crt-ffi/crt/s2n/s2n.mk +25 -0
- data/aws-crt-ffi/crt/s2n/scripts/s2n_safety_macros.py +14 -0
- data/aws-crt-ffi/crt/s2n/tests/benchmark/Readme.md +23 -9
- data/aws-crt-ffi/crt/s2n/tests/features/clone.c +24 -0
- data/aws-crt-ffi/crt/s2n/tests/features/madvise.c +27 -0
- data/aws-crt-ffi/crt/s2n/tests/features/minherit.c +22 -0
- data/aws-crt-ffi/crt/s2n/tests/integrationv2/conftest.py +2 -2
- data/aws-crt-ffi/crt/s2n/tests/unit/s2n_connection_test.c +1 -1
- data/aws-crt-ffi/crt/s2n/tests/unit/s2n_fork_generation_number_test.c +335 -0
- data/aws-crt-ffi/crt/s2n/tests/unit/s2n_mem_usage_test.c +1 -1
- data/aws-crt-ffi/crt/s2n/tests/unit/s2n_self_talk_client_hello_cb_test.c +93 -11
- data/aws-crt-ffi/crt/s2n/tests/unit/s2n_server_hello_retry_test.c +123 -1
- data/aws-crt-ffi/crt/s2n/tests/unit/s2n_tls13_key_schedule_rfc8448_test.c +18 -3
- data/aws-crt-ffi/crt/s2n/tests/unit/s2n_tls13_key_schedule_test.c +0 -38
- data/aws-crt-ffi/crt/s2n/tests/unit/s2n_tls13_secrets_test.c +134 -15
- data/aws-crt-ffi/crt/s2n/tls/s2n_cipher_suites.c +1 -1
- data/aws-crt-ffi/crt/s2n/tls/s2n_client_hello.c +20 -9
- data/aws-crt-ffi/crt/s2n/tls/s2n_client_hello.h +8 -0
- data/aws-crt-ffi/crt/s2n/tls/s2n_config.c +13 -0
- data/aws-crt-ffi/crt/s2n/tls/s2n_config.h +6 -0
- data/aws-crt-ffi/crt/s2n/tls/s2n_handshake_io.c +2 -1
- data/aws-crt-ffi/crt/s2n/tls/s2n_internal.h +9 -0
- data/aws-crt-ffi/crt/s2n/tls/s2n_tls13_key_schedule.c +7 -7
- data/aws-crt-ffi/crt/s2n/tls/s2n_tls13_secrets.c +61 -8
- data/aws-crt-ffi/crt/s2n/tls/s2n_tls13_secrets.h +11 -5
- data/aws-crt-ffi/crt/s2n/utils/s2n_fork_detection.c +367 -0
- data/aws-crt-ffi/crt/s2n/utils/s2n_fork_detection.h +28 -0
- data/aws-crt-ffi/crt/s2n/utils/s2n_safety_macros.h +13 -22
- metadata +18 -3
@@ -0,0 +1,335 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License").
|
5
|
+
* You may not use this file except in compliance with the License.
|
6
|
+
* A copy of the License is located at
|
7
|
+
*
|
8
|
+
* http://aws.amazon.com/apache2.0
|
9
|
+
*
|
10
|
+
* or in the "license" file accompanying this file. This file is distributed
|
11
|
+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
12
|
+
* express or implied. See the License for the specific language governing
|
13
|
+
* permissions and limitations under the License.
|
14
|
+
*/
|
15
|
+
|
16
|
+
/* For clone() */
|
17
|
+
#define _GNU_SOURCE
|
18
|
+
|
19
|
+
#include "s2n_test.h"
|
20
|
+
#include "utils/s2n_fork_detection.h"
|
21
|
+
|
22
|
+
#include <pthread.h>
|
23
|
+
#include <sched.h>
|
24
|
+
#include <stdio.h>
|
25
|
+
#include <sys/wait.h>
|
26
|
+
|
27
|
+
#define NUMBER_OF_FGN_TEST_CASES 4
|
28
|
+
#define MAX_NUMBER_OF_TEST_THREADS 2
|
29
|
+
#define FORK_LEVEL_FOR_TESTS 2
|
30
|
+
/* Before calling s2n_get_fork_generation_number() set the argument to this
|
31
|
+
* value to avoid any unlucky collisions
|
32
|
+
*/
|
33
|
+
#define UNEXPECTED_RETURNED_FGN 0xFF
|
34
|
+
|
35
|
+
#define CLONE_TEST_NO 0
|
36
|
+
#define CLONE_TEST_YES 1
|
37
|
+
#define CLONE_TEST_DETERMINE_AT_RUNTIME 2
|
38
|
+
|
39
|
+
struct fgn_test_case {
|
40
|
+
const char *test_case_label;
|
41
|
+
int (*test_case_cb)(struct fgn_test_case *test_case);
|
42
|
+
int test_case_must_pass_clone_test;
|
43
|
+
};
|
44
|
+
|
45
|
+
static void s2n_verify_child_exit_status(pid_t proc_pid)
|
46
|
+
{
|
47
|
+
int status = 0;
|
48
|
+
EXPECT_EQUAL(waitpid(proc_pid, &status, __WALL), proc_pid);
|
49
|
+
|
50
|
+
/* Check that child exited with EXIT_SUCCESS. If not, this indicates
|
51
|
+
* that an error was encountered in the unit tests executed in that
|
52
|
+
* child process.
|
53
|
+
*/
|
54
|
+
EXPECT_NOT_EQUAL(WIFEXITED(status), 0);
|
55
|
+
EXPECT_EQUAL(WEXITSTATUS(status), EXIT_SUCCESS);
|
56
|
+
}
|
57
|
+
|
58
|
+
static void * s2n_unit_test_thread_get_fgn(void *expected_fork_generation_number)
|
59
|
+
{
|
60
|
+
uint64_t return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
61
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
62
|
+
EXPECT_EQUAL(return_fork_generation_number, *(uint64_t *) expected_fork_generation_number);
|
63
|
+
|
64
|
+
return NULL;
|
65
|
+
}
|
66
|
+
|
67
|
+
static int s2n_unit_test_thread(uint64_t expected_fork_generation_number)
|
68
|
+
{
|
69
|
+
pthread_t threads[MAX_NUMBER_OF_TEST_THREADS];
|
70
|
+
|
71
|
+
for (size_t thread_index = 0; thread_index < MAX_NUMBER_OF_TEST_THREADS; thread_index++) {
|
72
|
+
EXPECT_EQUAL(pthread_create(&threads[thread_index], NULL, &s2n_unit_test_thread_get_fgn, (void *) &expected_fork_generation_number), 0);
|
73
|
+
}
|
74
|
+
|
75
|
+
/* Wait for all threads to finish */
|
76
|
+
for (size_t thread_index = 0; thread_index < MAX_NUMBER_OF_TEST_THREADS; thread_index++) {
|
77
|
+
pthread_join(threads[thread_index], NULL);
|
78
|
+
}
|
79
|
+
|
80
|
+
return S2N_SUCCESS;
|
81
|
+
}
|
82
|
+
|
83
|
+
static int s2n_unit_test_fork(uint64_t parent_process_fgn, int fork_level)
|
84
|
+
{
|
85
|
+
pid_t proc_pid = fork();
|
86
|
+
EXPECT_TRUE(proc_pid >= 0);
|
87
|
+
|
88
|
+
fork_level = fork_level - 1;
|
89
|
+
|
90
|
+
if (proc_pid == 0) {
|
91
|
+
/* In child */
|
92
|
+
uint64_t return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
93
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
94
|
+
EXPECT_EQUAL(return_fork_generation_number, parent_process_fgn + 1);
|
95
|
+
|
96
|
+
/* Verify stability */
|
97
|
+
return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
98
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
99
|
+
EXPECT_EQUAL(return_fork_generation_number, parent_process_fgn + 1);
|
100
|
+
|
101
|
+
/* Verify in threads */
|
102
|
+
EXPECT_EQUAL(s2n_unit_test_thread(return_fork_generation_number), S2N_SUCCESS);
|
103
|
+
|
104
|
+
if (fork_level > 0) {
|
105
|
+
/* Fork again and verify fork generation number */
|
106
|
+
EXPECT_EQUAL(s2n_unit_test_fork(parent_process_fgn + 1, fork_level), S2N_SUCCESS);
|
107
|
+
}
|
108
|
+
|
109
|
+
/* Exit code EXIT_SUCCESS means that tests in this process finished
|
110
|
+
* successfully. Any errors would have exited the process with an
|
111
|
+
* exit code != EXIT_SUCCESS. We verify this in the parent process.
|
112
|
+
*/
|
113
|
+
exit(EXIT_SUCCESS);
|
114
|
+
}
|
115
|
+
else {
|
116
|
+
s2n_verify_child_exit_status(proc_pid);
|
117
|
+
|
118
|
+
/* Verify stability */
|
119
|
+
uint64_t return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
120
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
121
|
+
EXPECT_EQUAL(return_fork_generation_number, parent_process_fgn);
|
122
|
+
}
|
123
|
+
|
124
|
+
return S2N_SUCCESS;
|
125
|
+
}
|
126
|
+
|
127
|
+
/* Similar test to unit_test_fork() but verify in threads first */
|
128
|
+
static int s2n_unit_test_fork_check_threads_first(uint64_t parent_process_fgn)
|
129
|
+
{
|
130
|
+
pid_t proc_pid = fork();
|
131
|
+
EXPECT_TRUE(proc_pid >= 0);
|
132
|
+
|
133
|
+
if (proc_pid == 0) {
|
134
|
+
/* In child. Verify threads first. */
|
135
|
+
EXPECT_EQUAL(s2n_unit_test_thread(parent_process_fgn + 1), S2N_SUCCESS);
|
136
|
+
|
137
|
+
/* Then in the thread spawned when forking */
|
138
|
+
uint64_t return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
139
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
140
|
+
EXPECT_EQUAL(return_fork_generation_number, parent_process_fgn + 1);
|
141
|
+
|
142
|
+
/* Verify stability */
|
143
|
+
return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
144
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
145
|
+
EXPECT_EQUAL(return_fork_generation_number, parent_process_fgn + 1);
|
146
|
+
|
147
|
+
/* Exit code EXIT_SUCCESS means that tests in this process finished
|
148
|
+
* successfully. Any errors would have exited the process with an
|
149
|
+
* exit code != EXIT_SUCCESS. We verify this in the parent process.
|
150
|
+
*/
|
151
|
+
exit(EXIT_SUCCESS);
|
152
|
+
}
|
153
|
+
else {
|
154
|
+
s2n_verify_child_exit_status(proc_pid);
|
155
|
+
|
156
|
+
/* Verify stability */
|
157
|
+
uint64_t return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
158
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
159
|
+
EXPECT_EQUAL(return_fork_generation_number, parent_process_fgn);
|
160
|
+
}
|
161
|
+
|
162
|
+
return S2N_SUCCESS;
|
163
|
+
}
|
164
|
+
|
165
|
+
static int s2n_unit_test_clone_child_process(void *parent_process_fgn)
|
166
|
+
{
|
167
|
+
/* In child */
|
168
|
+
uint64_t local_parent_process_fgn = *(uint64_t *) parent_process_fgn;
|
169
|
+
uint64_t return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
170
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
171
|
+
EXPECT_EQUAL(return_fork_generation_number, local_parent_process_fgn + 1);
|
172
|
+
|
173
|
+
/* Verify stability */
|
174
|
+
return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
175
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
176
|
+
EXPECT_EQUAL(return_fork_generation_number, local_parent_process_fgn + 1);
|
177
|
+
|
178
|
+
/* Verify in threads */
|
179
|
+
EXPECT_EQUAL(s2n_unit_test_thread(return_fork_generation_number), S2N_SUCCESS);
|
180
|
+
|
181
|
+
/* This translates to the exit code for this child process */
|
182
|
+
return EXIT_SUCCESS;
|
183
|
+
}
|
184
|
+
|
185
|
+
#define PROCESS_CHILD_STACK_SIZE (1024 * 1024) /* Suggested by clone() man page... */
|
186
|
+
static int s2n_unit_test_clone(uint64_t parent_process_fgn)
|
187
|
+
{
|
188
|
+
#if defined(S2N_CLONE_SUPPORTED)
|
189
|
+
/* Verify stability */
|
190
|
+
uint64_t return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
191
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
192
|
+
EXPECT_EQUAL(return_fork_generation_number, parent_process_fgn);
|
193
|
+
|
194
|
+
/* Use stack memory for this... We don't exit unit_test_clone() before this
|
195
|
+
* memory has served its purpose.
|
196
|
+
* Why? Using dynamically allocated memory causes Valgrind to squat on the
|
197
|
+
* allocated memory when the child process exists.
|
198
|
+
*/
|
199
|
+
char process_child_stack[PROCESS_CHILD_STACK_SIZE];
|
200
|
+
EXPECT_NOT_NULL(process_child_stack);
|
201
|
+
|
202
|
+
int proc_pid = clone(s2n_unit_test_clone_child_process, (void *) (process_child_stack + PROCESS_CHILD_STACK_SIZE), 0, (void *) &return_fork_generation_number);
|
203
|
+
EXPECT_NOT_EQUAL(proc_pid, -1);
|
204
|
+
|
205
|
+
s2n_verify_child_exit_status(proc_pid);
|
206
|
+
|
207
|
+
/* Verify stability */
|
208
|
+
return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
209
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
210
|
+
EXPECT_EQUAL(return_fork_generation_number, parent_process_fgn);
|
211
|
+
#endif
|
212
|
+
|
213
|
+
return S2N_SUCCESS;
|
214
|
+
}
|
215
|
+
|
216
|
+
static int s2n_unit_tests_common(struct fgn_test_case *test_case)
|
217
|
+
{
|
218
|
+
uint64_t return_fork_generation_number = 0;
|
219
|
+
|
220
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
221
|
+
EXPECT_EQUAL(return_fork_generation_number, 0);
|
222
|
+
|
223
|
+
/* Should be idempotent if no fork event occurred */
|
224
|
+
return_fork_generation_number = UNEXPECTED_RETURNED_FGN;
|
225
|
+
EXPECT_OK(s2n_get_fork_generation_number(&return_fork_generation_number));
|
226
|
+
EXPECT_EQUAL(return_fork_generation_number, 0);
|
227
|
+
|
228
|
+
/* Should be idempotent in threaded environment as well */
|
229
|
+
EXPECT_EQUAL(s2n_unit_test_thread(return_fork_generation_number), S2N_SUCCESS);
|
230
|
+
|
231
|
+
/* Cached FGN should increment if a fork event occurs */
|
232
|
+
EXPECT_EQUAL(s2n_unit_test_fork(return_fork_generation_number, FORK_LEVEL_FOR_TESTS), S2N_SUCCESS);
|
233
|
+
EXPECT_EQUAL(s2n_unit_test_fork_check_threads_first(return_fork_generation_number), S2N_SUCCESS);
|
234
|
+
|
235
|
+
/* Some fork detection mechanisms can also detect forks through clone() */
|
236
|
+
if (test_case->test_case_must_pass_clone_test == CLONE_TEST_YES) {
|
237
|
+
EXPECT_EQUAL((s2n_is_madv_wipeonfork_supported() == true) || (s2n_is_map_inherit_zero_supported() == true), true);
|
238
|
+
EXPECT_EQUAL(s2n_unit_test_clone(return_fork_generation_number), S2N_SUCCESS);
|
239
|
+
}
|
240
|
+
else if (test_case->test_case_must_pass_clone_test == CLONE_TEST_DETERMINE_AT_RUNTIME) {
|
241
|
+
if ((s2n_is_madv_wipeonfork_supported() == true) ||
|
242
|
+
(s2n_is_map_inherit_zero_supported() == true)) {
|
243
|
+
EXPECT_EQUAL(s2n_unit_test_clone(return_fork_generation_number), S2N_SUCCESS);
|
244
|
+
}
|
245
|
+
}
|
246
|
+
|
247
|
+
return S2N_SUCCESS;
|
248
|
+
}
|
249
|
+
|
250
|
+
static int s2n_test_case_default_cb(struct fgn_test_case *test_case)
|
251
|
+
{
|
252
|
+
EXPECT_EQUAL(s2n_unit_tests_common(test_case), S2N_SUCCESS);
|
253
|
+
|
254
|
+
return S2N_SUCCESS;
|
255
|
+
}
|
256
|
+
|
257
|
+
static int s2n_test_case_pthread_atfork_cb(struct fgn_test_case *test_case)
|
258
|
+
{
|
259
|
+
POSIX_GUARD_RESULT(s2n_ignore_wipeonfork_and_inherit_zero_for_testing());
|
260
|
+
EXPECT_EQUAL(s2n_unit_tests_common(test_case), S2N_SUCCESS);
|
261
|
+
|
262
|
+
return S2N_SUCCESS;
|
263
|
+
}
|
264
|
+
|
265
|
+
static int s2n_test_case_madv_wipeonfork_cb(struct fgn_test_case *test_case)
|
266
|
+
{
|
267
|
+
if (s2n_is_madv_wipeonfork_supported() == false) {
|
268
|
+
TEST_DEBUG_PRINT("s2n_fork_generation_number_test.c test case not supported. Skipping.\nTest case: %s\n", test_case->test_case_label);
|
269
|
+
return S2N_SUCCESS;
|
270
|
+
}
|
271
|
+
|
272
|
+
POSIX_GUARD_RESULT(s2n_ignore_pthread_atfork_for_testing());
|
273
|
+
EXPECT_EQUAL(s2n_unit_tests_common(test_case), S2N_SUCCESS);
|
274
|
+
|
275
|
+
return S2N_SUCCESS;
|
276
|
+
}
|
277
|
+
|
278
|
+
static int s2n_test_case_map_inherit_zero_cb(struct fgn_test_case *test_case)
|
279
|
+
{
|
280
|
+
if (s2n_is_map_inherit_zero_supported() == false) {
|
281
|
+
TEST_DEBUG_PRINT("s2n_fork_generation_number_test.c test case not supported. Skipping.\nTest case: %s\n", test_case->test_case_label);
|
282
|
+
return S2N_SUCCESS;
|
283
|
+
}
|
284
|
+
|
285
|
+
POSIX_GUARD_RESULT(s2n_ignore_pthread_atfork_for_testing());
|
286
|
+
EXPECT_EQUAL(s2n_unit_tests_common(test_case), S2N_SUCCESS);
|
287
|
+
|
288
|
+
return S2N_SUCCESS;
|
289
|
+
}
|
290
|
+
|
291
|
+
struct fgn_test_case fgn_test_cases[NUMBER_OF_FGN_TEST_CASES] = {
|
292
|
+
{"Default fork detect mechanisms.", s2n_test_case_default_cb, CLONE_TEST_DETERMINE_AT_RUNTIME},
|
293
|
+
{"Only pthread_atfork fork detection mechanism.", s2n_test_case_pthread_atfork_cb, CLONE_TEST_NO},
|
294
|
+
{"Only madv_wipeonfork fork detection mechanism.", s2n_test_case_madv_wipeonfork_cb, CLONE_TEST_YES},
|
295
|
+
{"Only map_inheret_zero fork detection mechanism.", s2n_test_case_map_inherit_zero_cb, CLONE_TEST_YES}
|
296
|
+
};
|
297
|
+
|
298
|
+
int main(int argc, char **argv)
|
299
|
+
{
|
300
|
+
BEGIN_TEST();
|
301
|
+
|
302
|
+
EXPECT_TRUE(s2n_array_len(fgn_test_cases) == NUMBER_OF_FGN_TEST_CASES);
|
303
|
+
|
304
|
+
/* Create NUMBER_OF_FGN_TEST_CASES number of child processes that run each
|
305
|
+
* test case.
|
306
|
+
*
|
307
|
+
* Fork detection is lazily initialised on first invocation of
|
308
|
+
* s2n_get_fork_generation_number(). Hence, it is important that childs are
|
309
|
+
* created before calling into the fork detection code.
|
310
|
+
*/
|
311
|
+
pid_t proc_pids[NUMBER_OF_FGN_TEST_CASES] = {0};
|
312
|
+
|
313
|
+
for (size_t i = 0; i < NUMBER_OF_FGN_TEST_CASES; i++) {
|
314
|
+
|
315
|
+
proc_pids[i] = fork();
|
316
|
+
EXPECT_TRUE(proc_pids[i] >= 0);
|
317
|
+
|
318
|
+
if (proc_pids[i] == 0) {
|
319
|
+
/* In child */
|
320
|
+
EXPECT_EQUAL(fgn_test_cases[i].test_case_cb(&fgn_test_cases[i]), S2N_SUCCESS);
|
321
|
+
|
322
|
+
/* Exit code EXIT_SUCCESS means that tests in this process finished
|
323
|
+
* successfully. Any errors would have exited the process with an
|
324
|
+
* exit code != EXIT_SUCCESS. We verify this in the parent process.
|
325
|
+
* Also prevents child from creating more childs.
|
326
|
+
*/
|
327
|
+
exit(EXIT_SUCCESS);
|
328
|
+
}
|
329
|
+
else {
|
330
|
+
s2n_verify_child_exit_status(proc_pids[i]);
|
331
|
+
}
|
332
|
+
}
|
333
|
+
|
334
|
+
END_TEST();
|
335
|
+
}
|
@@ -24,6 +24,7 @@
|
|
24
24
|
|
25
25
|
#include "api/s2n.h"
|
26
26
|
#include "tls/s2n_connection.h"
|
27
|
+
#include "tls/s2n_internal.h"
|
27
28
|
|
28
29
|
struct client_hello_context {
|
29
30
|
int invoked;
|
@@ -38,6 +39,7 @@ struct client_hello_context {
|
|
38
39
|
* this flag tests the previous behavior from blocking callbacks
|
39
40
|
*/
|
40
41
|
int legacy_rc_for_server_name_used;
|
42
|
+
bool mark_done;
|
41
43
|
};
|
42
44
|
|
43
45
|
int mock_client(struct s2n_test_io_pair *io_pair, int expect_failure, int expect_server_name_used)
|
@@ -181,9 +183,27 @@ int client_hello_fail_handshake(struct s2n_connection *conn, void *ctx)
|
|
181
183
|
/* Return negative value to terminate the handshake */
|
182
184
|
return -1;
|
183
185
|
|
184
|
-
}
|
186
|
+
}
|
187
|
+
|
188
|
+
int s2n_client_hello_poll_cb(struct s2n_connection *conn, void *ctx)
|
189
|
+
{
|
190
|
+
struct client_hello_context *client_hello_ctx;
|
191
|
+
if (ctx == NULL) {
|
192
|
+
return -1;
|
193
|
+
}
|
194
|
+
client_hello_ctx = ctx;
|
195
|
+
/* Increment counter to ensure that callback was invoked */
|
196
|
+
client_hello_ctx->invoked++;
|
197
|
+
|
198
|
+
if (client_hello_ctx->mark_done) {
|
199
|
+
EXPECT_SUCCESS(s2n_client_hello_cb_done(conn));
|
200
|
+
return S2N_SUCCESS;
|
201
|
+
}
|
202
|
+
|
203
|
+
return S2N_SUCCESS;
|
204
|
+
}
|
185
205
|
|
186
|
-
int s2n_negotiate_nonblocking_ch_cb(struct s2n_connection *conn,
|
206
|
+
int s2n_negotiate_nonblocking_ch_cb(struct s2n_connection *conn,
|
187
207
|
struct client_hello_context *ch_ctx, bool server_name_used)
|
188
208
|
{
|
189
209
|
s2n_blocked_status blocked;
|
@@ -191,7 +211,7 @@ int s2n_negotiate_nonblocking_ch_cb(struct s2n_connection *conn,
|
|
191
211
|
/* negotiate handshake, we should pause after the nonblocking callback is invoked */
|
192
212
|
EXPECT_FAILURE_WITH_ERRNO(s2n_negotiate(conn, &blocked), S2N_ERR_ASYNC_BLOCKED);
|
193
213
|
EXPECT_EQUAL(blocked, S2N_BLOCKED_ON_APPLICATION_INPUT);
|
194
|
-
|
214
|
+
|
195
215
|
/* verify client hello cb has been invoked */
|
196
216
|
EXPECT_EQUAL(ch_ctx->invoked, 1);
|
197
217
|
|
@@ -201,7 +221,7 @@ int s2n_negotiate_nonblocking_ch_cb(struct s2n_connection *conn,
|
|
201
221
|
}
|
202
222
|
/* unless explicitly unblocked we should stay paused */
|
203
223
|
EXPECT_FAILURE_WITH_ERRNO(s2n_negotiate(conn, &blocked), S2N_ERR_ASYNC_BLOCKED);
|
204
|
-
EXPECT_EQUAL(blocked, S2N_BLOCKED_ON_APPLICATION_INPUT);
|
224
|
+
EXPECT_EQUAL(blocked, S2N_BLOCKED_ON_APPLICATION_INPUT);
|
205
225
|
|
206
226
|
/* mark the client hello cb complete */
|
207
227
|
EXPECT_SUCCESS(s2n_client_hello_cb_done(conn));
|
@@ -211,11 +231,39 @@ int s2n_negotiate_nonblocking_ch_cb(struct s2n_connection *conn,
|
|
211
231
|
return s2n_negotiate(conn, &blocked);
|
212
232
|
}
|
213
233
|
|
234
|
+
int s2n_negotiate_nonblocking_poll(struct s2n_connection *conn,
|
235
|
+
struct client_hello_context *ch_ctx)
|
236
|
+
{
|
237
|
+
EXPECT_NOT_NULL(conn);
|
238
|
+
EXPECT_NOT_NULL(ch_ctx);
|
239
|
+
int invoked = 0;
|
240
|
+
s2n_blocked_status blocked = S2N_NOT_BLOCKED;
|
241
|
+
|
242
|
+
EXPECT_EQUAL(ch_ctx->invoked, 0);
|
243
|
+
|
244
|
+
do {
|
245
|
+
/* negotiate handshake, we should pause after the nonblocking callback is invoked */
|
246
|
+
EXPECT_FAILURE_WITH_ERRNO(s2n_negotiate(conn, &blocked), S2N_ERR_ASYNC_BLOCKED);
|
247
|
+
EXPECT_EQUAL(blocked, S2N_BLOCKED_ON_APPLICATION_INPUT);
|
248
|
+
invoked++;
|
249
|
+
EXPECT_EQUAL(ch_ctx->invoked, invoked);
|
250
|
+
} while(invoked < 10);
|
251
|
+
EXPECT_EQUAL(ch_ctx->invoked, invoked);
|
252
|
+
|
253
|
+
ch_ctx->mark_done = true;
|
254
|
+
|
255
|
+
/* Expect the callback to complete after 2nd iteration */
|
256
|
+
EXPECT_SUCCESS(s2n_negotiate(conn, &blocked));
|
257
|
+
EXPECT_EQUAL(ch_ctx->invoked, invoked + 1);
|
258
|
+
|
259
|
+
return S2N_SUCCESS;
|
260
|
+
}
|
261
|
+
|
214
262
|
int s2n_negotiate_blocking_ch_cb(struct s2n_connection *conn, struct client_hello_context *ch_ctx)
|
215
263
|
{
|
216
264
|
s2n_blocked_status blocked;
|
217
265
|
EXPECT_NOT_NULL(conn);
|
218
|
-
|
266
|
+
|
219
267
|
int rc = s2n_negotiate(conn, &blocked);
|
220
268
|
/* verify client hello cb has been invoked */
|
221
269
|
EXPECT_EQUAL(ch_ctx->invoked, 1);
|
@@ -329,7 +377,7 @@ int run_test_config_swap_ch_cb(s2n_client_hello_cb_mode cb_mode,
|
|
329
377
|
|
330
378
|
EXPECT_SUCCESS(start_client_conn(&io_pair, &pid, 0 , 1));
|
331
379
|
EXPECT_SUCCESS(init_server_conn(&conn, &io_pair, config));
|
332
|
-
|
380
|
+
|
333
381
|
/* do the handshake */
|
334
382
|
if ( cb_mode == S2N_CLIENT_HELLO_CB_NONBLOCKING && !ch_ctx->mark_done_during_callback) {
|
335
383
|
/* swap the config and mark server_name_used in the async context */
|
@@ -340,7 +388,7 @@ int run_test_config_swap_ch_cb(s2n_client_hello_cb_mode cb_mode,
|
|
340
388
|
*/
|
341
389
|
EXPECT_SUCCESS(s2n_negotiate_blocking_ch_cb(conn, ch_ctx));
|
342
390
|
}
|
343
|
-
|
391
|
+
|
344
392
|
/* Server name and error are as expected with null connection */
|
345
393
|
EXPECT_NULL(s2n_get_server_name(NULL));
|
346
394
|
EXPECT_EQUAL(s2n_errno, S2N_ERR_NULL);
|
@@ -349,7 +397,7 @@ int run_test_config_swap_ch_cb(s2n_client_hello_cb_mode cb_mode,
|
|
349
397
|
EXPECT_STRING_EQUAL(s2n_get_application_protocol(conn), protocols[0]);
|
350
398
|
|
351
399
|
EXPECT_SUCCESS(server_recv(conn));
|
352
|
-
|
400
|
+
|
353
401
|
EXPECT_SUCCESS(test_case_clean(conn, pid, config, &io_pair, ch_ctx));
|
354
402
|
EXPECT_SUCCESS(s2n_config_free(swap_config));
|
355
403
|
return S2N_SUCCESS;
|
@@ -372,7 +420,7 @@ int run_test_no_config_swap_ch_cb(s2n_client_hello_cb_mode cb_mode,
|
|
372
420
|
EXPECT_SUCCESS(s2n_config_set_client_hello_cb_mode(config, cb_mode));
|
373
421
|
EXPECT_SUCCESS(start_client_conn(&io_pair, &pid, 0 , 0));
|
374
422
|
EXPECT_SUCCESS(init_server_conn(&conn, &io_pair, config));
|
375
|
-
|
423
|
+
|
376
424
|
/* do the handshake */
|
377
425
|
if ( cb_mode == S2N_CLIENT_HELLO_CB_NONBLOCKING ) {
|
378
426
|
/* swap the config and mark server_name_used in the async context */
|
@@ -387,7 +435,7 @@ int run_test_no_config_swap_ch_cb(s2n_client_hello_cb_mode cb_mode,
|
|
387
435
|
EXPECT_EQUAL(s2n_errno, S2N_ERR_NULL);
|
388
436
|
|
389
437
|
EXPECT_SUCCESS(server_recv(conn));
|
390
|
-
|
438
|
+
|
391
439
|
EXPECT_SUCCESS(test_case_clean(conn, pid, config, &io_pair, ch_ctx));
|
392
440
|
return S2N_SUCCESS;
|
393
441
|
}
|
@@ -425,7 +473,7 @@ int run_test_reject_handshake_ch_cb(s2n_client_hello_cb_mode cb_mode,
|
|
425
473
|
|
426
474
|
/* Ensure that callback was invoked */
|
427
475
|
EXPECT_EQUAL(ch_ctx->invoked, 1);
|
428
|
-
|
476
|
+
|
429
477
|
/* shutdown to flush alert, expext failure as client doesn't send close notify */
|
430
478
|
EXPECT_FAILURE(s2n_shutdown(conn, &blocked));
|
431
479
|
EXPECT_SUCCESS(s2n_connection_free(conn));
|
@@ -434,6 +482,37 @@ int run_test_reject_handshake_ch_cb(s2n_client_hello_cb_mode cb_mode,
|
|
434
482
|
return S2N_SUCCESS;
|
435
483
|
}
|
436
484
|
|
485
|
+
int run_test_poll_ch_cb(s2n_client_hello_cb_mode cb_mode,
|
486
|
+
struct s2n_cert_chain_and_key *chain_and_key,
|
487
|
+
struct client_hello_context *ch_ctx)
|
488
|
+
{
|
489
|
+
struct s2n_test_io_pair io_pair = { 0 };
|
490
|
+
struct s2n_config *config = s2n_config_new();
|
491
|
+
EXPECT_NOT_NULL(config);
|
492
|
+
struct s2n_connection *conn;
|
493
|
+
pid_t pid = 0;
|
494
|
+
|
495
|
+
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key));
|
496
|
+
|
497
|
+
/* Setup ClientHello callback */
|
498
|
+
EXPECT_SUCCESS(s2n_config_set_client_hello_cb(config, s2n_client_hello_poll_cb, ch_ctx));
|
499
|
+
EXPECT_SUCCESS(s2n_config_set_client_hello_cb_mode(config, cb_mode));
|
500
|
+
|
501
|
+
/* Enable callback polling mode */
|
502
|
+
EXPECT_SUCCESS(s2n_config_client_hello_cb_enable_poll(config));
|
503
|
+
|
504
|
+
EXPECT_SUCCESS(start_client_conn(&io_pair, &pid, 0 , 0));
|
505
|
+
EXPECT_SUCCESS(init_server_conn(&conn, &io_pair, config));
|
506
|
+
|
507
|
+
/* negotiate and make assertions */
|
508
|
+
EXPECT_SUCCESS(s2n_negotiate_nonblocking_poll(conn, ch_ctx));
|
509
|
+
|
510
|
+
EXPECT_SUCCESS(server_recv(conn));
|
511
|
+
|
512
|
+
EXPECT_SUCCESS(test_case_clean(conn, pid, config, &io_pair, ch_ctx));
|
513
|
+
return S2N_SUCCESS;
|
514
|
+
}
|
515
|
+
|
437
516
|
int main(int argc, char **argv)
|
438
517
|
{
|
439
518
|
struct client_hello_context client_hello_ctx = {0};
|
@@ -487,6 +566,9 @@ int main(int argc, char **argv)
|
|
487
566
|
EXPECT_SUCCESS(run_test_reject_handshake_ch_cb(S2N_CLIENT_HELLO_CB_NONBLOCKING,
|
488
567
|
chain_and_key, &client_hello_ctx));
|
489
568
|
|
569
|
+
EXPECT_SUCCESS(run_test_poll_ch_cb(S2N_CLIENT_HELLO_CB_NONBLOCKING,
|
570
|
+
chain_and_key, &client_hello_ctx));
|
571
|
+
|
490
572
|
EXPECT_SUCCESS(s2n_cert_chain_and_key_free(chain_and_key));
|
491
573
|
free(cert_chain_pem);
|
492
574
|
free(private_key_pem);
|