1 /* Copyright (c) 2013-2018, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #define CONNECTION_PRIVATE
5 #define EXT_ORPORT_PRIVATE
6 #define MAINLOOP_PRIVATE
7 #include "core/or/or.h"
8 #include "lib/container/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.h"
13 #include "lib/crypt_ops/crypto_rand.h"
14 #include "feature/relay/ext_orport.h"
15 #include "core/mainloop/mainloop.h"
17 #include "core/or/or_connection_st.h"
19 #include "test/test.h"
20 #include "test/test_helpers.h"
22 #ifdef HAVE_SYS_STAT_H
26 /* Test connection_or_remove_from_ext_or_id_map and
27 * connection_or_set_ext_or_identifier */
29 test_ext_or_id_map(void *arg
)
31 or_connection_t
*c1
= NULL
, *c2
= NULL
, *c3
= NULL
;
32 char *idp
= NULL
, *idp2
= NULL
;
35 /* pre-initialization */
36 tt_ptr_op(NULL
, OP_EQ
,
37 connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
39 c1
= or_connection_new(CONN_TYPE_EXT_OR
, AF_INET
);
40 c2
= or_connection_new(CONN_TYPE_EXT_OR
, AF_INET
);
41 c3
= or_connection_new(CONN_TYPE_OR
, AF_INET
);
43 tt_ptr_op(c1
->ext_or_conn_id
, OP_NE
, NULL
);
44 tt_ptr_op(c2
->ext_or_conn_id
, OP_NE
, NULL
);
45 tt_ptr_op(c3
->ext_or_conn_id
, OP_EQ
, NULL
);
47 tt_ptr_op(c1
, OP_EQ
, connection_or_get_by_ext_or_id(c1
->ext_or_conn_id
));
48 tt_ptr_op(c2
, OP_EQ
, connection_or_get_by_ext_or_id(c2
->ext_or_conn_id
));
49 tt_ptr_op(NULL
, OP_EQ
,
50 connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
52 idp
= tor_memdup(c2
->ext_or_conn_id
, EXT_OR_CONN_ID_LEN
);
54 /* Give c2 a new ID. */
55 connection_or_set_ext_or_identifier(c2
);
56 tt_mem_op(idp
, OP_NE
, c2
->ext_or_conn_id
, EXT_OR_CONN_ID_LEN
);
57 idp2
= tor_memdup(c2
->ext_or_conn_id
, EXT_OR_CONN_ID_LEN
);
58 tt_assert(!tor_digest_is_zero(idp2
));
60 tt_ptr_op(NULL
, OP_EQ
, connection_or_get_by_ext_or_id(idp
));
61 tt_ptr_op(c2
, OP_EQ
, connection_or_get_by_ext_or_id(idp2
));
64 connection_or_remove_from_ext_or_id_map(c2
);
65 tt_ptr_op(NULL
, OP_EQ
, connection_or_get_by_ext_or_id(idp
));
66 tt_ptr_op(NULL
, OP_EQ
, connection_or_get_by_ext_or_id(idp2
));
70 connection_free_minimal(TO_CONN(c1
));
72 connection_free_minimal(TO_CONN(c2
));
74 connection_free_minimal(TO_CONN(c3
));
77 connection_or_clear_ext_or_id_map();
80 /* Simple connection_write_to_buf_impl_ replacement that unconditionally
81 * writes to outbuf. */
83 connection_write_to_buf_impl_replacement(const char *string
, size_t len
,
84 connection_t
*conn
, int compressed
)
90 buf_add(conn
->outbuf
, string
, len
);
94 test_ext_or_write_command(void *arg
)
102 MOCK(connection_write_to_buf_impl_
,
103 connection_write_to_buf_impl_replacement
);
105 c1
= or_connection_new(CONN_TYPE_EXT_OR
, AF_INET
);
108 /* Length too long */
109 tt_int_op(connection_write_ext_or_command(TO_CONN(c1
), 100, "X", 100000),
113 tt_int_op(connection_write_ext_or_command(TO_CONN(c1
), 0x99, NULL
, 0),
115 cp
= buf_get_contents(TO_CONN(c1
)->outbuf
, &sz
);
116 tt_int_op(sz
, OP_EQ
, 4);
117 tt_mem_op(cp
, OP_EQ
, "\x00\x99\x00\x00", 4);
120 /* Medium command. */
121 tt_int_op(connection_write_ext_or_command(TO_CONN(c1
), 0x99,
122 "Wai\0Hello", 9), OP_EQ
, 0);
123 cp
= buf_get_contents(TO_CONN(c1
)->outbuf
, &sz
);
124 tt_int_op(sz
, OP_EQ
, 13);
125 tt_mem_op(cp
, OP_EQ
, "\x00\x99\x00\x09Wai\x00Hello", 13);
129 buf
= tor_malloc(65535);
130 memset(buf
, 'x', 65535);
131 tt_int_op(connection_write_ext_or_command(TO_CONN(c1
), 0xf00d,
132 buf
, 65535), OP_EQ
, 0);
133 cp
= buf_get_contents(TO_CONN(c1
)->outbuf
, &sz
);
134 tt_int_op(sz
, OP_EQ
, 65539);
135 tt_mem_op(cp
, OP_EQ
, "\xf0\x0d\xff\xff", 4);
136 tt_mem_op(cp
+4, OP_EQ
, buf
, 65535);
141 connection_free_minimal(TO_CONN(c1
));
144 UNMOCK(connection_write_to_buf_impl_
);
148 write_bytes_to_file_fail(const char *fname
, const char *str
, size_t len
,
160 test_ext_or_init_auth(void *arg
)
162 or_options_t
*options
= get_options_mutable();
169 /* Check default filename location */
170 tor_free(options
->DataDirectory
);
171 options
->DataDirectory
= tor_strdup("foo");
172 cp
= get_ext_or_auth_cookie_file_name();
173 tt_str_op(cp
, OP_EQ
, "foo"PATH_SEPARATOR
"extended_orport_auth_cookie");
176 /* Shouldn't be initialized already, or our tests will be a bit
178 ext_or_auth_cookie
= tor_malloc_zero(32);
179 tt_assert(tor_mem_is_zero((char*)ext_or_auth_cookie
, 32));
181 /* Now make sure we use a temporary file */
182 fn
= get_fname("ext_cookie_file");
183 options
->ExtORPortCookieAuthFile
= tor_strdup(fn
);
184 cp
= get_ext_or_auth_cookie_file_name();
185 tt_str_op(cp
, OP_EQ
, fn
);
188 /* Test the initialization function with a broken
189 write_bytes_to_file(). See if the problem is handled properly. */
190 MOCK(write_bytes_to_file
, write_bytes_to_file_fail
);
191 tt_int_op(-1, OP_EQ
, init_ext_or_cookie_authentication(1));
192 tt_int_op(ext_or_auth_cookie_is_set
, OP_EQ
, 0);
193 UNMOCK(write_bytes_to_file
);
195 /* Now do the actual initialization. */
196 tt_int_op(0, OP_EQ
, init_ext_or_cookie_authentication(1));
197 tt_int_op(ext_or_auth_cookie_is_set
, OP_EQ
, 1);
198 cp
= read_file_to_str(fn
, RFTS_BIN
, &st
);
199 tt_ptr_op(cp
, OP_NE
, NULL
);
200 tt_u64_op((uint64_t)st
.st_size
, OP_EQ
, 64);
201 tt_mem_op(cp
,OP_EQ
, "! Extended ORPort Auth Cookie !\x0a", 32);
202 tt_mem_op(cp
+32,OP_EQ
, ext_or_auth_cookie
, 32);
203 memcpy(cookie0
, ext_or_auth_cookie
, 32);
204 tt_assert(!tor_mem_is_zero((char*)ext_or_auth_cookie
, 32));
206 /* Operation should be idempotent. */
207 tt_int_op(0, OP_EQ
, init_ext_or_cookie_authentication(1));
208 tt_mem_op(cookie0
,OP_EQ
, ext_or_auth_cookie
, 32);
212 ext_orport_free_all();
216 test_ext_or_cookie_auth(void *arg
)
218 char *reply
=NULL
, *reply2
=NULL
, *client_hash
=NULL
, *client_hash2
=NULL
;
220 char hmac1
[32], hmac2
[32];
222 const char client_nonce
[32] =
223 "Who is the third who walks alway";
224 char server_hash_input
[] =
225 "ExtORPort authentication server-to-client hash"
226 "Who is the third who walks alway"
227 "................................";
228 char client_hash_input
[] =
229 "ExtORPort authentication client-to-server hash"
230 "Who is the third who walks alway"
231 "................................";
235 tt_int_op(strlen(client_hash_input
), OP_EQ
, 46+32+32);
236 tt_int_op(strlen(server_hash_input
), OP_EQ
, 46+32+32);
238 ext_or_auth_cookie
= tor_malloc_zero(32);
239 memcpy(ext_or_auth_cookie
, "s beside you? When I count, ther", 32);
240 ext_or_auth_cookie_is_set
= 1;
242 /* For this authentication, the client sends 32 random bytes (ClientNonce)
243 * The server replies with 32 byte ServerHash and 32 byte ServerNonce,
244 * where ServerHash is:
245 * HMAC-SHA256(CookieString,
246 * "ExtORPort authentication server-to-client hash" | ClientNonce |
248 * The client must reply with 32-byte ClientHash, which we compute as:
249 * ClientHash is computed as:
250 * HMAC-SHA256(CookieString,
251 * "ExtORPort authentication client-to-server hash" | ClientNonce |
257 handle_client_auth_nonce(client_nonce
, 33, &client_hash
, &reply
,
260 handle_client_auth_nonce(client_nonce
, 31, &client_hash
, &reply
,
263 /* Now let's try this for real! */
265 handle_client_auth_nonce(client_nonce
, 32, &client_hash
, &reply
,
267 tt_int_op(reply_len
, OP_EQ
, 64);
268 tt_ptr_op(reply
, OP_NE
, NULL
);
269 tt_ptr_op(client_hash
, OP_NE
, NULL
);
270 /* Fill in the server nonce into the hash inputs... */
271 memcpy(server_hash_input
+46+32, reply
+32, 32);
272 memcpy(client_hash_input
+46+32, reply
+32, 32);
273 /* Check the HMACs are correct... */
274 crypto_hmac_sha256(hmac1
, (char*)ext_or_auth_cookie
, 32, server_hash_input
,
276 crypto_hmac_sha256(hmac2
, (char*)ext_or_auth_cookie
, 32, client_hash_input
,
278 tt_mem_op(hmac1
,OP_EQ
, reply
, 32);
279 tt_mem_op(hmac2
,OP_EQ
, client_hash
, 32);
281 /* Now do it again and make sure that the results are *different* */
283 handle_client_auth_nonce(client_nonce
, 32, &client_hash2
, &reply2
,
285 tt_mem_op(reply2
,OP_NE
, reply
, reply_len
);
286 tt_mem_op(client_hash2
,OP_NE
, client_hash
, 32);
287 /* But that this one checks out too. */
288 memcpy(server_hash_input
+46+32, reply2
+32, 32);
289 memcpy(client_hash_input
+46+32, reply2
+32, 32);
290 /* Check the HMACs are correct... */
291 crypto_hmac_sha256(hmac1
, (char*)ext_or_auth_cookie
, 32, server_hash_input
,
293 crypto_hmac_sha256(hmac2
, (char*)ext_or_auth_cookie
, 32, client_hash_input
,
295 tt_mem_op(hmac1
,OP_EQ
, reply2
, 32);
296 tt_mem_op(hmac2
,OP_EQ
, client_hash2
, 32);
300 tor_free(client_hash
);
302 tor_free(client_hash2
);
306 crypto_rand_return_tse_str(char *to
, size_t n
)
309 TT_FAIL(("Asked for %d bytes, not 32", (int)n
));
312 memcpy(to
, "te road There is always another ", 32);
316 test_ext_or_cookie_auth_testvec(void *arg
)
318 char *reply
=NULL
, *client_hash
=NULL
;
320 char *mem_op_hex_tmp
=NULL
;
322 const char client_nonce
[] = "But when I look ahead up the whi";
325 ext_or_auth_cookie
= tor_malloc_zero(32);
326 memcpy(ext_or_auth_cookie
, "Gliding wrapt in a brown mantle," , 32);
327 ext_or_auth_cookie_is_set
= 1;
329 MOCK(crypto_rand
, crypto_rand_return_tse_str
);
332 handle_client_auth_nonce(client_nonce
, 32, &client_hash
, &reply
,
334 tt_ptr_op(reply
, OP_NE
, NULL
);
335 tt_uint_op(reply_len
, OP_EQ
, 64);
336 tt_mem_op(reply
+32,OP_EQ
, "te road There is always another ", 32);
337 /* HMACSHA256("Gliding wrapt in a brown mantle,"
338 * "ExtORPort authentication server-to-client hash"
339 * "But when I look ahead up the write road There is always another ");
341 test_memeq_hex(reply
,
342 "ec80ed6e546d3b36fdfc22fe1315416b"
343 "029f1ade7610d910878b62eeb7403821");
344 /* HMACSHA256("Gliding wrapt in a brown mantle,"
345 * "ExtORPort authentication client-to-server hash"
346 * "But when I look ahead up the write road There is always another ");
347 * (Both values computed using Python CLI.)
349 test_memeq_hex(client_hash
,
350 "ab391732dd2ed968cd40c087d1b1f25b"
351 "33b3cd77ff79bd80c2074bbf438119a2");
356 tor_free(client_hash
);
357 tor_free(mem_op_hex_tmp
);
361 ignore_bootstrap_problem(const char *warn
, int reason
,
362 or_connection_t
*conn
)
369 static int is_reading
= 1;
370 static int handshake_start_called
= 0;
373 note_read_stopped(connection_t
*conn
)
379 note_read_started(connection_t
*conn
)
385 handshake_start(or_connection_t
*conn
, int receiving
)
387 if (!conn
|| !receiving
)
388 TT_FAIL(("Bad arguments to handshake_start"));
389 handshake_start_called
= 1;
395 buf_add(TO_CONN(conn)->inbuf, (s), (n)); \
397 #define CONTAINS(s,n) \
399 tt_int_op((n), OP_LE, sizeof(b)); \
400 tt_int_op(buf_datalen(TO_CONN(conn)->outbuf), OP_EQ, (n)); \
402 buf_get_bytes(TO_CONN(conn)->outbuf, b, (n)); \
403 tt_mem_op(b, OP_EQ, (s), (n)); \
407 /* Helper: Do a successful Extended ORPort authentication handshake. */
409 do_ext_or_handshake(or_connection_t
*conn
)
413 tt_int_op(0, OP_EQ
, connection_ext_or_start_auth(conn
));
414 CONTAINS("\x01\x00", 2);
416 WRITE("But when I look ahead up the whi", 32);
417 MOCK(crypto_rand
, crypto_rand_return_tse_str
);
418 tt_int_op(0, OP_EQ
, connection_ext_or_process_inbuf(conn
));
420 tt_int_op(TO_CONN(conn
)->state
, OP_EQ
,
421 EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH
);
422 CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
423 "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
424 "te road There is always another ", 64);
425 /* Send the right response this time. */
426 WRITE("\xab\x39\x17\x32\xdd\x2e\xd9\x68\xcd\x40\xc0\x87\xd1\xb1\xf2\x5b"
427 "\x33\xb3\xcd\x77\xff\x79\xbd\x80\xc2\x07\x4b\xbf\x43\x81\x19\xa2",
429 tt_int_op(0, OP_EQ
, connection_ext_or_process_inbuf(conn
));
431 tt_assert(! TO_CONN(conn
)->marked_for_close
);
432 tt_int_op(TO_CONN(conn
)->state
, OP_EQ
, EXT_OR_CONN_STATE_OPEN
);
438 test_ext_or_handshake(void *arg
)
440 or_connection_t
*conn
=NULL
;
444 MOCK(connection_write_to_buf_impl_
,
445 connection_write_to_buf_impl_replacement
);
446 /* Use same authenticators as for test_ext_or_cookie_auth_testvec */
447 ext_or_auth_cookie
= tor_malloc_zero(32);
448 memcpy(ext_or_auth_cookie
, "Gliding wrapt in a brown mantle," , 32);
449 ext_or_auth_cookie_is_set
= 1;
451 tor_init_connection_lists();
453 conn
= or_connection_new(CONN_TYPE_EXT_OR
, AF_INET
);
454 tt_int_op(0, OP_EQ
, connection_ext_or_start_auth(conn
));
455 /* The server starts by telling us about the one supported authtype. */
456 CONTAINS("\x01\x00", 2);
457 /* Say the client hasn't responded yet. */
458 tt_int_op(0, OP_EQ
, connection_ext_or_process_inbuf(conn
));
459 /* Let's say the client replies badly. */
461 tt_int_op(-1, OP_EQ
, connection_ext_or_process_inbuf(conn
));
463 tt_assert(TO_CONN(conn
)->marked_for_close
);
464 close_closeable_connections();
467 /* Okay, try again. */
468 conn
= or_connection_new(CONN_TYPE_EXT_OR
, AF_INET
);
469 tt_int_op(0, OP_EQ
, connection_ext_or_start_auth(conn
));
470 CONTAINS("\x01\x00", 2);
471 /* Let's say the client replies sensibly this time. "Yes, AUTHTYPE_COOKIE
472 * sounds delicious. Let's have some of that!" */
474 /* Let's say that the client also sends part of a nonce. */
475 WRITE("But when I look ", 16);
476 tt_int_op(0, OP_EQ
, connection_ext_or_process_inbuf(conn
));
478 tt_int_op(TO_CONN(conn
)->state
, OP_EQ
,
479 EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE
);
480 /* Pump it again. Nothing should happen. */
481 tt_int_op(0, OP_EQ
, connection_ext_or_process_inbuf(conn
));
482 /* send the rest of the nonce. */
483 WRITE("ahead up the whi", 16);
484 MOCK(crypto_rand
, crypto_rand_return_tse_str
);
485 tt_int_op(0, OP_EQ
, connection_ext_or_process_inbuf(conn
));
487 /* We should get the right reply from the server. */
488 CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
489 "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
490 "te road There is always another ", 64);
491 /* Send the wrong response. */
492 WRITE("not with a bang but a whimper...", 32);
493 MOCK(control_event_bootstrap_prob_or
, ignore_bootstrap_problem
);
494 tt_int_op(-1, OP_EQ
, connection_ext_or_process_inbuf(conn
));
496 tt_assert(TO_CONN(conn
)->marked_for_close
);
497 /* XXXX Hold-open-until-flushed. */
498 close_closeable_connections();
500 UNMOCK(control_event_bootstrap_prob_or
);
502 MOCK(connection_start_reading
, note_read_started
);
503 MOCK(connection_stop_reading
, note_read_stopped
);
504 MOCK(connection_tls_start_handshake
, handshake_start
);
506 /* Okay, this time let's succeed. */
507 conn
= or_connection_new(CONN_TYPE_EXT_OR
, AF_INET
);
508 do_ext_or_handshake(conn
);
510 /* Now let's run through some messages. */
511 /* First let's send some junk and make sure it's ignored. */
512 WRITE("\xff\xf0\x00\x03""ABC", 7);
513 tt_int_op(0, OP_EQ
, connection_ext_or_process_inbuf(conn
));
515 /* Now let's send a USERADDR command. */
516 WRITE("\x00\x01\x00\x0c""1.2.3.4:5678", 16);
517 tt_int_op(0, OP_EQ
, connection_ext_or_process_inbuf(conn
));
518 tt_int_op(TO_CONN(conn
)->port
, OP_EQ
, 5678);
519 tt_int_op(tor_addr_to_ipv4h(&TO_CONN(conn
)->addr
), OP_EQ
, 0x01020304);
520 /* Now let's send a TRANSPORT command. */
521 WRITE("\x00\x02\x00\x07""rfc1149", 11);
522 tt_int_op(0, OP_EQ
, connection_ext_or_process_inbuf(conn
));
523 tt_ptr_op(NULL
, OP_NE
, conn
->ext_or_transport
);
524 tt_str_op("rfc1149", OP_EQ
, conn
->ext_or_transport
);
525 tt_int_op(is_reading
,OP_EQ
,1);
526 tt_int_op(TO_CONN(conn
)->state
, OP_EQ
, EXT_OR_CONN_STATE_OPEN
);
528 WRITE("\x00\x00\x00\x00", 4);
529 tt_int_op(0, OP_EQ
, connection_ext_or_process_inbuf(conn
));
530 tt_int_op(TO_CONN(conn
)->state
, OP_EQ
, EXT_OR_CONN_STATE_FLUSHING
);
531 tt_int_op(is_reading
,OP_EQ
,0);
532 CONTAINS("\x10\x00\x00\x00", 4);
533 tt_int_op(handshake_start_called
,OP_EQ
,0);
534 tt_int_op(0, OP_EQ
, connection_ext_or_finished_flushing(conn
));
535 tt_int_op(is_reading
,OP_EQ
,1);
536 tt_int_op(handshake_start_called
,OP_EQ
,1);
537 tt_int_op(TO_CONN(conn
)->type
, OP_EQ
, CONN_TYPE_OR
);
538 tt_int_op(TO_CONN(conn
)->state
, OP_EQ
, 0);
539 close_closeable_connections();
542 /* Okay, this time let's succeed the handshake but fail the USERADDR
544 conn
= or_connection_new(CONN_TYPE_EXT_OR
, AF_INET
);
545 do_ext_or_handshake(conn
);
546 /* USERADDR command with an extra NUL byte */
547 WRITE("\x00\x01\x00\x0d""1.2.3.4:5678\x00", 17);
548 MOCK(control_event_bootstrap_prob_or
, ignore_bootstrap_problem
);
549 tt_int_op(-1, OP_EQ
, connection_ext_or_process_inbuf(conn
));
551 tt_assert(TO_CONN(conn
)->marked_for_close
);
552 close_closeable_connections();
554 UNMOCK(control_event_bootstrap_prob_or
);
556 /* Now fail the TRANSPORT command. */
557 conn
= or_connection_new(CONN_TYPE_EXT_OR
, AF_INET
);
558 do_ext_or_handshake(conn
);
559 /* TRANSPORT command with an extra NUL byte */
560 WRITE("\x00\x02\x00\x08""rfc1149\x00", 12);
561 MOCK(control_event_bootstrap_prob_or
, ignore_bootstrap_problem
);
562 tt_int_op(-1, OP_EQ
, connection_ext_or_process_inbuf(conn
));
564 tt_assert(TO_CONN(conn
)->marked_for_close
);
565 close_closeable_connections();
567 UNMOCK(control_event_bootstrap_prob_or
);
569 /* Now fail the TRANSPORT command. */
570 conn
= or_connection_new(CONN_TYPE_EXT_OR
, AF_INET
);
571 do_ext_or_handshake(conn
);
572 /* TRANSPORT command with transport name with symbols (not a
574 WRITE("\x00\x02\x00\x07""rf*1149", 11);
575 MOCK(control_event_bootstrap_prob_or
, ignore_bootstrap_problem
);
576 tt_int_op(-1, OP_EQ
, connection_ext_or_process_inbuf(conn
));
578 tt_assert(TO_CONN(conn
)->marked_for_close
);
579 close_closeable_connections();
581 UNMOCK(control_event_bootstrap_prob_or
);
584 UNMOCK(connection_write_to_buf_impl_
);
587 connection_free_minimal(TO_CONN(conn
));
592 struct testcase_t extorport_tests
[] = {
593 { "id_map", test_ext_or_id_map
, TT_FORK
, NULL
, NULL
},
594 { "write_command", test_ext_or_write_command
, TT_FORK
, NULL
, NULL
},
595 { "init_auth", test_ext_or_init_auth
, TT_FORK
, NULL
, NULL
},
596 { "cookie_auth", test_ext_or_cookie_auth
, TT_FORK
, NULL
, NULL
},
597 { "cookie_auth_testvec", test_ext_or_cookie_auth_testvec
, TT_FORK
,
599 { "handshake", test_ext_or_handshake
, TT_FORK
, NULL
, NULL
},