]> git.saurik.com Git - apple/security.git/blob - protocol/SecProtocolTest.m
Security-59754.41.1.tar.gz
[apple/security.git] / protocol / SecProtocolTest.m
1 //
2 // SecProtocolTest.m
3 // SecureTransportTests
4 //
5
6 #import <AssertMacros.h>
7 #import <Foundation/Foundation.h>
8
9 #include <os/log.h>
10 #include <dlfcn.h>
11 #include <sys/param.h>
12
13 #import <XCTest/XCTest.h>
14
15 #import "SecProtocolConfiguration.h"
16 #import "SecProtocolPriv.h"
17 #import "SecProtocolInternal.h"
18
19 #import <nw/private.h> // Needed for the mock protocol
20
21 #define SEC_PROTOCOL_OPTIONS_VALIDATE(m, r) \
22 if (((void *)(m) == NULL) || ((size_t)(m) == 0)) { \
23 return (r); \
24 }
25
26 #define SEC_PROTOCOL_METADATA_VALIDATE(m, r) \
27 if (((void *)(m) == NULL) || ((size_t)(m) == 0)) { \
28 return (r); \
29 }
30
31 typedef struct mock_protocol {
32 struct nw_protocol protocol;
33 char *name;
34 } *mock_protocol_t;
35
36 static nw_protocol_t
37 _mock_protocol_create_extended(nw_protocol_identifier_const_t identifier,
38 nw_endpoint_t endpoint,
39 nw_parameters_t parameters)
40 {
41 mock_protocol_t handle = (mock_protocol_t)calloc(1, sizeof(struct mock_protocol));
42 if (handle == NULL) {
43 return NULL;
44 }
45
46 struct nw_protocol_callbacks *callbacks = (struct nw_protocol_callbacks *) malloc(sizeof(struct nw_protocol_callbacks));
47 memset(callbacks, 0, sizeof(struct nw_protocol_callbacks));
48
49 handle->protocol.callbacks = callbacks;
50 handle->protocol.handle = (void *)handle;
51
52 return &handle->protocol;
53 }
54
55 static bool
56 mock_protocol_register_extended(nw_protocol_identifier_const_t identifier,
57 nw_protocol_create_extended_f create_extended_function)
58 {
59 static void *libnetworkImage = NULL;
60 static dispatch_once_t onceToken;
61 static bool (*_nw_protocol_register_extended)(nw_protocol_identifier_const_t, nw_protocol_create_extended_f) = NULL;
62
63 dispatch_once(&onceToken, ^{
64 libnetworkImage = dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY | RTLD_LOCAL);
65 if (NULL != libnetworkImage) {
66 _nw_protocol_register_extended = (__typeof(_nw_protocol_register_extended))dlsym(libnetworkImage, "nw_protocol_register_extended");
67 if (NULL == _nw_protocol_register_extended) {
68 os_log_error(OS_LOG_DEFAULT, "dlsym libnetwork nw_protocol_register_extended");
69 }
70 } else {
71 os_log_error(OS_LOG_DEFAULT, "dlopen libnetwork");
72 }
73 });
74
75 if (_nw_protocol_register_extended == NULL) {
76 return false;
77 }
78
79 return _nw_protocol_register_extended(identifier, create_extended_function);
80 }
81
82 static nw_protocol_identifier_t
83 _mock_protocol_identifier(const char *name, size_t name_len)
84 {
85 static struct nw_protocol_identifier mock_identifer = {};
86 static dispatch_once_t onceToken = 0;
87 dispatch_once(&onceToken, ^{
88 memset(&mock_identifer, 0, sizeof(mock_identifer));
89
90 strlcpy((char *)mock_identifer.name, name, name_len);
91
92 mock_identifer.level = nw_protocol_level_application;
93 mock_identifer.mapping = nw_protocol_mapping_one_to_one;
94
95 mock_protocol_register_extended(&mock_identifer, _mock_protocol_create_extended);
96 });
97
98 return &mock_identifer;
99 }
100
101 static void * _Nullable
102 mock_protocol_allocate_metadata(__unused nw_protocol_definition_t definition)
103 {
104 return calloc(1, sizeof(struct sec_protocol_metadata_content));
105 }
106
107 static void
108 mock_protocol_deallocate_metadata(__unused nw_protocol_definition_t definition, void *metadata)
109 {
110 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)metadata;
111 if (content) {
112 // pass
113 }
114 free(content);
115 }
116
117 static void
118 mock_protocol_set_metadata_allocator(nw_protocol_definition_t definition, nw_protocol_definition_allocate_f allocator, nw_protocol_definition_deallocate_f deallocator)
119 {
120 static void *libnetworkImage = NULL;
121 static dispatch_once_t onceToken;
122 static void (*_nw_protocol_definition_set_metadata_allocator)(nw_protocol_definition_t, nw_protocol_definition_allocate_f, nw_protocol_definition_deallocate_f) = NULL;
123
124 dispatch_once(&onceToken, ^{
125 libnetworkImage = dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY | RTLD_LOCAL);
126 if (NULL != libnetworkImage) {
127 _nw_protocol_definition_set_metadata_allocator = (__typeof(_nw_protocol_definition_set_metadata_allocator))dlsym(libnetworkImage, "nw_protocol_definition_set_metadata_allocator");
128 if (NULL == _nw_protocol_definition_set_metadata_allocator) {
129 os_log_error(OS_LOG_DEFAULT, "dlsym libnetwork nw_protocol_definition_set_metadata_allocator");
130 }
131 } else {
132 os_log_error(OS_LOG_DEFAULT, "dlopen libnetwork");
133 }
134 });
135
136 if (_nw_protocol_definition_set_metadata_allocator == NULL) {
137 return;
138 }
139
140 _nw_protocol_definition_set_metadata_allocator(definition, allocator, deallocator);
141 }
142
143 static void * _Nullable
144 mock_protocol_copy_options(__unused nw_protocol_definition_t definition, void *options)
145 {
146 void *new_options = calloc(1, sizeof(struct sec_protocol_options_content));
147
148 sec_protocol_options_content_t copy = (sec_protocol_options_content_t)new_options;
149 sec_protocol_options_content_t original = (sec_protocol_options_content_t)options;
150
151 copy->min_version = original->min_version;
152 copy->max_version = original->max_version;
153 copy->disable_sni = original->disable_sni;
154 copy->enable_fallback_attempt = original->enable_fallback_attempt;
155 copy->enable_false_start = original->enable_false_start;
156 copy->enable_tickets = original->enable_tickets;
157 copy->enable_sct = original->enable_sct;
158 copy->enable_ocsp = original->enable_ocsp;
159 copy->enable_resumption = original->enable_resumption;
160 copy->enable_renegotiation = original->enable_renegotiation;
161 copy->enable_early_data = original->enable_early_data;
162
163 if (original->server_name) {
164 copy->server_name = strdup(original->server_name);
165 }
166 if (original->identity) {
167 copy->identity = original->identity;
168 }
169 if (original->application_protocols) {
170 copy->application_protocols = xpc_copy(original->application_protocols);
171 }
172 if (original->ciphersuites) {
173 copy->ciphersuites = xpc_copy(original->ciphersuites);
174 }
175 if (original->dh_params) {
176 copy->dh_params = original->dh_params;
177 }
178 if (original->key_update_block) {
179 copy->key_update_block = original->key_update_block;
180 copy->key_update_queue = original->key_update_queue;
181 }
182 if (original->challenge_block) {
183 copy->challenge_block = original->challenge_block;
184 copy->challenge_queue = original->challenge_queue;
185 }
186 if (original->verify_block) {
187 copy->verify_block = original->verify_block;
188 copy->verify_queue = original->verify_queue;
189 }
190 if (original->session_state) {
191 copy->session_state = original->session_state;
192 }
193 if (original->session_update_block) {
194 copy->session_update_block = original->session_update_block;
195 copy->session_update_queue = original->session_update_queue;
196 }
197 if (original->pre_shared_keys) {
198 copy->pre_shared_keys = xpc_copy(original->pre_shared_keys);
199 }
200
201 return new_options;
202 }
203
204 static void * _Nullable
205 mock_protocol_allocate_options(__unused nw_protocol_definition_t definition)
206 {
207 return calloc(1, sizeof(struct sec_protocol_options_content));
208 }
209
210 static void
211 mock_protocol_deallocate_options(__unused nw_protocol_definition_t definition, void *options)
212 {
213 sec_protocol_options_content_t content = (sec_protocol_options_content_t)options;
214 if (content) {
215 // pass
216 }
217 free(content);
218 }
219
220 static void
221 mock_protocol_set_options_allocator(nw_protocol_definition_t definition,
222 nw_protocol_definition_allocate_f allocate_function,
223 nw_protocol_definition_copy_f copy_function,
224 nw_protocol_definition_deallocate_f deallocate_function)
225 {
226 static void *libnetworkImage = NULL;
227 static dispatch_once_t onceToken;
228 static void (*_nw_protocol_definition_set_options_allocator)(nw_protocol_definition_t, nw_protocol_definition_allocate_f, nw_protocol_definition_copy_f, nw_protocol_definition_deallocate_f) = NULL;
229
230 dispatch_once(&onceToken, ^{
231 libnetworkImage = dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY | RTLD_LOCAL);
232 if (NULL != libnetworkImage) {
233 _nw_protocol_definition_set_options_allocator = (__typeof(_nw_protocol_definition_set_options_allocator))dlsym(libnetworkImage, "nw_protocol_definition_set_options_allocator");
234 if (NULL == _nw_protocol_definition_set_options_allocator) {
235 os_log_error(OS_LOG_DEFAULT, "dlsym libnetwork nw_protocol_definition_set_options_allocator");
236 }
237 } else {
238 os_log_error(OS_LOG_DEFAULT, "dlopen libnetwork");
239 }
240 });
241
242 if (_nw_protocol_definition_set_options_allocator == NULL) {
243 return;
244 }
245
246 _nw_protocol_definition_set_options_allocator(definition, allocate_function, copy_function, deallocate_function);
247 }
248
249 static nw_protocol_definition_t
250 mock_protocol_definition_create_with_identifier(nw_protocol_identifier_const_t identifier)
251 {
252 static void *libnetworkImage = NULL;
253 static dispatch_once_t onceToken;
254 static nw_protocol_definition_t (*_nw_protocol_definition_create_with_identifier)(nw_protocol_identifier_const_t) = NULL;
255
256 dispatch_once(&onceToken, ^{
257 libnetworkImage = dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY | RTLD_LOCAL);
258 if (NULL != libnetworkImage) {
259 _nw_protocol_definition_create_with_identifier = (__typeof(_nw_protocol_definition_create_with_identifier))dlsym(libnetworkImage, "nw_protocol_definition_create_with_identifier");
260 if (NULL == _nw_protocol_definition_create_with_identifier) {
261 os_log_error(OS_LOG_DEFAULT, "dlsym libnetwork nw_protocol_definition_create_with_identifier");
262 }
263 } else {
264 os_log_error(OS_LOG_DEFAULT, "dlopen libnetwork");
265 }
266 });
267
268 if (_nw_protocol_definition_create_with_identifier == NULL) {
269 return NULL;
270 }
271
272 return _nw_protocol_definition_create_with_identifier(identifier);
273 }
274
275 static nw_protocol_definition_t
276 mock_protocol_copy_definition(void)
277 {
278 static nw_protocol_definition_t definition = NULL;
279 static dispatch_once_t onceToken;
280 dispatch_once(&onceToken, ^{
281 const char *mock_protocol_name = "secProtocolTestMockProtocol";
282 definition = mock_protocol_definition_create_with_identifier(_mock_protocol_identifier(mock_protocol_name, strlen(mock_protocol_name)));
283 mock_protocol_set_options_allocator(definition,
284 mock_protocol_allocate_options,
285 mock_protocol_copy_options,
286 mock_protocol_deallocate_options);
287 mock_protocol_set_metadata_allocator(definition,
288 mock_protocol_allocate_metadata,
289 mock_protocol_deallocate_metadata);
290
291 });
292
293 return definition;
294 }
295
296 @interface SecProtocolTest : XCTestCase
297 @property nw_protocol_t mock_protocol;
298 @end
299
300 @implementation SecProtocolTest
301
302 - (void)setUp {
303 [super setUp];
304 }
305
306 - (void)tearDown {
307 [super tearDown];
308 }
309
310 - (sec_protocol_options_t)create_sec_protocol_options {
311 static void *libnetworkImage = NULL;
312 static dispatch_once_t onceToken;
313
314 static sec_protocol_options_t (*_nw_protocol_create_options)(nw_protocol_definition_t) = NULL;
315
316 dispatch_once(&onceToken, ^{
317 libnetworkImage = dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY | RTLD_LOCAL);
318 if (NULL != libnetworkImage) {
319 _nw_protocol_create_options = (__typeof(_nw_protocol_create_options))dlsym(libnetworkImage, "nw_protocol_create_options");
320 if (NULL == _nw_protocol_create_options) {
321 os_log_error(OS_LOG_DEFAULT, "dlsym libnetwork _nw_protocol_create_options");
322 }
323 } else {
324 os_log_error(OS_LOG_DEFAULT, "dlopen libnetwork");
325 }
326 });
327
328 if (_nw_protocol_create_options == NULL) {
329 return nil;
330 }
331
332 return (sec_protocol_options_t)_nw_protocol_create_options(mock_protocol_copy_definition());
333 }
334
335 - (sec_protocol_metadata_t)create_sec_protocol_metadata {
336 uuid_t identifier;
337 uuid_generate(identifier);
338
339 static void *libnetworkImage = NULL;
340 static dispatch_once_t onceToken;
341 static sec_protocol_metadata_t (*_nw_protocol_metadata_create)(nw_protocol_definition_t, _Nonnull uuid_t) = NULL;
342
343 dispatch_once(&onceToken, ^{
344 libnetworkImage = dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY | RTLD_LOCAL);
345 if (NULL != libnetworkImage) {
346 _nw_protocol_metadata_create = (__typeof(_nw_protocol_metadata_create))dlsym(libnetworkImage, "nw_protocol_metadata_create");
347 if (NULL == _nw_protocol_metadata_create) {
348 os_log_error(OS_LOG_DEFAULT, "dlsym libnetwork nw_protocol_metadata_create");
349 }
350 } else {
351 os_log_error(OS_LOG_DEFAULT, "dlopen libnetwork");
352 }
353 });
354
355 if (_nw_protocol_metadata_create == NULL) {
356 return nil;
357 }
358
359 return (sec_protocol_metadata_t)_nw_protocol_metadata_create(mock_protocol_copy_definition(), identifier);
360 }
361
362 - (void)test_sec_protocol_metadata_get_connection_strength_tls12 {
363 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
364
365 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
366 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
367 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
368
369 content->negotiated_ciphersuite = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
370 #pragma clang diagnostic push
371 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
372 content->negotiated_protocol_version = kTLSProtocol12;
373 #pragma clang diagnostic pop
374
375 return true;
376 });
377
378 XCTAssertTrue(SSLConnectionStrengthStrong == sec_protocol_metadata_get_connection_strength(metadata),
379 "Expected SSLConnectionStrengthStrong for TLS 1.2 with a strong ciphersuite, got %d", (int)sec_protocol_metadata_get_connection_strength(metadata));
380 }
381
382 - (void)test_sec_protocol_metadata_get_connection_strength_tls12_weak_ciphersuite {
383 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
384 if (metadata) {
385 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
386 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
387 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
388
389 content->negotiated_ciphersuite = TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
390 #pragma clang diagnostic push
391 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
392 content->negotiated_protocol_version = kTLSProtocol12;
393 #pragma clang diagnostic pop
394
395 return true;
396 });
397
398 XCTAssertTrue(SSLConnectionStrengthWeak == sec_protocol_metadata_get_connection_strength(metadata),
399 "Expected SSLConnectionStrengthWeak for TLS 1.2 with a weak ciphersuite, got %d", (int)sec_protocol_metadata_get_connection_strength(metadata));
400 }
401 }
402
403 - (void)test_sec_protocol_metadata_get_connection_strength_tls11 {
404 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
405 if (metadata) {
406 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
407 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
408 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
409
410 content->negotiated_ciphersuite = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
411 #pragma clang diagnostic push
412 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
413 content->negotiated_protocol_version = kTLSProtocol11;
414 #pragma clang diagnostic pop
415
416 return true;
417 });
418
419 XCTAssertTrue(SSLConnectionStrengthWeak == sec_protocol_metadata_get_connection_strength(metadata),
420 "Expected SSLConnectionStrengthWeak for TLS 1.1, got %d", (int)sec_protocol_metadata_get_connection_strength(metadata));
421 }
422 }
423
424 - (void)test_sec_protocol_metadata_get_connection_strength_tls10 {
425 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
426 if (metadata) {
427 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
428 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
429 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
430
431 content->negotiated_ciphersuite = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
432 #pragma clang diagnostic push
433 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
434 content->negotiated_protocol_version = kTLSProtocol1;
435 #pragma clang diagnostic pop
436
437 return true;
438 });
439
440 XCTAssertTrue(SSLConnectionStrengthWeak == sec_protocol_metadata_get_connection_strength(metadata),
441 "Expected SSLConnectionStrengthWeak for TLS 1.0, got %d", (int)sec_protocol_metadata_get_connection_strength(metadata));
442 }
443 }
444
445 - (void)test_sec_protocol_metadata_get_connection_strength_sslv3_strong_ciphersuite {
446 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
447 if (metadata) {
448 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
449 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
450 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
451
452 content->negotiated_ciphersuite = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; // This can be anything -- we downgrade based on the version here.
453 #pragma clang diagnostic push
454 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
455 content->negotiated_protocol_version = kSSLProtocol3;
456 #pragma clang diagnostic pop
457
458 return true;
459 });
460
461 XCTAssertTrue(SSLConnectionStrengthNonsecure == sec_protocol_metadata_get_connection_strength(metadata),
462 "Expected SSLConnectionStrengthNonsecure for SSL 3.0, got %d", (int)sec_protocol_metadata_get_connection_strength(metadata));
463 }
464 }
465
466 - (void)test_sec_protocol_metadata_get_connection_strength_sslv3_weak_ciphersuite {
467 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
468 if (metadata) {
469 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
470 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
471 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
472
473 content->negotiated_ciphersuite = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
474 #pragma clang diagnostic push
475 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
476 content->negotiated_protocol_version = kSSLProtocol3;
477 #pragma clang diagnostic pop
478
479 return true;
480 });
481
482 XCTAssertTrue(SSLConnectionStrengthNonsecure == sec_protocol_metadata_get_connection_strength(metadata),
483 "Expected SSLConnectionStrengthNonsecure for SSL 3.0, got %d", (int)sec_protocol_metadata_get_connection_strength(metadata));
484 }
485 }
486
487 static size_t
488 _sec_protocol_dispatch_data_copyout(dispatch_data_t data, void *destination, size_t maxlen)
489 {
490 __block size_t copied = 0;
491 __block uint8_t *buffer = (uint8_t *)destination;
492
493 if (data) {
494 dispatch_data_apply(data, ^bool(__unused dispatch_data_t region, __unused size_t offset, const void *dbuffer, size_t size) {
495 size_t consumed = MIN(maxlen - copied, size);
496 if (consumed) {
497 memcpy(&buffer[copied], dbuffer, consumed);
498 copied += consumed;
499 }
500
501 return copied < maxlen;
502 });
503 }
504
505 return copied;
506 }
507
508 static dispatch_data_t
509 _sec_protocol_test_metadata_session_exporter(void *handle)
510 {
511 if (handle == NULL) {
512 return nil;
513 }
514
515 const char *received_handle = (const char *)handle;
516 dispatch_data_t serialized_session = dispatch_data_create(received_handle, strlen(received_handle), NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
517 return serialized_session;
518 }
519
520 - (void)test_sec_protocol_register_session_update {
521 sec_protocol_options_t options = [self create_sec_protocol_options];
522 dispatch_queue_t test_queue = dispatch_queue_create("test_sec_protocol_register_session_update", NULL);
523 __block bool session_updated = false;
524
525 __block dispatch_data_t serialized_session_copy = nil;
526 sec_protocol_session_update_t update_block = ^(sec_protocol_metadata_t metadata) {
527 session_updated = true;
528 serialized_session_copy = sec_protocol_metadata_copy_serialized_session(metadata);
529 };
530
531 sec_protocol_options_set_session_update_block(options, update_block, test_queue);
532
533 const char *metadata_context_handle = "context handle";
534
535 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
536 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
537 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
538 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
539
540 content->session_exporter_context = (void *)metadata_context_handle;
541 content->session_exporter_function = _sec_protocol_test_metadata_session_exporter;
542
543 return true;
544 });
545
546 update_block(metadata);
547
548 XCTAssertTrue(session_updated, "Expected session update callback block to fire");
549 XCTAssertNotNil(serialized_session_copy, "Expected non-nil serialized session");
550
551 if (serialized_session_copy) {
552 size_t data_size = dispatch_data_get_size(serialized_session_copy);
553 uint8_t *session_copy_buffer = (uint8_t *)malloc(data_size);
554
555 (void)_sec_protocol_dispatch_data_copyout(serialized_session_copy, session_copy_buffer, data_size);
556 XCTAssertTrue(data_size == strlen(metadata_context_handle));
557 XCTAssertTrue(memcmp(session_copy_buffer, metadata_context_handle, data_size) == 0);
558
559 free(session_copy_buffer);
560 }
561 }
562
563 #define SEC_PROTOCOL_METADATA_KEY_FAILURE_STACK_ERROR "stack_error"
564 #define SEC_PROTOCOL_METADATA_KEY_CIPHERSUITE "cipher_name"
565
566 - (void)test_sec_protocol_metadata_serialize_success {
567 sec_protocol_options_t options = [self create_sec_protocol_options];
568 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
569 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
570 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
571 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
572
573 content->failure = false;
574 content->stack_error = 0xDEAD;
575 content->negotiated_ciphersuite = TLS_AES_256_GCM_SHA384;
576 return true;
577 });
578
579 xpc_object_t dictionary = sec_protocol_metadata_serialize_with_options(metadata, options);
580 XCTAssertTrue(dictionary != NULL);
581 XCTAssertTrue(xpc_dictionary_get_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_FAILURE_STACK_ERROR) == 0x00,
582 "Expected 0x%x, got 0x%llx", 0x00, xpc_dictionary_get_int64(dictionary, SEC_PROTOCOL_METADATA_KEY_FAILURE_STACK_ERROR));
583 XCTAssertTrue(xpc_dictionary_get_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_CIPHERSUITE) == TLS_AES_256_GCM_SHA384,
584 "Expected 0x%x, got 0x%llx", TLS_AES_256_GCM_SHA384, xpc_dictionary_get_int64(dictionary, SEC_PROTOCOL_METADATA_KEY_CIPHERSUITE));
585 }
586
587 - (void)test_sec_protocol_metadata_serialize_failure {
588 sec_protocol_options_t options = [self create_sec_protocol_options];
589 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
590 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
591 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
592 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
593
594 content->failure = true;
595 content->stack_error = 0xDEAD;
596 content->negotiated_ciphersuite = TLS_AES_256_GCM_SHA384;
597 return true;
598 });
599
600 xpc_object_t dictionary = sec_protocol_metadata_serialize_with_options(metadata, options);
601 XCTAssertTrue(dictionary != NULL);
602 XCTAssertTrue(xpc_dictionary_get_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_FAILURE_STACK_ERROR) == 0xDEAD,
603 "Expected 0x%x, got 0x%llx", 0xDEAD, xpc_dictionary_get_int64(dictionary, SEC_PROTOCOL_METADATA_KEY_FAILURE_STACK_ERROR));
604 XCTAssertTrue(xpc_dictionary_get_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_CIPHERSUITE) == 0x00,
605 "Expected 0x%x, got 0x%llx", 0x00, xpc_dictionary_get_int64(dictionary, SEC_PROTOCOL_METADATA_KEY_CIPHERSUITE));
606 }
607
608 - (void)test_sec_protocol_options_set_quic_transport_parameters {
609 uint8_t parameters_buffer[] = {0x00, 0x01, 0x02, 0x03};
610 uint8_t expected_parameters_buffer[sizeof(parameters_buffer)] = {0};
611
612 __block size_t parameters_len = sizeof(parameters_buffer);
613 __block uint8_t *parameters = parameters_buffer;
614 __block uint8_t *expected_parameters = expected_parameters_buffer;
615 __block dispatch_data_t parameters_data = dispatch_data_create(parameters, sizeof(parameters_buffer), NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
616
617 sec_protocol_options_t options = [self create_sec_protocol_options];
618 sec_protocol_options_set_quic_transport_parameters(options, parameters_data);
619
620 bool result = sec_protocol_options_access_handle(options, ^bool(void *handle) {
621 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
622 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
623
624 if (content->quic_transport_parameters) {
625 dispatch_data_t actual_parameters = content->quic_transport_parameters;
626 size_t data_len = _sec_protocol_dispatch_data_copyout(actual_parameters, expected_parameters, parameters_len);
627
628 if (data_len == parameters_len) {
629 return 0 == memcmp(parameters, expected_parameters, parameters_len);
630 }
631 }
632
633 return false;
634 });
635
636 XCTAssertTrue(result);
637 }
638
639 - (void)test_sec_protocol_metadata_copy_quic_transport_parameters {
640 uint8_t parameters_buffer[] = {0x00, 0x01, 0x02, 0x03};
641 uint8_t expected_parameters_buffer[sizeof(parameters_buffer)] = {0};
642
643 __block size_t parameters_len = sizeof(parameters_buffer);
644 __block uint8_t *parameters = parameters_buffer;
645 __block uint8_t *expected_parameters = expected_parameters_buffer;
646 __block dispatch_data_t parameters_data = dispatch_data_create(parameters, sizeof(parameters_buffer), NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
647
648 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
649 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
650 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
651 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
652
653 content->quic_transport_parameters = parameters_data;
654 return true;
655 });
656
657 dispatch_data_t actual_parameters = sec_protocol_metadata_copy_quic_transport_parameters(metadata);
658 size_t data_len = _sec_protocol_dispatch_data_copyout(actual_parameters, expected_parameters, parameters_len);
659
660 bool result = false;
661 if (data_len == parameters_len) {
662 result = 0 == memcmp(parameters, expected_parameters, parameters_len);
663 }
664 XCTAssertTrue(result);
665 }
666
667 - (void)test_sec_protocol_options_set_tls_encryption_secret_update_block {
668 void (^update_block)(sec_protocol_tls_encryption_level_t, bool, dispatch_data_t) = ^(__unused sec_protocol_tls_encryption_level_t level, __unused bool is_write, __unused dispatch_data_t secret) {
669 // pass
670 };
671
672 dispatch_queue_t update_queue = dispatch_queue_create("test_sec_protocol_options_set_tls_encryption_secret_update_block_queue", DISPATCH_QUEUE_SERIAL);
673
674 sec_protocol_options_t options = [self create_sec_protocol_options];
675 sec_protocol_options_set_tls_encryption_secret_update_block(options, update_block, update_queue);
676 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
677 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
678 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
679 XCTAssertTrue(content->tls_secret_update_block == update_block);
680 XCTAssertTrue(content->tls_secret_update_queue != nil);
681 return false;
682 });
683 }
684
685 - (void)test_sec_protocol_options_set_tls_encryption_level_update_block {
686 void (^update_block)(sec_protocol_tls_encryption_level_t, bool) = ^(__unused sec_protocol_tls_encryption_level_t level, __unused bool is_write) {
687 // pass
688 };
689
690 dispatch_queue_t update_queue = dispatch_queue_create("test_sec_protocol_options_set_tls_encryption_level_update_block_queue", DISPATCH_QUEUE_SERIAL);
691
692 sec_protocol_options_t options = [self create_sec_protocol_options];
693 sec_protocol_options_set_tls_encryption_level_update_block(options, update_block, update_queue);
694 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
695 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
696 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
697 XCTAssertTrue(content->tls_encryption_level_update_block == update_block);
698 XCTAssertTrue(content->tls_encryption_level_update_queue != nil);
699 return false;
700 });
701 }
702
703 - (void)test_sec_protocol_options_set_local_certificates {
704 sec_protocol_options_t options = [self create_sec_protocol_options];
705
706 sec_array_t certificates = sec_array_create();
707 sec_protocol_options_set_local_certificates(options, certificates);
708
709 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
710 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
711 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
712 XCTAssertTrue(content->certificates == certificates);
713 return true;
714 });
715 }
716
717 - (void)test_sec_protocol_options_set_private_key_blocks {
718 sec_protocol_options_t options = [self create_sec_protocol_options];
719
720 void (^sign_block)(uint16_t algorithm, dispatch_data_t, sec_protocol_private_key_complete_t) = ^(__unused uint16_t algorithm, __unused dispatch_data_t input, __unused sec_protocol_private_key_complete_t complete) {
721 // pass
722 };
723 void (^decrypt_block)(dispatch_data_t, sec_protocol_private_key_complete_t) = ^(__unused dispatch_data_t input, __unused sec_protocol_private_key_complete_t complete) {
724 // pass
725 };
726 dispatch_queue_t queue = dispatch_queue_create("private_key_operation_queue", DISPATCH_QUEUE_SERIAL);
727
728 sec_protocol_options_set_private_key_blocks(options, sign_block, decrypt_block, queue);
729 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
730 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
731 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
732 XCTAssertTrue(content->private_key_sign_block == sign_block);
733 XCTAssertTrue(content->private_key_decrypt_block == decrypt_block);
734 XCTAssertTrue(content->private_key_queue == queue);
735 return true;
736 });
737 }
738
739 - (void)test_sec_protocol_options_set_tls_certificate_compression_enabled {
740 sec_protocol_options_t options = [self create_sec_protocol_options];
741
742 sec_protocol_options_set_tls_certificate_compression_enabled(options, true);
743 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
744 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
745 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
746 XCTAssertTrue(content->certificate_compression_enabled);
747 return true;
748 });
749 }
750
751 - (void)test_sec_protocol_options_set_peer_authentication_required {
752 sec_protocol_options_t options = [self create_sec_protocol_options];
753
754 sec_protocol_options_set_peer_authentication_required(options, true);
755 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
756 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
757 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
758 XCTAssertTrue(content->peer_authentication_required);
759 return true;
760 });
761 }
762
763 - (void)test_sec_protocol_options_set_peer_authentication_optional {
764 sec_protocol_options_t options = [self create_sec_protocol_options];
765
766 sec_protocol_options_set_peer_authentication_optional(options, true);
767 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
768 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
769 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
770 XCTAssertTrue(content->peer_authentication_optional);
771 return true;
772 });
773 }
774
775 - (void)test_sec_protocol_options_are_equal {
776 sec_protocol_options_t optionsA = [self create_sec_protocol_options];
777 sec_protocol_options_t optionsB = [self create_sec_protocol_options];
778
779 #pragma clang diagnostic push
780 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
781 sec_protocol_options_set_tls_min_version(optionsA, kTLSProtocol13);
782 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
783 sec_protocol_options_set_tls_min_version(optionsB, kTLSProtocol13);
784 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
785
786 sec_protocol_options_set_tls_max_version(optionsA, kTLSProtocol13);
787 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
788 sec_protocol_options_set_tls_max_version(optionsB, kTLSProtocol13);
789 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
790 #pragma clang diagnostic pop
791
792 sec_protocol_options_set_tls_sni_disabled(optionsA, true);
793 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
794 sec_protocol_options_set_tls_sni_disabled(optionsB, false);
795 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
796 sec_protocol_options_set_tls_sni_disabled(optionsB, true);
797 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
798
799 sec_protocol_options_set_tls_is_fallback_attempt(optionsA, true);
800 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
801 sec_protocol_options_set_tls_is_fallback_attempt(optionsB, false);
802 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
803 sec_protocol_options_set_tls_is_fallback_attempt(optionsB, true);
804 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
805
806 sec_protocol_options_set_tls_false_start_enabled(optionsA, true);
807 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
808 sec_protocol_options_set_tls_false_start_enabled(optionsB, false);
809 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
810 sec_protocol_options_set_tls_false_start_enabled(optionsB, true);
811 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
812
813 sec_protocol_options_set_tls_tickets_enabled(optionsA, true);
814 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
815 sec_protocol_options_set_tls_tickets_enabled(optionsB, false);
816 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
817 sec_protocol_options_set_tls_tickets_enabled(optionsB, true);
818 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
819
820 sec_protocol_options_set_tls_sct_enabled(optionsA, true);
821 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
822 sec_protocol_options_set_tls_sct_enabled(optionsB, false);
823 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
824 sec_protocol_options_set_tls_sct_enabled(optionsB, true);
825 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
826
827 sec_protocol_options_set_tls_ocsp_enabled(optionsA, true);
828 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
829 sec_protocol_options_set_tls_ocsp_enabled(optionsB, false);
830 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
831 sec_protocol_options_set_tls_ocsp_enabled(optionsB, true);
832 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
833
834 sec_protocol_options_set_tls_resumption_enabled(optionsA, true);
835 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
836 sec_protocol_options_set_tls_resumption_enabled(optionsB, false);
837 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
838 sec_protocol_options_set_tls_resumption_enabled(optionsB, true);
839 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
840
841 sec_protocol_options_set_tls_renegotiation_enabled(optionsA, true);
842 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
843 sec_protocol_options_set_tls_renegotiation_enabled(optionsB, false);
844 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
845 sec_protocol_options_set_tls_renegotiation_enabled(optionsB, true);
846 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
847
848 sec_protocol_options_set_tls_grease_enabled(optionsA, true);
849 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
850 sec_protocol_options_set_tls_grease_enabled(optionsB, false);
851 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
852 sec_protocol_options_set_tls_grease_enabled(optionsB, true);
853 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
854
855 sec_protocol_options_set_tls_delegated_credentials_enabled(optionsA, true);
856 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
857 sec_protocol_options_set_tls_delegated_credentials_enabled(optionsB, false);
858 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
859 sec_protocol_options_set_tls_delegated_credentials_enabled(optionsB, true);
860 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
861
862 sec_protocol_options_set_eddsa_enabled(optionsA, true);
863 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
864 sec_protocol_options_set_eddsa_enabled(optionsB, false);
865 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
866 sec_protocol_options_set_eddsa_enabled(optionsB, true);
867 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
868
869 sec_protocol_options_set_tls_early_data_enabled(optionsA, true);
870 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
871 sec_protocol_options_set_tls_early_data_enabled(optionsB, false);
872 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
873 sec_protocol_options_set_tls_early_data_enabled(optionsB, true);
874 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
875
876 sec_protocol_options_set_tls_certificate_compression_enabled(optionsA, true);
877 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
878 sec_protocol_options_set_tls_certificate_compression_enabled(optionsB, false);
879 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
880 sec_protocol_options_set_tls_certificate_compression_enabled(optionsB, true);
881 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
882
883 const char *server_nameA = "localhost";
884 const char *server_nameB = "apple.com";
885 sec_protocol_options_set_tls_server_name(optionsA, server_nameA);
886 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
887 sec_protocol_options_set_tls_server_name(optionsB, server_nameB);
888 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
889 sec_protocol_options_set_tls_server_name(optionsB, server_nameA);
890 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
891
892 uint8_t quic_parameters_buffer[] = {0x00, 0x01, 0x02, 0x03};
893 dispatch_data_t quic_parameters = dispatch_data_create(quic_parameters_buffer, sizeof(quic_parameters_buffer), nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
894 sec_protocol_options_set_quic_transport_parameters(optionsA, quic_parameters);
895 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
896 sec_protocol_options_set_quic_transport_parameters(optionsB, quic_parameters);
897 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
898
899 sec_protocol_options_append_tls_ciphersuite(optionsA, 1337);
900 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
901 sec_protocol_options_append_tls_ciphersuite(optionsB, 1337);
902 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
903
904 const char *application_protocolA = "h2";
905 sec_protocol_options_add_tls_application_protocol(optionsA, application_protocolA);
906 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
907 sec_protocol_options_add_tls_application_protocol(optionsB, application_protocolA);
908 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
909
910 const char *application_protocolB = "h3";
911 sec_protocol_options_add_transport_specific_application_protocol(optionsA, application_protocolB,
912 sec_protocol_transport_quic);
913 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
914 sec_protocol_options_add_transport_specific_application_protocol(optionsB, application_protocolB,
915 sec_protocol_transport_quic);
916 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
917
918
919 sec_protocol_options_append_tls_ciphersuite(optionsB, 7331);
920 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
921 }
922
923 - (void)test_sec_protocol_options_copy_transport_specific_application_protocol {
924 sec_protocol_options_t options = [self create_sec_protocol_options];
925
926 const char *application_protocol_dummy = "dummy";
927 const char *application_protocol_h2 = "h2";
928 const char *application_protocol_h3 = "h3";
929
930 sec_protocol_options_add_transport_specific_application_protocol(options, application_protocol_h2, sec_protocol_transport_tcp);
931 xpc_object_t protocols = sec_protocol_options_copy_transport_specific_application_protocol(options, sec_protocol_transport_quic);
932 XCTAssertFalse(protocols != NULL);
933 if (protocols != NULL) {
934 return;
935 }
936
937 sec_protocol_options_add_tls_application_protocol(options, application_protocol_dummy);
938 sec_protocol_options_add_transport_specific_application_protocol(options, application_protocol_h3, sec_protocol_transport_quic);
939
940 for (sec_protocol_transport_t t = sec_protocol_transport_any; t <= sec_protocol_transport_quic; t++) {
941 protocols = sec_protocol_options_copy_transport_specific_application_protocol(options, t);
942 XCTAssertFalse(protocols == NULL);
943 if (protocols == NULL) {
944 return;
945 }
946
947 const char *application_protocols_for_any[] = { application_protocol_h2, application_protocol_dummy, application_protocol_h3, };
948 // application_protocols_for_tcp includes application_protocol_dummy because "dummy" isn't tied to any transport.
949 const char *application_protocols_for_tcp[] = { application_protocol_h2, application_protocol_dummy, };
950 const char *application_protocols_for_quic[] = { application_protocol_dummy, application_protocol_h3, };
951
952 size_t count_of_application_protocols_for_transport[] = {
953 [sec_protocol_transport_any] = sizeof(application_protocols_for_any)/sizeof(application_protocols_for_any[0]),
954 [sec_protocol_transport_tcp] = sizeof(application_protocols_for_tcp)/sizeof(application_protocols_for_tcp[0]),
955 [sec_protocol_transport_quic] = sizeof(application_protocols_for_quic)/sizeof(application_protocols_for_quic[0]),
956 };
957
958 XCTAssertFalse(xpc_get_type(protocols) != XPC_TYPE_ARRAY);
959 if (xpc_get_type(protocols) != XPC_TYPE_ARRAY) {
960 return;
961 }
962
963 size_t protocols_count = xpc_array_get_count(protocols);
964 XCTAssertFalse(protocols_count != count_of_application_protocols_for_transport[t]);
965 if (protocols_count != count_of_application_protocols_for_transport[t]) {
966 return;
967 }
968
969 const char **application_protocols_for_transport[] = {
970 [sec_protocol_transport_any] = application_protocols_for_any,
971 [sec_protocol_transport_tcp] = application_protocols_for_tcp,
972 [sec_protocol_transport_quic] = application_protocols_for_quic,
973 };
974
975 for (size_t i = 0; i < protocols_count; i++) {
976 const char *protocol_name = xpc_array_get_string(protocols, i);
977 const char *expected_protocol_name = application_protocols_for_transport[t][i];
978 bool protocol_match = (strcmp(protocol_name, expected_protocol_name) == 0);
979
980 XCTAssertFalse(protocol_match == false);
981 if (protocol_match == false) {
982 return;
983 }
984 }
985 }
986 }
987
988 - (void)test_sec_protocol_options_set_tls_server_name {
989 sec_protocol_options_t optionsA = [self create_sec_protocol_options];
990 sec_protocol_options_t optionsB = [self create_sec_protocol_options];
991
992 const char *server_nameA = "apple.com";
993 const char *server_nameB = "example.com";
994
995 /*
996 * Empty options should be equal.
997 */
998 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
999
1000 /*
1001 * Set the name in optionsA.
1002 * Options A, B should now be different.
1003 */
1004 sec_protocol_options_set_tls_server_name(optionsA, server_nameA);
1005 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
1006
1007 /*
1008 * Set the name to nameA in optionsB.
1009 * Options A, B should now be equal.
1010 */
1011 sec_protocol_options_set_tls_server_name(optionsB, server_nameA);
1012 XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
1013
1014 /*
1015 * Change the current name in B.
1016 * Comparison should fail.
1017 */
1018 sec_protocol_options_set_tls_server_name(optionsB, server_nameB);
1019 XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
1020 }
1021
1022 - (void)test_sec_protocol_options_create_and_import_config {
1023 sec_protocol_options_t options = [self create_sec_protocol_options];
1024 sec_protocol_options_t imported_options = [self create_sec_protocol_options];
1025
1026 sec_protocol_options_set_min_tls_protocol_version(options, tls_protocol_version_TLSv13);
1027 sec_protocol_options_set_tls_early_data_enabled(options, true);
1028 xpc_object_t config = sec_protocol_options_create_config(options);
1029 XCTAssertTrue(config != NULL);
1030 if (config != NULL) {
1031 sec_protocol_options_apply_config(imported_options, config);
1032 XCTAssertTrue(sec_protocol_options_are_equal(options, imported_options));
1033 }
1034 }
1035
1036 - (void)test_sec_protocol_options_matches_full_config {
1037 sec_protocol_options_t options = [self create_sec_protocol_options];
1038
1039 sec_protocol_options_set_min_tls_protocol_version(options, tls_protocol_version_TLSv13);
1040 sec_protocol_options_set_tls_early_data_enabled(options, true);
1041 xpc_object_t config = sec_protocol_options_create_config(options);
1042 XCTAssertTrue(config != NULL);
1043 if (config != NULL) {
1044 XCTAssertTrue(sec_protocol_options_matches_config(options, config));
1045 }
1046 }
1047
1048 - (void)test_sec_protocol_options_matches_partial_config {
1049 sec_protocol_options_t options = [self create_sec_protocol_options];
1050 sec_protocol_options_set_tls_resumption_enabled(options, true);
1051
1052 xpc_object_t config = sec_protocol_options_create_config(options);
1053 XCTAssertTrue(config != NULL);
1054 if (config != NULL) {
1055 // Drop one key from the config, and make sure that the result still matches
1056 __block const char *enable_resumption_key = "enable_resumption";
1057 xpc_object_t trimmed_config = xpc_dictionary_create(NULL, NULL, 0);
1058 xpc_dictionary_apply(config, ^bool(const char * _Nonnull key, xpc_object_t _Nonnull value) {
1059 if (strncmp(key, enable_resumption_key, strlen(enable_resumption_key)) != 0) {
1060 xpc_dictionary_set_value(trimmed_config, key, value);
1061 }
1062 return true;
1063 });
1064 XCTAssertTrue(sec_protocol_options_matches_config(options, trimmed_config));
1065 }
1066 }
1067
1068 - (void)test_sec_protocol_options_matches_config_with_mismatch {
1069 sec_protocol_options_t options = [self create_sec_protocol_options];
1070
1071 __block bool enable_resumption = true;
1072 sec_protocol_options_set_tls_resumption_enabled(options, enable_resumption);
1073
1074 xpc_object_t config = sec_protocol_options_create_config(options);
1075 XCTAssertTrue(config != NULL);
1076 if (config != NULL) {
1077 // Flip a value in the config, and expect the match to fail
1078 __block const char *enable_resumption_key = "enable_resumption";
1079 xpc_object_t mismatched_config = xpc_dictionary_create(NULL, NULL, 0);
1080 xpc_dictionary_apply(config, ^bool(const char * _Nonnull key, xpc_object_t _Nonnull value) {
1081 if (strncmp(key, enable_resumption_key, strlen(enable_resumption_key)) != 0) {
1082 xpc_dictionary_set_value(mismatched_config, key, value);
1083 } else {
1084 xpc_dictionary_set_bool(mismatched_config, key, !enable_resumption);
1085 }
1086 return true;
1087 });
1088 XCTAssertFalse(sec_protocol_options_matches_config(options, mismatched_config));
1089 }
1090 }
1091
1092 - (void)test_protocol_version_map {
1093 #pragma clang diagnostic push
1094 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1095 XCTAssertTrue(tls_protocol_version_TLSv10 == SSLProtocolGetVersionCodepoint(kTLSProtocol1));
1096 XCTAssertTrue(tls_protocol_version_TLSv11 == SSLProtocolGetVersionCodepoint(kTLSProtocol11));
1097 XCTAssertTrue(tls_protocol_version_TLSv12 == SSLProtocolGetVersionCodepoint(kTLSProtocol12));
1098 XCTAssertTrue(tls_protocol_version_TLSv13 == SSLProtocolGetVersionCodepoint(kTLSProtocol13));
1099 XCTAssertTrue(tls_protocol_version_DTLSv12 == SSLProtocolGetVersionCodepoint(kDTLSProtocol12));
1100 XCTAssertTrue(tls_protocol_version_DTLSv10 == SSLProtocolGetVersionCodepoint(kDTLSProtocol1));
1101
1102 XCTAssertTrue(kTLSProtocol1 == SSLProtocolFromVersionCodepoint(tls_protocol_version_TLSv10));
1103 XCTAssertTrue(kTLSProtocol11 == SSLProtocolFromVersionCodepoint(tls_protocol_version_TLSv11));
1104 XCTAssertTrue(kTLSProtocol12 == SSLProtocolFromVersionCodepoint(tls_protocol_version_TLSv12));
1105 XCTAssertTrue(kTLSProtocol13 == SSLProtocolFromVersionCodepoint(tls_protocol_version_TLSv13));
1106 XCTAssertTrue(kDTLSProtocol12 == SSLProtocolFromVersionCodepoint(tls_protocol_version_DTLSv12));
1107 XCTAssertTrue(kDTLSProtocol1 == SSLProtocolFromVersionCodepoint(tls_protocol_version_DTLSv10));
1108 #pragma clang diagnostic pop
1109 }
1110
1111 - (void)test_default_protocol_versions {
1112 XCTAssertTrue(sec_protocol_options_get_default_max_tls_protocol_version() == tls_protocol_version_TLSv13);
1113 XCTAssertTrue(sec_protocol_options_get_default_min_tls_protocol_version() == tls_protocol_version_TLSv10);
1114 XCTAssertTrue(sec_protocol_options_get_default_max_dtls_protocol_version() == tls_protocol_version_DTLSv12);
1115 XCTAssertTrue(sec_protocol_options_get_default_min_dtls_protocol_version() == tls_protocol_version_DTLSv10);
1116 }
1117
1118 - (void)test_sec_protocol_options_set_psk_hint {
1119 __block dispatch_data_t hint = [self create_random_dispatch_data];
1120 sec_protocol_options_t options = [self create_sec_protocol_options];
1121
1122 (void)sec_protocol_options_access_handle(options, ^bool(void * _Nonnull handle) {
1123 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1124 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1125
1126 XCTAssertNil(content->psk_identity_hint, @"PSK identity initialized incorrectly");
1127 });
1128
1129 sec_protocol_options_set_tls_pre_shared_key_identity_hint(options, hint);
1130
1131 (void)sec_protocol_options_access_handle(options, ^bool(void * _Nonnull handle) {
1132 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1133 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1134
1135 XCTAssertTrue(sec_protocol_helper_dispatch_data_equal(content->psk_identity_hint, hint), @"PSK identity mistmatch");
1136 });
1137 }
1138
1139 - (void)test_sec_protocol_options_set_psk_selection_block {
1140 void (^selection_block)(sec_protocol_metadata_t, dispatch_data_t, sec_protocol_pre_shared_key_selection_complete_t) = ^(__unused sec_protocol_metadata_t metadata, __unused dispatch_data_t psk_identity_hint, __unused sec_protocol_pre_shared_key_selection_complete_t complete) {
1141 // pass
1142 };
1143 dispatch_queue_t selection_queue = dispatch_queue_create("test_sec_protocol_options_set_psk_selection_block_queue", DISPATCH_QUEUE_SERIAL);
1144
1145 sec_protocol_options_t options = [self create_sec_protocol_options];
1146 sec_protocol_options_set_pre_shared_key_selection_block(options, selection_block, selection_queue);
1147 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1148 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1149 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1150 XCTAssertTrue(content->psk_selection_block == selection_block);
1151 XCTAssertTrue(content->psk_selection_queue != nil);
1152 return false;
1153 });
1154 }
1155
1156 - (dispatch_data_t)create_random_dispatch_data {
1157 uint8_t random[32];
1158 (void)SecRandomCopyBytes(NULL, sizeof(random), random);
1159 return dispatch_data_create(random, sizeof(random), NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
1160 }
1161
1162 - (void)test_sec_protocol_metadata_access_psks {
1163 __block dispatch_data_t psk_data = [self create_random_dispatch_data];
1164 __block dispatch_data_t psk_identity_data = [self create_random_dispatch_data];
1165
1166 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
1167 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1168 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1169 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1170
1171 content->pre_shared_keys = xpc_array_create(NULL, 0);
1172
1173 xpc_object_t xpc_psk_data = xpc_data_create_with_dispatch_data(psk_data);
1174 xpc_object_t xpc_psk_identity_data = xpc_data_create_with_dispatch_data(psk_identity_data);
1175
1176 xpc_object_t tuple = xpc_array_create(NULL, 0);
1177 xpc_array_set_value(tuple, XPC_ARRAY_APPEND, xpc_psk_data);
1178 xpc_array_set_value(tuple, XPC_ARRAY_APPEND, xpc_psk_identity_data);
1179
1180 xpc_array_set_value(content->pre_shared_keys, XPC_ARRAY_APPEND, tuple);
1181 return true;
1182 });
1183
1184 BOOL accessed = sec_protocol_metadata_access_pre_shared_keys(metadata, ^(dispatch_data_t psk, dispatch_data_t identity) {
1185 XCTAssertTrue(sec_protocol_helper_dispatch_data_equal(psk, psk_data), @"Expected PSK data match");
1186 XCTAssertTrue(sec_protocol_helper_dispatch_data_equal(identity, psk_identity_data), @"Expected PSK identity data match");
1187 });
1188 XCTAssertTrue(accessed, @"Expected sec_protocol_metadata_access_pre_shared_keys to traverse PSK list");
1189 }
1190
1191 - (void)test_sec_protocol_options_set_tls_block_length_padding {
1192 sec_protocol_options_t options = [self create_sec_protocol_options];
1193
1194 sec_protocol_block_length_padding_t expected_block_length_padding = SEC_PROTOCOL_BLOCK_LENGTH_PADDING_DEFAULT;
1195 sec_protocol_options_set_tls_block_length_padding(options, expected_block_length_padding);
1196
1197 __block sec_protocol_block_length_padding_t current_block_length_padding = SEC_PROTOCOL_BLOCK_LENGTH_PADDING_NONE;
1198 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1199 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1200 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1201
1202 current_block_length_padding = content->tls_block_length_padding;
1203 return true;
1204 });
1205
1206 XCTAssertTrue(current_block_length_padding == expected_block_length_padding);
1207 }
1208
1209 - (void)test_sec_protocol_experiment_identifier {
1210 sec_protocol_options_t options = [self create_sec_protocol_options];
1211
1212 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1213 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1214 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1215 XCTAssertTrue(content->experiment_identifier == NULL);
1216 return true;
1217 });
1218
1219 const char *identifier = "first_experiment";
1220 sec_protocol_options_set_experiment_identifier(options, identifier);
1221 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1222 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1223 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1224 XCTAssertTrue(content->experiment_identifier != NULL);
1225 XCTAssertTrue(strncmp(identifier, content->experiment_identifier, strlen(identifier)) == 0);
1226 return true;
1227 });
1228
1229 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
1230 XCTAssertTrue(sec_protocol_metadata_get_experiment_identifier(metadata) == NULL);
1231
1232 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1233 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1234 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1235 content->experiment_identifier = strdup(identifier);
1236 return true;
1237 });
1238
1239 XCTAssertTrue(strncmp(identifier, sec_protocol_metadata_get_experiment_identifier(metadata), strlen(identifier)) == 0);
1240 }
1241
1242 - (void)test_sec_protocol_connection_id {
1243 sec_protocol_options_t options = [self create_sec_protocol_options];
1244
1245 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1246 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1247 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1248 uuid_t zeroes = {};
1249 XCTAssertTrue(memcmp(zeroes, content->connection_id, sizeof(zeroes)) == 0);
1250 return true;
1251 });
1252
1253 uuid_t uuid = {};
1254 __block uint8_t *uuid_ptr = uuid;
1255 __block size_t uuid_len = sizeof(uuid);
1256 (void)SecRandomCopyBytes(NULL, sizeof(uuid), uuid);
1257 sec_protocol_options_set_connection_id(options, uuid);
1258 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1259 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1260 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1261 XCTAssertTrue(memcmp(content->connection_id, uuid_ptr, uuid_len) == 0);
1262 return true;
1263 });
1264
1265 sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata];
1266 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1267 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1268 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1269 memcpy(content->connection_id, uuid_ptr, uuid_len);
1270 return true;
1271 });
1272
1273 uuid_t copied_metadata = {};
1274 sec_protocol_metadata_copy_connection_id(metadata, copied_metadata);
1275
1276 XCTAssertTrue(memcmp(uuid, copied_metadata, sizeof(copied_metadata)) == 0);
1277 }
1278
1279 - (void)test_sec_protocol_options_set_allow_unknown_alpn_protos {
1280 sec_protocol_options_t options = [self create_sec_protocol_options];
1281
1282 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1283 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1284 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1285 XCTAssertFalse(content->allow_unknown_alpn_protos_override);
1286 return true;
1287 });
1288
1289 sec_protocol_options_set_allow_unknown_alpn_protos(options, true);
1290 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1291 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1292 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1293 XCTAssertTrue(content->allow_unknown_alpn_protos);
1294 XCTAssertTrue(content->allow_unknown_alpn_protos_override);
1295 return true;
1296 });
1297 }
1298
1299 @end