1 /* 2 * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 #include <openssl/ssl.h> 10 #include <openssl/quic.h> 11 #include <openssl/bio.h> 12 #include "internal/common.h" 13 #include "internal/sockets.h" 14 #include "internal/quic_tserver.h" 15 #include "internal/quic_thread_assist.h" 16 #include "internal/quic_ssl.h" 17 #include "internal/time.h" 18 #include "testutil.h" 19 20 static const char msg1[] = "The quick brown fox jumped over the lazy dogs."; 21 static char msg2[1024], msg3[1024]; 22 static OSSL_TIME fake_time; 23 static CRYPTO_RWLOCK *fake_time_lock; 24 25 static const char *certfile, *keyfile; 26 27 static int is_want(SSL *s, int ret) 28 { 29 int ec = SSL_get_error(s, ret); 30 31 return ec == SSL_ERROR_WANT_READ || ec == SSL_ERROR_WANT_WRITE; 32 } 33 34 static unsigned char scratch_buf[2048]; 35 36 static OSSL_TIME fake_now(void *arg) 37 { 38 OSSL_TIME t; 39 40 if (!CRYPTO_THREAD_read_lock(fake_time_lock)) 41 return ossl_time_zero(); 42 43 t = fake_time; 44 45 CRYPTO_THREAD_unlock(fake_time_lock); 46 return t; 47 } 48 49 static OSSL_TIME real_now(void *arg) 50 { 51 return ossl_time_now(); 52 } 53 54 static int do_test(int use_thread_assist, int use_fake_time, int use_inject) 55 { 56 int testresult = 0, ret; 57 int s_fd = -1, c_fd = -1; 58 BIO *s_net_bio = NULL, *s_net_bio_own = NULL; 59 BIO *c_net_bio = NULL, *c_net_bio_own = NULL; 60 BIO *c_pair_own = NULL, *s_pair_own = NULL; 61 QUIC_TSERVER_ARGS tserver_args = { 0 }; 62 QUIC_TSERVER *tserver = NULL; 63 BIO_ADDR *s_addr_ = NULL, *c_addr_ = NULL; 64 struct in_addr ina = { 0 }; 65 union BIO_sock_info_u s_info = { 0 }; 66 SSL_CTX *c_ctx = NULL; 67 SSL *c_ssl = NULL; 68 int c_connected = 0, c_write_done = 0, c_begin_read = 0, s_read_done = 0; 69 int c_wait_eos = 0, c_done_eos = 0; 70 int c_start_idle_test = 0, c_done_idle_test = 0; 71 size_t l = 0, s_total_read = 0, s_total_written = 0, c_total_read = 0; 72 size_t idle_units_done = 0; 73 int s_begin_write = 0; 74 OSSL_TIME start_time; 75 unsigned char alpn[] = { 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' }; 76 size_t limit_ms = 10000; 77 78 #if defined(OPENSSL_NO_QUIC_THREAD_ASSIST) 79 if (use_thread_assist) { 80 TEST_skip("thread assisted mode not enabled"); 81 return 1; 82 } 83 #endif 84 85 ina.s_addr = htonl(0x7f000001UL); 86 87 /* Setup test server. */ 88 if (!TEST_ptr(s_addr_ = BIO_ADDR_new())) 89 goto err; 90 91 if (!TEST_true(BIO_ADDR_rawmake(s_addr_, AF_INET, &ina, sizeof(ina), 0))) 92 goto err; 93 94 if (use_fake_time) { 95 /* 96 * Keep accelerated fake time independent of OS network scheduling. 97 * Other iterations retain real UDP socket coverage. 98 */ 99 if (!TEST_true(BIO_new_bio_dgram_pair(&c_net_bio_own, 0, 100 &s_net_bio_own, 0))) 101 goto err; 102 103 c_net_bio = c_net_bio_own; 104 s_net_bio = s_net_bio_own; 105 106 if (!TEST_true(BIO_dgram_set_caps(c_net_bio, 107 BIO_DGRAM_CAP_HANDLES_DST_ADDR)) 108 || !TEST_true(BIO_dgram_set_caps(s_net_bio, 109 BIO_DGRAM_CAP_HANDLES_DST_ADDR))) 110 goto err; 111 112 if (!TEST_ptr(c_addr_ = BIO_ADDR_new()) 113 || !TEST_true(BIO_ADDR_rawmake(c_addr_, AF_INET, &ina, 114 sizeof(ina), 0)) 115 || !TEST_true(BIO_dgram_set0_local_addr(c_net_bio, c_addr_))) 116 goto err; 117 c_addr_ = NULL; 118 } else { 119 s_fd = BIO_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0); 120 if (!TEST_int_ge(s_fd, 0)) 121 goto err; 122 123 if (!TEST_true(BIO_socket_nbio(s_fd, 1))) 124 goto err; 125 126 if (!TEST_true(BIO_bind(s_fd, s_addr_, 0))) 127 goto err; 128 129 s_info.addr = s_addr_; 130 if (!TEST_true(BIO_sock_info(s_fd, BIO_SOCK_INFO_ADDRESS, &s_info))) 131 goto err; 132 133 if (!TEST_int_gt(BIO_ADDR_rawport(s_addr_), 0)) 134 goto err; 135 136 if (!TEST_ptr(s_net_bio = s_net_bio_own = BIO_new_dgram(s_fd, 0))) 137 goto err; 138 } 139 140 if (!BIO_up_ref(s_net_bio)) 141 goto err; 142 143 fake_time = ossl_ms2time(1000); 144 145 tserver_args.net_rbio = s_net_bio; 146 tserver_args.net_wbio = s_net_bio; 147 tserver_args.alpn = NULL; 148 tserver_args.ctx = NULL; 149 if (use_fake_time) 150 tserver_args.now_cb = fake_now; 151 152 if (!TEST_ptr(tserver = ossl_quic_tserver_new(&tserver_args, certfile, 153 keyfile))) { 154 BIO_free(s_net_bio); 155 goto err; 156 } 157 158 s_net_bio_own = NULL; 159 160 if (use_inject) { 161 /* 162 * In inject mode we create a dgram pair to feed to the QUIC client on 163 * the read side. We don't feed anything to this, it is just a 164 * placeholder to give the client something which never returns any 165 * datagrams. 166 */ 167 if (!TEST_true(BIO_new_bio_dgram_pair(&c_pair_own, 5000, 168 &s_pair_own, 5000))) 169 goto err; 170 } 171 172 /* Setup test client. */ 173 if (!use_fake_time) { 174 c_fd = BIO_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0); 175 if (!TEST_int_ge(c_fd, 0)) 176 goto err; 177 178 if (!TEST_true(BIO_socket_nbio(c_fd, 1))) 179 goto err; 180 181 if (!TEST_ptr(c_net_bio = c_net_bio_own = BIO_new_dgram(c_fd, 0))) 182 goto err; 183 184 if (!BIO_dgram_set_peer(c_net_bio, s_addr_)) 185 goto err; 186 } 187 188 if (!TEST_ptr(c_ctx = SSL_CTX_new(use_thread_assist 189 ? OSSL_QUIC_client_thread_method() 190 : OSSL_QUIC_client_method()))) 191 goto err; 192 193 if (!TEST_ptr(c_ssl = SSL_new(c_ctx))) 194 goto err; 195 196 if (use_fake_time) { 197 if (!TEST_true(SSL_set1_initial_peer_addr(c_ssl, s_addr_))) 198 goto err; 199 if (!TEST_true(ossl_quic_set_override_now_cb(c_ssl, fake_now, NULL))) 200 goto err; 201 } 202 203 /* 0 is a success for SSL_set_alpn_protos() */ 204 if (!TEST_false(SSL_set_alpn_protos(c_ssl, alpn, sizeof(alpn)))) 205 goto err; 206 207 /* Takes ownership of our reference to the BIO. */ 208 if (use_inject) { 209 SSL_set0_rbio(c_ssl, c_pair_own); 210 c_pair_own = NULL; 211 } else { 212 SSL_set0_rbio(c_ssl, c_net_bio); 213 214 /* Get another reference to be transferred in the SSL_set0_wbio call. */ 215 if (!TEST_true(BIO_up_ref(c_net_bio))) { 216 c_net_bio_own = NULL; /* SSL_free will free the first reference. */ 217 goto err; 218 } 219 } 220 221 SSL_set0_wbio(c_ssl, c_net_bio); 222 c_net_bio_own = NULL; 223 224 if (!TEST_true(SSL_set_blocking_mode(c_ssl, 0))) 225 goto err; 226 227 /* 228 * We use real time for the timeout not fake time. Otherwise with fake time 229 * we could hit a hang if we never increment the fake time 230 */ 231 start_time = real_now(NULL); 232 233 for (;;) { 234 if (ossl_time_compare(ossl_time_subtract(real_now(NULL), start_time), 235 ossl_ms2time(limit_ms)) 236 >= 0) { 237 TEST_error("timeout while attempting QUIC server test"); 238 goto err; 239 } 240 241 if (!c_start_idle_test) { 242 ret = SSL_connect(c_ssl); 243 if (!TEST_true(ret == 1 || is_want(c_ssl, ret))) 244 goto err; 245 246 if (ret == 1) { 247 c_connected = 1; 248 } else { 249 /* 250 * keep timer ticking to keep handshake running. 251 * The timer is important for calculation of ping deadline. 252 * If things stall for whatever reason we at least send 253 * ACK eliciting ping to let peer know we are here ready 254 * to hear back. 255 */ 256 if (!TEST_true(CRYPTO_THREAD_write_lock(fake_time_lock))) 257 goto err; 258 fake_time = ossl_time_add(fake_time, ossl_ms2time(100)); 259 CRYPTO_THREAD_unlock(fake_time_lock); 260 } 261 } 262 263 if (c_connected && !c_write_done) { 264 if (!TEST_int_eq(SSL_write(c_ssl, msg1, sizeof(msg1) - 1), 265 (int)sizeof(msg1) - 1)) 266 goto err; 267 268 if (!TEST_true(SSL_stream_conclude(c_ssl, 0))) 269 goto err; 270 271 c_write_done = 1; 272 } 273 274 if (c_connected && c_write_done && !s_read_done) { 275 if (!ossl_quic_tserver_read(tserver, 0, 276 (unsigned char *)msg2 + s_total_read, 277 sizeof(msg2) - s_total_read, &l)) { 278 if (!TEST_true(ossl_quic_tserver_has_read_ended(tserver, 0))) 279 goto err; 280 281 if (!TEST_mem_eq(msg1, sizeof(msg1) - 1, msg2, s_total_read)) 282 goto err; 283 284 s_begin_write = 1; 285 s_read_done = 1; 286 } else { 287 s_total_read += l; 288 if (!TEST_size_t_le(s_total_read, sizeof(msg1) - 1)) 289 goto err; 290 } 291 } 292 293 if (s_begin_write && s_total_written < sizeof(msg1) - 1) { 294 if (!TEST_true(ossl_quic_tserver_write(tserver, 0, 295 (unsigned char *)msg2 + s_total_written, 296 sizeof(msg1) - 1 - s_total_written, &l))) 297 goto err; 298 299 s_total_written += l; 300 301 if (s_total_written == sizeof(msg1) - 1) { 302 ossl_quic_tserver_conclude(tserver, 0); 303 c_begin_read = 1; 304 } 305 } 306 307 if (c_begin_read && c_total_read < sizeof(msg1) - 1) { 308 ret = SSL_read_ex(c_ssl, msg3 + c_total_read, 309 sizeof(msg1) - 1 - c_total_read, &l); 310 if (!TEST_true(ret == 1 || is_want(c_ssl, ret))) 311 goto err; 312 313 c_total_read += l; 314 315 if (c_total_read == sizeof(msg1) - 1) { 316 if (!TEST_mem_eq(msg1, sizeof(msg1) - 1, 317 msg3, c_total_read)) 318 goto err; 319 320 c_wait_eos = 1; 321 } 322 } 323 324 if (c_wait_eos && !c_done_eos) { 325 unsigned char c; 326 327 ret = SSL_read_ex(c_ssl, &c, sizeof(c), &l); 328 if (!TEST_false(ret)) 329 goto err; 330 331 /* 332 * Allow the implementation to take as long as it wants to finally 333 * notice EOS. Account for varied timings in OS networking stacks. 334 */ 335 if (SSL_get_error(c_ssl, ret) != SSL_ERROR_WANT_READ) { 336 if (!TEST_int_eq(SSL_get_error(c_ssl, ret), 337 SSL_ERROR_ZERO_RETURN)) 338 goto err; 339 340 c_done_eos = 1; 341 if (use_thread_assist && use_fake_time) { 342 if (!TEST_true(ossl_quic_tserver_is_connected(tserver))) 343 goto err; 344 c_start_idle_test = 1; 345 limit_ms = 120000; /* extend time limit */ 346 } else { 347 /* DONE */ 348 break; 349 } 350 } 351 } 352 353 if (c_start_idle_test && !c_done_idle_test) { 354 /* This is more than our default idle timeout of 30s. */ 355 if (idle_units_done < 600) { 356 struct timeval tv; 357 int isinf; 358 359 if (!TEST_true(CRYPTO_THREAD_write_lock(fake_time_lock))) 360 goto err; 361 fake_time = ossl_time_add(fake_time, ossl_ms2time(100)); 362 CRYPTO_THREAD_unlock(fake_time_lock); 363 364 ++idle_units_done; 365 366 /* 367 * The assist thread alone keeps the idle connection alive. It 368 * waits on real time internally, so advancing fake time can 369 * outrun it. Rather than race it, wait until it has caught up: 370 * the event timeout is computed against fake time, so once the 371 * next deadline is back in the future all events due up to now 372 * - including any keepalive - have been serviced. 373 */ 374 for (;;) { 375 ossl_quic_conn_force_assist_thread_wake(c_ssl); 376 377 if (!TEST_true(SSL_get_event_timeout(c_ssl, &tv, &isinf))) 378 goto err; 379 380 if (isinf 381 || ossl_time_compare(ossl_time_from_timeval(tv), 382 ossl_time_zero()) 383 > 0) 384 break; 385 386 if (ossl_time_compare(ossl_time_subtract(real_now(NULL), 387 start_time), 388 ossl_ms2time(limit_ms)) 389 >= 0) { 390 TEST_error("timeout waiting for assist thread to send " 391 "keepalive during idle test"); 392 goto err; 393 } 394 395 OSSL_sleep(1); /* Yield so the assist thread can run. */ 396 } 397 } else { 398 c_done_idle_test = 1; 399 } 400 } 401 402 if (c_done_idle_test) { 403 /* 404 * If we have finished the fake idling duration, the connection 405 * should still be healthy in TA mode. 406 */ 407 if (!TEST_true(ossl_quic_tserver_is_connected(tserver))) 408 goto err; 409 410 /* DONE */ 411 break; 412 } 413 414 /* 415 * This is inefficient because we spin until things work without 416 * blocking but this is just a test. 417 */ 418 if (!c_start_idle_test || c_done_idle_test) { 419 /* Inhibit manual ticking during idle test to test TA mode. */ 420 SSL_handle_events(c_ssl); 421 } 422 423 ossl_quic_tserver_tick(tserver); 424 425 if (use_inject) { 426 BIO_MSG rmsg = { 0 }; 427 size_t msgs_processed = 0; 428 429 for (;;) { 430 /* 431 * Manually spoonfeed received datagrams from the network BIO 432 * into QUIC via the injection interface, thereby testing the 433 * injection interface. 434 */ 435 rmsg.data = scratch_buf; 436 rmsg.data_len = sizeof(scratch_buf); 437 438 if (!BIO_recvmmsg(c_net_bio, &rmsg, sizeof(rmsg), 1, 0, &msgs_processed) 439 || msgs_processed == 0 || rmsg.data_len == 0) 440 break; 441 442 if (!TEST_true(SSL_inject_net_dgram(c_ssl, rmsg.data, rmsg.data_len, 443 NULL, NULL))) 444 goto err; 445 } 446 } 447 } 448 449 testresult = 1; 450 err: 451 SSL_free(c_ssl); 452 SSL_CTX_free(c_ctx); 453 ossl_quic_tserver_free(tserver); 454 BIO_ADDR_free(s_addr_); 455 BIO_ADDR_free(c_addr_); 456 BIO_free(s_net_bio_own); 457 BIO_free(c_net_bio_own); 458 BIO_free(c_pair_own); 459 BIO_free(s_pair_own); 460 if (s_fd >= 0) 461 BIO_closesocket(s_fd); 462 if (c_fd >= 0) 463 BIO_closesocket(c_fd); 464 return testresult; 465 } 466 467 static int test_tserver(int idx) 468 { 469 int thread_assisted, use_fake_time, use_inject; 470 471 thread_assisted = idx % 2; 472 idx /= 2; 473 474 use_inject = idx % 2; 475 idx /= 2; 476 477 use_fake_time = idx % 2; 478 479 if (use_fake_time && !thread_assisted) 480 return 1; 481 482 return do_test(thread_assisted, use_fake_time, use_inject); 483 } 484 485 OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n") 486 487 int setup_tests(void) 488 { 489 if (!test_skip_common_options()) { 490 TEST_error("Error parsing test options\n"); 491 return 0; 492 } 493 494 if (!TEST_ptr(certfile = test_get_argument(0)) 495 || !TEST_ptr(keyfile = test_get_argument(1))) 496 return 0; 497 498 if ((fake_time_lock = CRYPTO_THREAD_lock_new()) == NULL) 499 return 0; 500 501 ADD_ALL_TESTS(test_tserver, 2 * 2 * 2); 502 return 1; 503 } 504