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 #include "s2n_test.h"
17
18 #include "testlib/s2n_testlib.h"
19
20 #include <sys/wait.h>
21 #include <unistd.h>
22 #include <stdint.h>
23 #include <fcntl.h>
24
25 #include <s2n.h>
26 #include <tls/s2n_connection.h>
27
28 struct client_hello_context {
29 int invoked;
30 int swap_config_during_callback;
31 int swap_config_nonblocking_mode;
32 int mark_done_during_callback;
33 struct s2n_config *config;
34 /* the right way to mark server name extenstion was used
35 * after parsing ClientHello is to call
36 * s2n_connection_server_name_extension_used
37 *
38 * this flag tests the previous behavior from blocking callbacks
39 */
40 int legacy_rc_for_server_name_used;
41 };
42
mock_client(struct s2n_test_io_pair * io_pair,int expect_failure,int expect_server_name_used)43 int mock_client(struct s2n_test_io_pair *io_pair, int expect_failure, int expect_server_name_used)
44 {
45 struct s2n_connection *conn;
46 struct s2n_config *config;
47 s2n_blocked_status blocked;
48 int result = 0;
49 int rc = 0;
50 const char *protocols[] = { "h2", "http/1.1" };
51
52 /* Give the server a chance to listen */
53 sleep(1);
54
55 conn = s2n_connection_new(S2N_CLIENT);
56 config = s2n_config_new();
57 s2n_config_set_protocol_preferences(config, protocols, 2);
58 s2n_config_disable_x509_verification(config);
59 s2n_connection_set_config(conn, config);
60
61 s2n_connection_set_io_pair(conn, io_pair);
62
63 s2n_set_server_name(conn, "example.com");
64
65 rc = s2n_negotiate(conn, &blocked);
66 if (expect_failure) {
67 if (!rc) {
68 result = 1;
69 }
70
71 if (s2n_connection_get_alert(conn) != 40){
72 result = 2;
73 }
74 } else {
75 char buffer[0xffff];
76
77 if (conn->server_name_used != expect_server_name_used) {
78 result = 1;
79 }
80
81 if (rc < 0) {
82 result = 2;
83 }
84
85 for (int i = 1; i < 0xffff; i += 100) {
86 memset(buffer, 33, sizeof(char) * i);
87 s2n_send(conn, buffer, i, &blocked);
88 }
89
90 int shutdown_rc= -1;
91 do {
92 shutdown_rc = s2n_shutdown(conn, &blocked);
93 } while(shutdown_rc != 0);
94 }
95
96 s2n_connection_free(conn);
97 s2n_config_free(config);
98
99 /* Give the server a chance to a void a sigpipe */
100 sleep(1);
101
102 s2n_cleanup();
103 s2n_io_pair_close_one_end(io_pair, S2N_CLIENT);
104
105 _exit(result);
106 }
107
client_hello_swap_config(struct s2n_connection * conn,void * ctx)108 int client_hello_swap_config(struct s2n_connection *conn, void *ctx)
109 {
110 struct client_hello_context *client_hello_ctx;
111 struct s2n_client_hello *client_hello = s2n_connection_get_client_hello(conn);
112 const char *sent_server_name = "example.com";
113 const char *received_server_name;
114 if (ctx == NULL) {
115 return -1;
116 }
117 client_hello_ctx = ctx;
118 /* Increment counter to ensure that callback was invoked */
119 client_hello_ctx->invoked++;
120
121 /* Validate SNI extension */
122 uint8_t expected_server_name[] = {
123 /* Server names len */
124 0x00, 0x0E,
125 /* Server name type - host name */
126 0x00,
127 /* First server name len */
128 0x00, 0x0B,
129 /* First server name, matches sent_server_name */
130 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm'};
131
132 /* Get SNI extension from client hello */
133 uint32_t len = s2n_client_hello_get_extension_length(client_hello, S2N_EXTENSION_SERVER_NAME);
134 if (len != 16) {
135 return -1;
136 }
137
138 uint8_t ser_name[16] = {0};
139 if (s2n_client_hello_get_extension_by_id(client_hello, S2N_EXTENSION_SERVER_NAME, ser_name, len) <= 0) {
140 return -1;
141 }
142
143 /* Verify correct server name is returned. */
144 received_server_name = s2n_get_server_name(conn);
145 if (received_server_name == NULL || strcmp(received_server_name, sent_server_name)) {
146 return -1;
147 }
148
149 if (memcmp(ser_name, expected_server_name, len) != 0) {
150 return -1;
151 }
152
153 if (client_hello_ctx->mark_done_during_callback) {
154 EXPECT_SUCCESS(s2n_client_hello_cb_done(conn));
155 }
156
157 if (client_hello_ctx->swap_config_during_callback) {
158 EXPECT_SUCCESS(s2n_connection_set_config(conn, client_hello_ctx->config));
159 if (client_hello_ctx->legacy_rc_for_server_name_used) {
160 return 1;
161 }
162 EXPECT_SUCCESS(s2n_connection_server_name_extension_used(conn));
163 return 0;
164 }
165
166 return 0;
167 }
168
client_hello_fail_handshake(struct s2n_connection * conn,void * ctx)169 int client_hello_fail_handshake(struct s2n_connection *conn, void *ctx)
170 {
171 struct client_hello_context *client_hello_ctx;
172
173 if (ctx == NULL) {
174 return -1;
175 }
176 client_hello_ctx = ctx;
177
178 /* Incremet counter to ensure that callback was invoked */
179 client_hello_ctx->invoked++;
180
181 /* Return negative value to terminate the handshake */
182 return -1;
183
184 }
185
s2n_negotiate_nonblocking_ch_cb(struct s2n_connection * conn,struct client_hello_context * ch_ctx,bool server_name_used)186 int s2n_negotiate_nonblocking_ch_cb(struct s2n_connection *conn,
187 struct client_hello_context *ch_ctx, bool server_name_used)
188 {
189 s2n_blocked_status blocked;
190 EXPECT_NOT_NULL(conn);
191 /* negotiate handshake, we should pause after the nonblocking callback is invoked */
192 EXPECT_FAILURE_WITH_ERRNO(s2n_negotiate(conn, &blocked), S2N_ERR_ASYNC_BLOCKED);
193 EXPECT_EQUAL(blocked, S2N_BLOCKED_ON_APPLICATION_INPUT);
194
195 /* verify client hello cb has been invoked */
196 EXPECT_EQUAL(ch_ctx->invoked, 1);
197
198 /* while handshake is paused, swap the config if asked */
199 if (ch_ctx->swap_config_nonblocking_mode) {
200 EXPECT_SUCCESS(s2n_connection_set_config(conn, ch_ctx->config));
201 }
202 /* unless explicitly unblocked we should stay paused */
203 EXPECT_FAILURE_WITH_ERRNO(s2n_negotiate(conn, &blocked), S2N_ERR_ASYNC_BLOCKED);
204 EXPECT_EQUAL(blocked, S2N_BLOCKED_ON_APPLICATION_INPUT);
205
206 /* mark the client hello cb complete */
207 EXPECT_SUCCESS(s2n_client_hello_cb_done(conn));
208 if (server_name_used) {
209 EXPECT_SUCCESS(s2n_connection_server_name_extension_used(conn));
210 }
211 return s2n_negotiate(conn, &blocked);
212 }
213
s2n_negotiate_blocking_ch_cb(struct s2n_connection * conn,struct client_hello_context * ch_ctx)214 int s2n_negotiate_blocking_ch_cb(struct s2n_connection *conn, struct client_hello_context *ch_ctx)
215 {
216 s2n_blocked_status blocked;
217 EXPECT_NOT_NULL(conn);
218
219 int rc = s2n_negotiate(conn, &blocked);
220 /* verify client hello cb has been invoked */
221 EXPECT_EQUAL(ch_ctx->invoked, 1);
222 return rc;
223 }
224
server_recv(struct s2n_connection * conn)225 int server_recv(struct s2n_connection *conn)
226 {
227 static char buffer[0xffff];
228 s2n_blocked_status blocked;
229
230 for (int i = 1; i < 0xffff; i += 100) {
231 char * ptr = buffer;
232 int size = i;
233
234 do {
235 int bytes_read = 0;
236 EXPECT_SUCCESS(bytes_read = s2n_recv(conn, ptr, size, &blocked));
237
238 size -= bytes_read;
239 ptr += bytes_read;
240 } while(size);
241
242 for (int j = 0; j < i; j++) {
243 EXPECT_EQUAL((buffer)[j], 33);
244 }
245 }
246 return S2N_SUCCESS;
247 }
248
init_server_conn(struct s2n_connection ** conn,struct s2n_test_io_pair * io_pair,struct s2n_config * config)249 int init_server_conn(struct s2n_connection **conn, struct s2n_test_io_pair *io_pair,
250 struct s2n_config *config)
251 {
252 /* This is the server process, close the client end of the pipe */
253 EXPECT_SUCCESS(s2n_io_pair_close_one_end(io_pair, S2N_CLIENT));
254
255 EXPECT_NOT_NULL(*conn = s2n_connection_new(S2N_SERVER));
256
257 /* Set up the connection to read from the fd */
258 EXPECT_SUCCESS(s2n_connection_set_io_pair(*conn, io_pair));
259 EXPECT_SUCCESS(s2n_connection_set_config(*conn, config));
260 return S2N_SUCCESS;
261 }
262
start_client_conn(struct s2n_test_io_pair * io_pair,pid_t * pid,int expect_failure,int expect_server_name_used)263 int start_client_conn(struct s2n_test_io_pair *io_pair, pid_t *pid,
264 int expect_failure, int expect_server_name_used)
265 {
266 /* Create a pipe */
267 EXPECT_SUCCESS(s2n_io_pair_init(io_pair));
268
269 /* Create a child process */
270 *pid = fork();
271 if (*pid == 0) {
272 /* This is the client process, close the server end of the pipe */
273 EXPECT_SUCCESS(s2n_io_pair_close_one_end(io_pair, S2N_SERVER));
274
275 mock_client(io_pair, expect_failure, expect_server_name_used);
276 }
277 return S2N_SUCCESS;
278 }
279
test_case_clean(struct s2n_connection * conn,pid_t client_pid,struct s2n_config * config,struct s2n_test_io_pair * io_pair,struct client_hello_context * ch_ctx)280 static int test_case_clean(struct s2n_connection *conn, pid_t client_pid,
281 struct s2n_config *config, struct s2n_test_io_pair *io_pair,
282 struct client_hello_context *ch_ctx)
283 {
284 s2n_blocked_status blocked;
285 int status;
286
287 if (conn != NULL) {
288 EXPECT_SUCCESS(s2n_shutdown(conn, &blocked));
289 EXPECT_SUCCESS(s2n_connection_free(conn));
290 }
291 EXPECT_EQUAL(waitpid(-1, &status, 0), client_pid);
292 EXPECT_EQUAL(status, 0);
293 EXPECT_SUCCESS(s2n_config_free(config));
294 /* client process cleans their end, we just need to close server side */
295 EXPECT_SUCCESS(s2n_io_pair_close_one_end(io_pair, S2N_SERVER));
296 memset(ch_ctx, 0, sizeof(struct client_hello_context));
297 return S2N_SUCCESS;
298 }
299
run_test_config_swap_ch_cb(s2n_client_hello_cb_mode cb_mode,struct s2n_cert_chain_and_key * chain_and_key,struct client_hello_context * ch_ctx)300 int run_test_config_swap_ch_cb(s2n_client_hello_cb_mode cb_mode,
301 struct s2n_cert_chain_and_key *chain_and_key, struct client_hello_context *ch_ctx)
302 {
303
304 struct s2n_test_io_pair io_pair;
305 struct s2n_config *config;
306 struct s2n_connection *conn;
307 struct s2n_config *swap_config;
308 pid_t pid;
309
310 /* Add application protocols to swapped config */
311 static const char *protocols[] = { "h2" };
312
313 /* prepare swap_config */
314 EXPECT_NOT_NULL(swap_config = s2n_config_new());
315 EXPECT_SUCCESS(s2n_config_set_protocol_preferences(swap_config, protocols, 1));
316 EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(swap_config, chain_and_key));
317 ch_ctx->config = swap_config;
318 /* in the swap config make sure blocking more is SET correctly */
319 EXPECT_SUCCESS(s2n_config_set_client_hello_cb_mode(swap_config, cb_mode));
320
321 /* Don't set up certificate and private key for the main config, so if
322 * handshake succeeds we know that config was swapped */
323 EXPECT_NOT_NULL(config = s2n_config_new());
324
325
326 /* Set up the callback */
327 EXPECT_SUCCESS(s2n_config_set_client_hello_cb_mode(config, cb_mode));
328 EXPECT_SUCCESS(s2n_config_set_client_hello_cb(config, client_hello_swap_config, ch_ctx));
329
330 EXPECT_SUCCESS(start_client_conn(&io_pair, &pid, 0 , 1));
331 EXPECT_SUCCESS(init_server_conn(&conn, &io_pair, config));
332
333 /* do the handshake */
334 if ( cb_mode == S2N_CLIENT_HELLO_CB_NONBLOCKING && !ch_ctx->mark_done_during_callback) {
335 /* swap the config and mark server_name_used in the async context */
336 EXPECT_SUCCESS(s2n_negotiate_nonblocking_ch_cb(conn, ch_ctx, true));
337 }
338 else { /* cb_mode == S2N_CLIENT_HELLO_CB_BLOCKING or NONBLOCKING mode where
339 * a non blocking callback marks cb_done during the callback itself
340 */
341 EXPECT_SUCCESS(s2n_negotiate_blocking_ch_cb(conn, ch_ctx));
342 }
343
344 /* Server name and error are as expected with null connection */
345 EXPECT_NULL(s2n_get_server_name(NULL));
346 EXPECT_EQUAL(s2n_errno, S2N_ERR_NULL);
347
348 /* Expect most preferred negotiated protocol which only swap_config had */
349 EXPECT_STRING_EQUAL(s2n_get_application_protocol(conn), protocols[0]);
350
351 EXPECT_SUCCESS(server_recv(conn));
352
353 EXPECT_SUCCESS(test_case_clean(conn, pid, config, &io_pair, ch_ctx));
354 EXPECT_SUCCESS(s2n_config_free(swap_config));
355 return S2N_SUCCESS;
356 }
357
run_test_no_config_swap_ch_cb(s2n_client_hello_cb_mode cb_mode,struct s2n_cert_chain_and_key * chain_and_key,struct client_hello_context * ch_ctx)358 int run_test_no_config_swap_ch_cb(s2n_client_hello_cb_mode cb_mode,
359 struct s2n_cert_chain_and_key *chain_and_key,
360 struct client_hello_context *ch_ctx)
361 {
362 struct s2n_test_io_pair io_pair;
363 struct s2n_config *config;
364 struct s2n_connection *conn;
365 pid_t pid;
366
367 EXPECT_NOT_NULL(config = s2n_config_new());
368 EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key));
369
370 /* Setup ClientHello callback */
371 EXPECT_SUCCESS(s2n_config_set_client_hello_cb(config, client_hello_swap_config, ch_ctx));
372 EXPECT_SUCCESS(s2n_config_set_client_hello_cb_mode(config, cb_mode));
373 EXPECT_SUCCESS(start_client_conn(&io_pair, &pid, 0 , 0));
374 EXPECT_SUCCESS(init_server_conn(&conn, &io_pair, config));
375
376 /* do the handshake */
377 if ( cb_mode == S2N_CLIENT_HELLO_CB_NONBLOCKING ) {
378 /* swap the config and mark server_name_used in the async context */
379 EXPECT_SUCCESS(s2n_negotiate_nonblocking_ch_cb(conn, ch_ctx, false));
380 }
381 else { /* cb_mode == S2N_CLIENT_HELLO_CB_BLOCKING */
382 EXPECT_SUCCESS(s2n_negotiate_blocking_ch_cb(conn, ch_ctx));
383 }
384
385 /* Server name and error are as expected with null connection */
386 EXPECT_NULL(s2n_get_server_name(NULL));
387 EXPECT_EQUAL(s2n_errno, S2N_ERR_NULL);
388
389 EXPECT_SUCCESS(server_recv(conn));
390
391 EXPECT_SUCCESS(test_case_clean(conn, pid, config, &io_pair, ch_ctx));
392 return S2N_SUCCESS;
393 }
394
run_test_reject_handshake_ch_cb(s2n_client_hello_cb_mode cb_mode,struct s2n_cert_chain_and_key * chain_and_key,struct client_hello_context * ch_ctx)395 int run_test_reject_handshake_ch_cb(s2n_client_hello_cb_mode cb_mode,
396 struct s2n_cert_chain_and_key *chain_and_key,
397 struct client_hello_context *ch_ctx)
398 {
399 struct s2n_test_io_pair io_pair;
400 struct s2n_config *config;
401 struct s2n_connection *conn;
402 pid_t pid;
403 s2n_blocked_status blocked;
404
405 EXPECT_NOT_NULL(config = s2n_config_new());
406 EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key));
407
408 /* Setup ClientHello callback */
409 EXPECT_SUCCESS(s2n_config_set_client_hello_cb(config, client_hello_fail_handshake, ch_ctx));
410 EXPECT_SUCCESS(s2n_config_set_client_hello_cb_mode(config, cb_mode));
411
412 EXPECT_SUCCESS(start_client_conn(&io_pair, &pid, 1 , 0));
413
414 EXPECT_SUCCESS(init_server_conn(&conn, &io_pair, config));
415 /* If s2n_negotiate fails, it usually would delay with a sleep. In order to
416 * test that we don't blind when CLientHello callback fails the handshake,
417 * disable blinding here */
418 EXPECT_SUCCESS(s2n_connection_set_blinding(conn, S2N_SELF_SERVICE_BLINDING));
419
420 /* Negotiate the handshake. */
421 EXPECT_FAILURE_WITH_ERRNO(s2n_negotiate(conn, &blocked), S2N_ERR_CANCELLED);
422
423 /* Check that blinding was not invoked */
424 EXPECT_EQUAL(s2n_connection_get_delay(conn), 0);
425
426 /* Ensure that callback was invoked */
427 EXPECT_EQUAL(ch_ctx->invoked, 1);
428
429 /* shutdown to flush alert, expext failure as client doesn't send close notify */
430 EXPECT_FAILURE(s2n_shutdown(conn, &blocked));
431 EXPECT_SUCCESS(s2n_connection_free(conn));
432
433 EXPECT_SUCCESS(test_case_clean(NULL, pid, config, &io_pair, ch_ctx));
434 return S2N_SUCCESS;
435 }
436
main(int argc,char ** argv)437 int main(int argc, char **argv)
438 {
439 struct client_hello_context client_hello_ctx = {0};
440 char *cert_chain_pem;
441 char *private_key_pem;
442 struct s2n_cert_chain_and_key *chain_and_key;
443 BEGIN_TEST();
444
445 EXPECT_NOT_NULL(cert_chain_pem = malloc(S2N_MAX_TEST_PEM_SIZE));
446 EXPECT_NOT_NULL(private_key_pem = malloc(S2N_MAX_TEST_PEM_SIZE));
447 EXPECT_SUCCESS(s2n_read_test_pem(S2N_DEFAULT_TEST_CERT_CHAIN, cert_chain_pem, S2N_MAX_TEST_PEM_SIZE));
448 EXPECT_SUCCESS(s2n_read_test_pem(S2N_DEFAULT_TEST_PRIVATE_KEY, private_key_pem, S2N_MAX_TEST_PEM_SIZE));
449 EXPECT_NOT_NULL(chain_and_key = s2n_cert_chain_and_key_new());
450 EXPECT_SUCCESS(s2n_cert_chain_and_key_load_pem(chain_and_key, cert_chain_pem, private_key_pem));
451 /** Test config swapping in client hello callback **/
452
453 /* we want to update the config outside of callback so don't swap in callback */
454 client_hello_ctx.swap_config_nonblocking_mode = 1;
455 EXPECT_SUCCESS(run_test_config_swap_ch_cb(S2N_CLIENT_HELLO_CB_NONBLOCKING,
456 chain_and_key, &client_hello_ctx));
457
458 /* non blocking callback when callback marks cb_done during the callback */
459 client_hello_ctx.swap_config_during_callback = 1;
460 client_hello_ctx.mark_done_during_callback = 1;
461 EXPECT_SUCCESS(run_test_config_swap_ch_cb(S2N_CLIENT_HELLO_CB_NONBLOCKING,
462 chain_and_key, &client_hello_ctx));
463
464 /* we want to update the config in the callback */
465 client_hello_ctx.swap_config_during_callback = 1;
466 EXPECT_SUCCESS(run_test_config_swap_ch_cb(S2N_CLIENT_HELLO_CB_BLOCKING,
467 chain_and_key, &client_hello_ctx));
468
469 /* validate legacy behavior for server_name_used */
470 /* we want to update the config in the callback */
471 client_hello_ctx.swap_config_during_callback = 1;
472 client_hello_ctx.legacy_rc_for_server_name_used = 1;
473 EXPECT_SUCCESS(run_test_config_swap_ch_cb(S2N_CLIENT_HELLO_CB_BLOCKING,
474 chain_and_key, &client_hello_ctx));
475
476 /** Tests for test when server_name_used is not set **/
477 EXPECT_SUCCESS(run_test_no_config_swap_ch_cb(S2N_CLIENT_HELLO_CB_BLOCKING,
478 chain_and_key, &client_hello_ctx));
479
480 EXPECT_SUCCESS(run_test_no_config_swap_ch_cb(S2N_CLIENT_HELLO_CB_NONBLOCKING,
481 chain_and_key, &client_hello_ctx));
482
483 /** Test rejecting connection in client hello callback **/
484 EXPECT_SUCCESS(run_test_reject_handshake_ch_cb(S2N_CLIENT_HELLO_CB_BLOCKING,
485 chain_and_key, &client_hello_ctx));
486
487 EXPECT_SUCCESS(run_test_reject_handshake_ch_cb(S2N_CLIENT_HELLO_CB_NONBLOCKING,
488 chain_and_key, &client_hello_ctx));
489
490 EXPECT_SUCCESS(s2n_cert_chain_and_key_free(chain_and_key));
491 free(cert_chain_pem);
492 free(private_key_pem);
493
494 END_TEST();
495
496 return 0;
497 }
498