test_extorport.c (18741B)
1 /* Copyright (c) 2013-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 #define CONNECTION_PRIVATE 5 #define EXT_ORPORT_PRIVATE 6 #define MAINLOOP_PRIVATE 7 #include "core/or/or.h" 8 #include "lib/buf/buffers.h" 9 #include "core/mainloop/connection.h" 10 #include "core/or/connection_or.h" 11 #include "app/config/config.h" 12 #include "feature/control/control_events.h" 13 #include "lib/crypt_ops/crypto_rand.h" 14 #include "feature/relay/ext_orport.h" 15 #include "core/mainloop/mainloop.h" 16 17 #include "core/or/or_connection_st.h" 18 19 #include "test/test.h" 20 #include "test/test_helpers.h" 21 #include "test/rng_test_helpers.h" 22 23 #ifdef HAVE_SYS_STAT_H 24 #include <sys/stat.h> 25 #endif 26 27 /* Simple connection_write_to_buf_impl_ replacement that unconditionally 28 * writes to outbuf. */ 29 static void 30 connection_write_to_buf_impl_replacement(const char *string, size_t len, 31 connection_t *conn, int compressed) 32 { 33 (void) compressed; 34 35 tor_assert(string); 36 tor_assert(conn); 37 buf_add(conn->outbuf, string, len); 38 } 39 40 static void 41 test_ext_or_write_command(void *arg) 42 { 43 or_connection_t *c1; 44 char *cp = NULL; 45 char *buf = NULL; 46 size_t sz; 47 48 (void) arg; 49 MOCK(connection_write_to_buf_impl_, 50 connection_write_to_buf_impl_replacement); 51 52 c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET); 53 tt_assert(c1); 54 55 /* Length too long */ 56 tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 100, "X", 100000), 57 OP_LT, 0); 58 59 /* Empty command */ 60 tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, NULL, 0), 61 OP_EQ, 0); 62 cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz); 63 tt_int_op(sz, OP_EQ, 4); 64 tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x00", 4); 65 tor_free(cp); 66 67 /* Medium command. */ 68 tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, 69 "Wai\0Hello", 9), OP_EQ, 0); 70 cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz); 71 tt_int_op(sz, OP_EQ, 13); 72 tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x09Wai\x00Hello", 13); 73 tor_free(cp); 74 75 /* Long command */ 76 buf = tor_malloc(65535); 77 memset(buf, 'x', 65535); 78 tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0xf00d, 79 buf, 65535), OP_EQ, 0); 80 cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz); 81 tt_int_op(sz, OP_EQ, 65539); 82 tt_mem_op(cp, OP_EQ, "\xf0\x0d\xff\xff", 4); 83 tt_mem_op(cp+4, OP_EQ, buf, 65535); 84 tor_free(cp); 85 86 done: 87 if (c1) 88 connection_free_minimal(TO_CONN(c1)); 89 tor_free(cp); 90 tor_free(buf); 91 UNMOCK(connection_write_to_buf_impl_); 92 } 93 94 static int 95 write_bytes_to_file_fail(const char *fname, const char *str, size_t len, 96 int bin) 97 { 98 (void) fname; 99 (void) str; 100 (void) len; 101 (void) bin; 102 103 return -1; 104 } 105 106 static void 107 test_ext_or_init_auth(void *arg) 108 { 109 or_options_t *options = get_options_mutable(); 110 const char *fn; 111 char *cp = NULL; 112 struct stat st; 113 char cookie0[32]; 114 (void)arg; 115 116 /* Check default filename location */ 117 tor_free(options->DataDirectory); 118 options->DataDirectory = tor_strdup("foo"); 119 cp = get_ext_or_auth_cookie_file_name(); 120 tt_str_op(cp, OP_EQ, "foo"PATH_SEPARATOR"extended_orport_auth_cookie"); 121 tor_free(cp); 122 123 /* Shouldn't be initialized already, or our tests will be a bit 124 * meaningless */ 125 ext_or_auth_cookie = tor_malloc_zero(32); 126 tt_assert(fast_mem_is_zero((char*)ext_or_auth_cookie, 32)); 127 128 /* Now make sure we use a temporary file */ 129 fn = get_fname("ext_cookie_file"); 130 options->ExtORPortCookieAuthFile = tor_strdup(fn); 131 cp = get_ext_or_auth_cookie_file_name(); 132 tt_str_op(cp, OP_EQ, fn); 133 tor_free(cp); 134 135 /* Test the initialization function with a broken 136 write_bytes_to_file(). See if the problem is handled properly. */ 137 MOCK(write_bytes_to_file, write_bytes_to_file_fail); 138 tt_int_op(-1, OP_EQ, init_ext_or_cookie_authentication(1)); 139 tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 0); 140 UNMOCK(write_bytes_to_file); 141 142 /* Now do the actual initialization. */ 143 tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1)); 144 tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 1); 145 cp = read_file_to_str(fn, RFTS_BIN, &st); 146 tt_ptr_op(cp, OP_NE, NULL); 147 tt_u64_op((uint64_t)st.st_size, OP_EQ, 64); 148 tt_mem_op(cp,OP_EQ, "! Extended ORPort Auth Cookie !\x0a", 32); 149 tt_mem_op(cp+32,OP_EQ, ext_or_auth_cookie, 32); 150 memcpy(cookie0, ext_or_auth_cookie, 32); 151 tt_assert(!fast_mem_is_zero((char*)ext_or_auth_cookie, 32)); 152 153 /* Operation should be idempotent. */ 154 tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1)); 155 tt_mem_op(cookie0,OP_EQ, ext_or_auth_cookie, 32); 156 157 done: 158 tor_free(cp); 159 ext_orport_free_all(); 160 } 161 162 static void 163 test_ext_or_cookie_auth(void *arg) 164 { 165 char *reply=NULL, *reply2=NULL, *client_hash=NULL, *client_hash2=NULL; 166 size_t reply_len=0; 167 char hmac1[32], hmac2[32]; 168 169 NONSTRING const char client_nonce[32] = 170 "Who is the third who walks alway"; 171 char server_hash_input[] = 172 "ExtORPort authentication server-to-client hash" 173 "Who is the third who walks alway" 174 "................................"; 175 char client_hash_input[] = 176 "ExtORPort authentication client-to-server hash" 177 "Who is the third who walks alway" 178 "................................"; 179 180 (void)arg; 181 182 tt_int_op(strlen(client_hash_input), OP_EQ, 46+32+32); 183 tt_int_op(strlen(server_hash_input), OP_EQ, 46+32+32); 184 185 ext_or_auth_cookie = tor_malloc_zero(32); 186 memcpy(ext_or_auth_cookie, "s beside you? When I count, ther", 32); 187 ext_or_auth_cookie_is_set = 1; 188 189 /* For this authentication, the client sends 32 random bytes (ClientNonce) 190 * The server replies with 32 byte ServerHash and 32 byte ServerNonce, 191 * where ServerHash is: 192 * HMAC-SHA256(CookieString, 193 * "ExtORPort authentication server-to-client hash" | ClientNonce | 194 * ServerNonce)" 195 * The client must reply with 32-byte ClientHash, which we compute as: 196 * ClientHash is computed as: 197 * HMAC-SHA256(CookieString, 198 * "ExtORPort authentication client-to-server hash" | ClientNonce | 199 * ServerNonce) 200 */ 201 202 /* Wrong length */ 203 tt_int_op(-1, OP_EQ, 204 handle_client_auth_nonce(client_nonce, 33, &client_hash, &reply, 205 &reply_len)); 206 tt_int_op(-1, OP_EQ, 207 handle_client_auth_nonce(client_nonce, 31, &client_hash, &reply, 208 &reply_len)); 209 210 /* Now let's try this for real! */ 211 tt_int_op(0, OP_EQ, 212 handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply, 213 &reply_len)); 214 tt_int_op(reply_len, OP_EQ, 64); 215 tt_ptr_op(reply, OP_NE, NULL); 216 tt_ptr_op(client_hash, OP_NE, NULL); 217 /* Fill in the server nonce into the hash inputs... */ 218 memcpy(server_hash_input+46+32, reply+32, 32); 219 memcpy(client_hash_input+46+32, reply+32, 32); 220 /* Check the HMACs are correct... */ 221 crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input, 222 46+32+32); 223 crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input, 224 46+32+32); 225 tt_mem_op(hmac1,OP_EQ, reply, 32); 226 tt_mem_op(hmac2,OP_EQ, client_hash, 32); 227 228 /* Now do it again and make sure that the results are *different* */ 229 tt_int_op(0, OP_EQ, 230 handle_client_auth_nonce(client_nonce, 32, &client_hash2, &reply2, 231 &reply_len)); 232 tt_mem_op(reply2,OP_NE, reply, reply_len); 233 tt_mem_op(client_hash2,OP_NE, client_hash, 32); 234 /* But that this one checks out too. */ 235 memcpy(server_hash_input+46+32, reply2+32, 32); 236 memcpy(client_hash_input+46+32, reply2+32, 32); 237 /* Check the HMACs are correct... */ 238 crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input, 239 46+32+32); 240 crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input, 241 46+32+32); 242 tt_mem_op(hmac1,OP_EQ, reply2, 32); 243 tt_mem_op(hmac2,OP_EQ, client_hash2, 32); 244 245 done: 246 tor_free(reply); 247 tor_free(client_hash); 248 tor_free(reply2); 249 tor_free(client_hash2); 250 } 251 252 static void 253 test_ext_or_cookie_auth_testvec(void *arg) 254 { 255 char *reply=NULL, *client_hash=NULL; 256 size_t reply_len; 257 char *mem_op_hex_tmp=NULL; 258 259 const char client_nonce[] = "But when I look ahead up the whi"; 260 (void)arg; 261 262 ext_or_auth_cookie = tor_malloc_zero(32); 263 memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32); 264 ext_or_auth_cookie_is_set = 1; 265 266 testing_enable_prefilled_rng("te road There is always another ", 32); 267 268 tt_int_op(0, OP_EQ, 269 handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply, 270 &reply_len)); 271 tt_ptr_op(reply, OP_NE, NULL ); 272 tt_uint_op(reply_len, OP_EQ, 64); 273 tt_mem_op(reply+32,OP_EQ, "te road There is always another ", 32); 274 /* HMACSHA256("Gliding wrapt in a brown mantle," 275 * "ExtORPort authentication server-to-client hash" 276 * "But when I look ahead up the write road There is always another "); 277 */ 278 test_memeq_hex(reply, 279 "ec80ed6e546d3b36fdfc22fe1315416b" 280 "029f1ade7610d910878b62eeb7403821"); 281 /* HMACSHA256("Gliding wrapt in a brown mantle," 282 * "ExtORPort authentication client-to-server hash" 283 * "But when I look ahead up the write road There is always another "); 284 * (Both values computed using Python CLI.) 285 */ 286 test_memeq_hex(client_hash, 287 "ab391732dd2ed968cd40c087d1b1f25b" 288 "33b3cd77ff79bd80c2074bbf438119a2"); 289 290 done: 291 testing_disable_prefilled_rng(); 292 tor_free(reply); 293 tor_free(client_hash); 294 tor_free(mem_op_hex_tmp); 295 } 296 297 static void 298 ignore_bootstrap_problem(const char *warn, int reason, 299 or_connection_t *conn) 300 { 301 (void)warn; 302 (void)reason; 303 (void)conn; 304 } 305 306 static int is_reading = 1; 307 static int handshake_start_called = 0; 308 309 static void 310 note_read_stopped(connection_t *conn) 311 { 312 (void)conn; 313 is_reading=0; 314 } 315 static void 316 note_read_started(connection_t *conn) 317 { 318 (void)conn; 319 is_reading=1; 320 } 321 static int 322 handshake_start(or_connection_t *conn, int receiving) 323 { 324 if (!conn || !receiving) 325 TT_FAIL(("Bad arguments to handshake_start")); 326 handshake_start_called = 1; 327 return 0; 328 } 329 330 #define WRITE(s,n) \ 331 do { \ 332 buf_add(TO_CONN(conn)->inbuf, (s), (n)); \ 333 } while (0) 334 #define CONTAINS(s,n) \ 335 do { \ 336 tt_int_op((n), OP_LE, sizeof(b)); \ 337 tt_int_op(buf_datalen(TO_CONN(conn)->outbuf), OP_EQ, (n)); \ 338 if ((n)) { \ 339 buf_get_bytes(TO_CONN(conn)->outbuf, b, (n)); \ 340 tt_mem_op(b, OP_EQ, (s), (n)); \ 341 } \ 342 } while (0) 343 344 /* Helper: Do a successful Extended ORPort authentication handshake. */ 345 static void 346 do_ext_or_handshake(or_connection_t *conn) 347 { 348 char b[256]; 349 350 tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn)); 351 CONTAINS("\x01\x00", 2); 352 WRITE("\x01", 1); 353 WRITE("But when I look ahead up the whi", 32); 354 testing_enable_prefilled_rng("te road There is always another ", 32); 355 tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); 356 testing_disable_prefilled_rng(); 357 tt_int_op(TO_CONN(conn)->state, OP_EQ, 358 EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH); 359 CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b" 360 "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21" 361 "te road There is always another ", 64); 362 /* Send the right response this time. */ 363 WRITE("\xab\x39\x17\x32\xdd\x2e\xd9\x68\xcd\x40\xc0\x87\xd1\xb1\xf2\x5b" 364 "\x33\xb3\xcd\x77\xff\x79\xbd\x80\xc2\x07\x4b\xbf\x43\x81\x19\xa2", 365 32); 366 tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); 367 CONTAINS("\x01", 1); 368 tt_assert(! TO_CONN(conn)->marked_for_close); 369 tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN); 370 371 done: ; 372 } 373 374 static void 375 test_ext_or_handshake(void *arg) 376 { 377 or_connection_t *conn=NULL; 378 char b[256]; 379 380 (void) arg; 381 MOCK(connection_write_to_buf_impl_, 382 connection_write_to_buf_impl_replacement); 383 /* Use same authenticators as for test_ext_or_cookie_auth_testvec */ 384 ext_or_auth_cookie = tor_malloc_zero(32); 385 memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32); 386 ext_or_auth_cookie_is_set = 1; 387 388 tor_init_connection_lists(); 389 390 conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET); 391 tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn)); 392 /* The server starts by telling us about the one supported authtype. */ 393 CONTAINS("\x01\x00", 2); 394 /* Say the client hasn't responded yet. */ 395 tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); 396 /* Let's say the client replies badly. */ 397 WRITE("\x99", 1); 398 tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn)); 399 CONTAINS("", 0); 400 tt_assert(TO_CONN(conn)->marked_for_close); 401 close_closeable_connections(); 402 conn = NULL; 403 404 /* Okay, try again. */ 405 conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET); 406 tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn)); 407 CONTAINS("\x01\x00", 2); 408 /* Let's say the client replies sensibly this time. "Yes, AUTHTYPE_COOKIE 409 * sounds delicious. Let's have some of that!" */ 410 WRITE("\x01", 1); 411 /* Let's say that the client also sends part of a nonce. */ 412 WRITE("But when I look ", 16); 413 tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); 414 CONTAINS("", 0); 415 tt_int_op(TO_CONN(conn)->state, OP_EQ, 416 EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE); 417 /* Pump it again. Nothing should happen. */ 418 tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); 419 /* send the rest of the nonce. */ 420 WRITE("ahead up the whi", 16); 421 testing_enable_prefilled_rng("te road There is always another ", 32); 422 tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); 423 testing_disable_prefilled_rng(); 424 /* We should get the right reply from the server. */ 425 CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b" 426 "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21" 427 "te road There is always another ", 64); 428 /* Send the wrong response. */ 429 WRITE("not with a bang but a whimper...", 32); 430 MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem); 431 tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn)); 432 CONTAINS("\x00", 1); 433 tt_assert(TO_CONN(conn)->marked_for_close); 434 /* XXXX Hold-open-until-flushed. */ 435 close_closeable_connections(); 436 conn = NULL; 437 UNMOCK(control_event_bootstrap_prob_or); 438 439 MOCK(connection_start_reading, note_read_started); 440 MOCK(connection_stop_reading, note_read_stopped); 441 MOCK(connection_tls_start_handshake, handshake_start); 442 443 /* Okay, this time let's succeed. */ 444 conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET); 445 do_ext_or_handshake(conn); 446 447 /* Now let's run through some messages. */ 448 /* First let's send some junk and make sure it's ignored. */ 449 WRITE("\xff\xf0\x00\x03""ABC", 7); 450 tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); 451 CONTAINS("", 0); 452 /* Now let's send a USERADDR command. */ 453 WRITE("\x00\x01\x00\x0c""1.2.3.4:5678", 16); 454 tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); 455 tt_int_op(TO_CONN(conn)->port, OP_EQ, 5678); 456 tt_int_op(tor_addr_to_ipv4h(&TO_CONN(conn)->addr), OP_EQ, 0x01020304); 457 /* Now let's send a TRANSPORT command. */ 458 WRITE("\x00\x02\x00\x07""rfc1149", 11); 459 tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); 460 tt_ptr_op(NULL, OP_NE, conn->ext_or_transport); 461 tt_str_op("rfc1149", OP_EQ, conn->ext_or_transport); 462 tt_int_op(is_reading,OP_EQ,1); 463 tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN); 464 /* DONE */ 465 WRITE("\x00\x00\x00\x00", 4); 466 tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); 467 tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_FLUSHING); 468 tt_int_op(is_reading,OP_EQ,0); 469 CONTAINS("\x10\x00\x00\x00", 4); 470 tt_int_op(handshake_start_called,OP_EQ,0); 471 tt_int_op(0, OP_EQ, connection_ext_or_finished_flushing(conn)); 472 tt_int_op(is_reading,OP_EQ,1); 473 tt_int_op(handshake_start_called,OP_EQ,1); 474 tt_int_op(TO_CONN(conn)->type, OP_EQ, CONN_TYPE_OR); 475 tt_int_op(TO_CONN(conn)->state, OP_EQ, 0); 476 connection_free_(TO_CONN(conn)); 477 conn = NULL; 478 479 /* Okay, this time let's succeed the handshake but fail the USERADDR 480 command. */ 481 conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET); 482 do_ext_or_handshake(conn); 483 /* USERADDR command with an extra NUL byte */ 484 WRITE("\x00\x01\x00\x0d""1.2.3.4:5678\x00", 17); 485 MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem); 486 tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn)); 487 CONTAINS("", 0); 488 tt_assert(TO_CONN(conn)->marked_for_close); 489 close_closeable_connections(); 490 conn = NULL; 491 UNMOCK(control_event_bootstrap_prob_or); 492 493 /* Now fail the TRANSPORT command. */ 494 conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET); 495 do_ext_or_handshake(conn); 496 /* TRANSPORT command with an extra NUL byte */ 497 WRITE("\x00\x02\x00\x08""rfc1149\x00", 12); 498 MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem); 499 tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn)); 500 CONTAINS("", 0); 501 tt_assert(TO_CONN(conn)->marked_for_close); 502 close_closeable_connections(); 503 conn = NULL; 504 UNMOCK(control_event_bootstrap_prob_or); 505 506 /* Now fail the TRANSPORT command. */ 507 conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET); 508 do_ext_or_handshake(conn); 509 /* TRANSPORT command with transport name with symbols (not a 510 C-identifier) */ 511 WRITE("\x00\x02\x00\x07""rf*1149", 11); 512 MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem); 513 tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn)); 514 CONTAINS("", 0); 515 tt_assert(TO_CONN(conn)->marked_for_close); 516 close_closeable_connections(); 517 conn = NULL; 518 UNMOCK(control_event_bootstrap_prob_or); 519 520 done: 521 UNMOCK(connection_write_to_buf_impl_); 522 testing_disable_prefilled_rng(); 523 if (conn) 524 connection_free_minimal(TO_CONN(conn)); 525 #undef CONTAINS 526 #undef WRITE 527 } 528 529 struct testcase_t extorport_tests[] = { 530 { "write_command", test_ext_or_write_command, TT_FORK, NULL, NULL }, 531 { "init_auth", test_ext_or_init_auth, TT_FORK, NULL, NULL }, 532 { "cookie_auth", test_ext_or_cookie_auth, TT_FORK, NULL, NULL }, 533 { "cookie_auth_testvec", test_ext_or_cookie_auth_testvec, TT_FORK, 534 NULL, NULL }, 535 { "handshake", test_ext_or_handshake, TT_FORK, &helper_pubsub_setup, NULL }, 536 END_OF_TESTCASES 537 };