]> git.saurik.com Git - apple/security.git/blob - protocol/SecProtocol.c
Security-58286.240.4.tar.gz
[apple/security.git] / protocol / SecProtocol.c
1 //
2 // SecProtocol.c
3 // Security
4 //
5
6 #include <Security/SecProtocolOptions.h>
7 #include <Security/SecProtocolMetadata.h>
8 #include <Security/SecProtocolPriv.h>
9
10 #include <Security/SecureTransportPriv.h>
11
12 #include <xpc/xpc.h>
13 #include <os/log.h>
14 #include <dlfcn.h>
15 #include <sys/param.h>
16
17 #define CFReleaseSafe(value) \
18 if (value != NULL) { \
19 CFRelease(value); \
20 }
21
22 typedef bool (^sec_access_block_t)(void *handle);
23
24 static bool
25 sec_protocol_options_access_handle(sec_protocol_options_t options,
26 sec_access_block_t access_block)
27 {
28 static void *libnetworkImage = NULL;
29 static dispatch_once_t onceToken;
30 static bool (*_nw_protocol_options_access_handle)(void *, sec_access_block_t) = NULL;
31
32 dispatch_once(&onceToken, ^{
33 libnetworkImage = dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY | RTLD_LOCAL);
34 if (NULL != libnetworkImage) {
35 _nw_protocol_options_access_handle = (__typeof(_nw_protocol_options_access_handle))dlsym(libnetworkImage,
36 "nw_protocol_options_access_handle");
37 if (NULL == _nw_protocol_options_access_handle) {
38 os_log_error(OS_LOG_DEFAULT, "dlsym libnetwork nw_protocol_options_access_handle");
39 }
40 } else {
41 os_log_error(OS_LOG_DEFAULT, "dlopen libnetwork");
42 }
43 });
44
45 if (_nw_protocol_options_access_handle == NULL) {
46 return false;
47 }
48
49 return _nw_protocol_options_access_handle(options, access_block);
50 }
51
52 static bool
53 sec_protocol_metadata_access_handle(sec_protocol_metadata_t options,
54 sec_access_block_t access_block)
55 {
56 static void *libnetworkImage = NULL;
57 static dispatch_once_t onceToken;
58 static bool (*_nw_protocol_metadata_access_handle)(void *, sec_access_block_t) = NULL;
59
60 dispatch_once(&onceToken, ^{
61 libnetworkImage = dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY | RTLD_LOCAL);
62 if (NULL != libnetworkImage) {
63 _nw_protocol_metadata_access_handle = (__typeof(_nw_protocol_metadata_access_handle))dlsym(libnetworkImage,
64 "nw_protocol_metadata_access_handle");
65 if (NULL == _nw_protocol_metadata_access_handle) {
66 os_log_error(OS_LOG_DEFAULT, "dlsym libnetwork _nw_protocol_metadata_access_handle");
67 }
68 } else {
69 os_log_error(OS_LOG_DEFAULT, "dlopen libnetwork");
70 }
71 });
72
73 if (_nw_protocol_metadata_access_handle == NULL) {
74 return false;
75 }
76
77 return _nw_protocol_metadata_access_handle(options, access_block);
78 }
79
80 #define SEC_PROTOCOL_OPTIONS_VALIDATE(o,r) \
81 if (o == NULL) { \
82 return r; \
83 }
84
85 #define SEC_PROTOCOL_METADATA_VALIDATE(m,r) \
86 if (((void *)m == NULL) || ((size_t)m == 0)) { \
87 return r; \
88 }
89
90 void
91 sec_protocol_options_set_local_identity(sec_protocol_options_t options, sec_identity_t identity)
92 {
93 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
94
95 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
96 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
97 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
98
99 if (content->identity != NULL) {
100 sec_release(content->identity);
101 }
102 content->identity = sec_retain(identity);
103 return true;
104 });
105 }
106
107 void
108 sec_protocol_options_add_tls_ciphersuite(sec_protocol_options_t options, SSLCipherSuite ciphersuite)
109 {
110 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
111
112 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
113 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
114 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
115
116 if (content->ciphersuites == NULL) {
117 content->ciphersuites = xpc_array_create(NULL, 0);
118 }
119 xpc_array_set_uint64(content->ciphersuites, XPC_ARRAY_APPEND, (uint64_t)ciphersuite);
120 return true;
121 });
122 }
123
124 void
125 sec_protocol_options_add_tls_ciphersuite_group(sec_protocol_options_t options, SSLCiphersuiteGroup group)
126 {
127 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
128
129 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
130 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
131 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
132
133 if (content->ciphersuites == NULL) {
134 content->ciphersuites = xpc_array_create(NULL, 0);
135 }
136
137 // Fetch the list of ciphersuites associated with the ciphersuite group
138 size_t ciphersuite_count = 0;
139 const SSLCipherSuite *list = SSLCiphersuiteGroupToCiphersuiteList(group, &ciphersuite_count);
140 if (list != NULL) {
141 for (size_t i = 0; i < ciphersuite_count; i++) {
142 SSLCipherSuite ciphersuite = list[i];
143 xpc_array_set_uint64(content->ciphersuites, XPC_ARRAY_APPEND, (uint64_t)ciphersuite);
144 }
145 }
146
147 return true;
148 });
149 }
150
151 void
152 sec_protocol_options_set_tls_min_version(sec_protocol_options_t options, SSLProtocol version)
153 {
154 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
155
156 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
157 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
158 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
159
160 content->min_version = version;
161 return true;
162 });
163 }
164
165 void
166 sec_protocol_options_set_tls_max_version(sec_protocol_options_t options, SSLProtocol version)
167 {
168 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
169
170 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
171 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
172 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
173
174 content->max_version = version;
175 return true;
176 });
177 }
178
179 void
180 sec_protocol_options_add_tls_application_protocol(sec_protocol_options_t options, const char *application_protocol)
181 {
182 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
183 SEC_PROTOCOL_OPTIONS_VALIDATE(application_protocol,);
184
185 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
186 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
187 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
188
189 if (content->application_protocols == NULL) {
190 content->application_protocols = xpc_array_create(NULL, 0);
191 }
192 xpc_array_set_string(content->application_protocols, XPC_ARRAY_APPEND, application_protocol);
193 return true;
194 });
195 }
196
197 void
198 sec_protocol_options_set_tls_server_name(sec_protocol_options_t options, const char *server_name)
199 {
200 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
201 SEC_PROTOCOL_OPTIONS_VALIDATE(server_name,);
202
203 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
204 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
205 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
206
207 if (content->server_name != NULL) {
208 free(content->server_name);
209 }
210 content->server_name = strdup(server_name);
211 return true;
212 });
213 }
214
215 void
216 sec_protocol_options_set_tls_diffie_hellman_parameters(sec_protocol_options_t options, dispatch_data_t params)
217 {
218 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
219 SEC_PROTOCOL_OPTIONS_VALIDATE(params,);
220
221 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
222 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
223 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
224
225 if (content->dh_params) {
226 dispatch_release(content->dh_params);
227 }
228 content->dh_params = params;
229 dispatch_retain(params);
230 return true;
231 });
232 }
233
234 void
235 sec_protocol_options_add_pre_shared_key(sec_protocol_options_t options, dispatch_data_t psk, dispatch_data_t psk_identity)
236 {
237 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
238 SEC_PROTOCOL_OPTIONS_VALIDATE(psk,);
239 SEC_PROTOCOL_OPTIONS_VALIDATE(psk_identity,);
240
241 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
242 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
243 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
244
245 if (content->pre_shared_keys == NULL) {
246 content->pre_shared_keys = xpc_array_create(NULL, 0);
247 }
248
249 xpc_object_t psk_data = xpc_data_create_with_dispatch_data(psk);
250 xpc_object_t psk_identity_data = xpc_data_create_with_dispatch_data(psk_identity);
251
252 xpc_object_t tuple = xpc_array_create(NULL, 0);
253 xpc_array_set_value(tuple, XPC_ARRAY_APPEND, psk_data);
254 xpc_array_set_value(tuple, XPC_ARRAY_APPEND, psk_identity_data);
255 xpc_release(psk_data);
256 xpc_release(psk_identity_data);
257
258 xpc_array_set_value(content->pre_shared_keys, XPC_ARRAY_APPEND, tuple);
259 xpc_release(tuple);
260 return true;
261 });
262 }
263
264 void
265 sec_protocol_options_set_tls_is_fallback_attempt(sec_protocol_options_t options, bool fallback_attempt)
266 {
267 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
268
269 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
270 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
271 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
272
273 content->enable_fallback_attempt = fallback_attempt;
274 return true;
275 });
276 }
277
278 void
279 sec_protocol_options_set_tls_tickets_enabled(sec_protocol_options_t options, bool tickets_enabled)
280 {
281 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
282
283 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
284 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
285 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
286
287 content->enable_tickets = tickets_enabled;
288 return true;
289 });
290 }
291
292 void
293 sec_protocol_options_set_tls_resumption_enabled(sec_protocol_options_t options, bool resumption_enabled)
294 {
295 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
296
297 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
298 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
299 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
300
301 content->enable_resumption = resumption_enabled;
302 return true;
303 });
304 }
305
306 void
307 sec_protocol_options_set_tls_false_start_enabled(sec_protocol_options_t options, bool false_start_enabled)
308 {
309 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
310
311 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
312 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
313 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
314
315 content->enable_false_start = false_start_enabled;
316 return true;
317 });
318 }
319
320 void
321 sec_protocol_options_set_tls_early_data_enabled(sec_protocol_options_t options, bool early_data_enabled)
322 {
323 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
324
325 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
326 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
327 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
328
329 content->enable_early_data = early_data_enabled;
330 return true;
331 });
332 }
333
334 void
335 sec_protocol_options_set_tls_sni_disabled(sec_protocol_options_t options, bool sni_disabled)
336 {
337 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
338
339 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
340 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
341 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
342
343 content->disable_sni = sni_disabled;
344 return true;
345 });
346 }
347
348 void
349 sec_protocol_options_set_enforce_ev(sec_protocol_options_t options, bool enforce_ev)
350 {
351 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
352
353 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
354 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
355 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
356
357 content->enforce_ev = enforce_ev;
358 return true;
359 });
360 }
361
362 void
363 sec_protocol_options_set_tls_ocsp_enabled(sec_protocol_options_t options, bool ocsp_enabled)
364 {
365 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
366
367 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
368 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
369 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
370
371 content->enable_ocsp = ocsp_enabled;
372 return true;
373 });
374 }
375
376 void
377 sec_protocol_options_set_tls_sct_enabled(sec_protocol_options_t options, bool sct_enabled)
378 {
379 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
380
381 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
382 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
383 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
384
385 content->enable_sct = sct_enabled;
386 return true;
387 });
388 }
389
390 void
391 sec_protocol_options_set_tls_renegotiation_enabled(sec_protocol_options_t options, bool renegotiation_enabled)
392 {
393 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
394
395 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
396 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
397 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
398
399 content->enable_renegotiation = renegotiation_enabled;
400 return true;
401 });
402 }
403
404 void
405 sec_protocol_options_set_peer_authentication_required(sec_protocol_options_t options, bool peer_authentication_required)
406 {
407 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
408
409 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
410 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
411 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
412
413 content->peer_authentication_required = peer_authentication_required;
414 content->peer_authentication_override = true;
415 return true;
416 });
417 }
418
419 void
420 sec_protocol_options_set_key_update_block(sec_protocol_options_t options, sec_protocol_key_update_t update_block, dispatch_queue_t update_queue)
421 {
422 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
423 SEC_PROTOCOL_OPTIONS_VALIDATE(update_queue,);
424
425 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
426 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
427 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
428
429 if (content->key_update_block != NULL) {
430 Block_release(content->key_update_block);
431 }
432 if (content->key_update_queue != NULL) {
433 dispatch_release(content->key_update_queue);
434 }
435
436 content->key_update_block = Block_copy(update_block);
437 content->key_update_queue = Block_copy(update_queue);
438 dispatch_retain(content->key_update_queue);
439 return true;
440 });
441 }
442
443 void
444 sec_protocol_options_set_challenge_block(sec_protocol_options_t options, sec_protocol_challenge_t challenge_block, dispatch_queue_t challenge_queue)
445 {
446 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
447 SEC_PROTOCOL_OPTIONS_VALIDATE(challenge_queue,);
448
449 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
450 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
451 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
452
453 if (content->challenge_block != NULL) {
454 Block_release(content->challenge_block);
455 }
456 if (content->challenge_queue != NULL) {
457 dispatch_release(content->challenge_queue);
458 }
459
460 content->challenge_block = Block_copy(challenge_block);
461 content->challenge_queue = challenge_queue;
462 dispatch_retain(content->challenge_queue);
463 return true;
464 });
465 }
466
467 void
468 sec_protocol_options_set_verify_block(sec_protocol_options_t options, sec_protocol_verify_t verify_block, dispatch_queue_t verify_queue)
469 {
470 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
471 SEC_PROTOCOL_OPTIONS_VALIDATE(verify_queue,);
472
473 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
474 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
475 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
476
477 if (content->verify_block != NULL) {
478 Block_release(content->verify_block);
479 }
480 if (content->verify_queue != NULL) {
481 dispatch_release(content->verify_queue);
482 }
483
484 content->verify_block = Block_copy(verify_block);
485 content->verify_queue = verify_queue;
486 dispatch_retain(content->verify_queue);
487 return true;
488 });
489 }
490
491 void
492 sec_protocol_options_add_tls_extension(sec_protocol_options_t options, sec_tls_extension_t extension)
493 {
494 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
495 SEC_PROTOCOL_OPTIONS_VALIDATE(extension,);
496
497 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
498 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
499 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
500
501 if (content->custom_extensions == NULL) {
502 content->custom_extensions = sec_array_create();
503 }
504
505 sec_array_append(content->custom_extensions, (sec_object_t)extension);
506 return true;
507 });
508 }
509
510 const char *
511 sec_protocol_metadata_get_negotiated_protocol(sec_protocol_metadata_t metadata)
512 {
513 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
514
515 __block const char *negotiated_protocol = NULL;
516 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
517 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
518 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
519 negotiated_protocol = content->negotiated_protocol;
520 return true;
521 });
522
523 return negotiated_protocol;
524 }
525
526 bool
527 sec_protocol_metadata_access_peer_certificate_chain(sec_protocol_metadata_t metadata,
528 void (^handler)(sec_certificate_t certficate))
529 {
530 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
531 SEC_PROTOCOL_METADATA_VALIDATE(handler, false);
532
533 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
534 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
535 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
536 if (content->peer_certificate_chain == NULL) {
537 return false;
538 }
539 sec_array_t array = content->peer_certificate_chain;
540 sec_array_apply(array, ^bool(__unused size_t index, sec_object_t object) {
541 handler((sec_certificate_t)object);
542 return true;
543 });
544 return true;
545 });
546 }
547
548 dispatch_data_t
549 sec_protocol_metadata_copy_peer_public_key(sec_protocol_metadata_t metadata)
550 {
551 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
552
553 __block dispatch_data_t peer_public_key = NULL;
554 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
555 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
556 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
557 peer_public_key = ((dispatch_data_t)content->peer_public_key);
558 if (peer_public_key) {
559 dispatch_retain(peer_public_key);
560 }
561 return true;
562 });
563
564 return peer_public_key;
565 }
566
567 SSLProtocol
568 sec_protocol_metadata_get_negotiated_protocol_version(sec_protocol_metadata_t metadata)
569 {
570 SEC_PROTOCOL_METADATA_VALIDATE(metadata, kSSLProtocolUnknown);
571
572 __block SSLProtocol protocol_version = kSSLProtocolUnknown;
573 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
574 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
575 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
576 protocol_version = content->negotiated_protocol_version;
577 return true;
578 });
579
580 return protocol_version;
581 }
582
583 SSLCipherSuite
584 sec_protocol_metadata_get_negotiated_ciphersuite(sec_protocol_metadata_t metadata)
585 {
586 SEC_PROTOCOL_METADATA_VALIDATE(metadata, SSL_NO_SUCH_CIPHERSUITE);
587
588 __block SSLCipherSuite negotiated_ciphersuite = SSL_NO_SUCH_CIPHERSUITE;
589 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
590 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
591 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
592 negotiated_ciphersuite = content->negotiated_ciphersuite;
593 return true;
594 });
595
596 return negotiated_ciphersuite;
597 }
598
599 bool
600 sec_protocol_metadata_get_early_data_accepted(sec_protocol_metadata_t metadata)
601 {
602 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
603
604 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
605 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
606 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
607 return content->early_data_accepted;
608 });
609 }
610
611 bool
612 sec_protocol_metadata_access_supported_signature_algorithms(sec_protocol_metadata_t metadata,
613 void (^handler)(uint16_t signature_algorithm))
614 {
615 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
616 SEC_PROTOCOL_METADATA_VALIDATE(handler, false);
617
618 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
619 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
620 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
621 if (content->supported_signature_algorithms == NULL) {
622 return false;
623 }
624 xpc_object_t array = content->supported_signature_algorithms;
625 xpc_array_apply(array, ^bool(__unused size_t index, xpc_object_t _Nonnull value) {
626 handler((uint16_t)xpc_uint64_get_value(value));
627 return true;
628 });
629 return true;
630 });
631 }
632
633 bool
634 sec_protocol_metadata_access_ocsp_response(sec_protocol_metadata_t metadata,
635 void (^handler)(dispatch_data_t ocsp_data))
636 {
637 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
638 SEC_PROTOCOL_METADATA_VALIDATE(handler, false);
639
640 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
641 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
642 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
643 if (content->ocsp_response == NULL) {
644 return false;
645 }
646 sec_array_t array = content->ocsp_response;
647 sec_array_apply(array, ^bool(__unused size_t index, sec_object_t object) {
648 handler((dispatch_data_t)object);
649 return true;
650 });
651 return true;
652 });
653 }
654
655 bool
656 sec_protocol_metadata_access_distinguished_names(sec_protocol_metadata_t metadata,
657 void (^handler)(dispatch_data_t distinguished_name))
658 {
659 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
660 SEC_PROTOCOL_METADATA_VALIDATE(handler, false);
661
662 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
663 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
664 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
665 if (content->distinguished_names == NULL) {
666 return false;
667 }
668 sec_array_t array = content->distinguished_names;
669 sec_array_apply(array, ^bool(__unused size_t index, sec_object_t object) {
670 handler((dispatch_data_t)object);
671 return true;
672 });
673 return true;
674 });
675 }
676
677 static bool
678 sec_protocol_dispatch_data_are_equal(dispatch_data_t left, dispatch_data_t right)
679 {
680 if (!left || !right || left == right) {
681 return left == right;
682 }
683 if (dispatch_data_get_size(left) != dispatch_data_get_size(right)) {
684 return false;
685 }
686
687 __block bool equal = true;
688 dispatch_data_apply(left, ^bool(__unused dispatch_data_t _Nonnull lregion, size_t loffset, const void * _Nonnull lbuffer, size_t lsize) {
689 dispatch_data_apply(right, ^bool(__unused dispatch_data_t _Nonnull rregion, size_t roffset, const void * _Nonnull rbuffer, size_t rsize) {
690 // There is some overlap
691 const size_t start = MAX(loffset, roffset);
692 const size_t end = MIN(loffset + lsize, roffset + rsize);
693 if (start < end) {
694 equal = memcmp(&((const uint8_t*)rbuffer)[start - roffset], &((const uint8_t*)lbuffer)[start - loffset], end - start) == 0;
695 } else {
696 if (roffset > loffset + lsize) {
697 // Iteration of right has gone past where we're at on left, bail out of inner apply
698 // left |---|
699 // right |---|
700 return false;
701 } else if (roffset + rsize < loffset) {
702 // Iteration of right has not yet reached where we're at on left, keep going
703 // left |---|
704 // right |--|
705 return true;
706 }
707 }
708 return equal;
709 });
710 return equal;
711 });
712 return equal;
713 }
714
715 static bool
716 sec_protocol_sec_array_of_dispatch_data_are_equal(sec_array_t arrayA, sec_array_t arrayB)
717 {
718 if (sec_array_get_count(arrayA) != sec_array_get_count(arrayB)) {
719 return false;
720 }
721
722 __block bool equal = true;
723 (void)sec_array_apply(arrayA, ^bool(size_t indexA, sec_object_t objectA) {
724 return sec_array_apply(arrayB, ^bool(size_t indexB, sec_object_t objectB) {
725 if (indexA == indexB) {
726 dispatch_data_t dataA = (dispatch_data_t)objectA;
727 dispatch_data_t dataB = (dispatch_data_t)objectB;
728 equal &= sec_protocol_dispatch_data_are_equal(dataA, dataB);
729 return equal;
730 }
731 return true;
732 });
733 });
734
735 return equal;
736 }
737
738 static bool
739 sec_protocol_sec_array_of_sec_certificate_are_equal(sec_array_t arrayA, sec_array_t arrayB)
740 {
741 if (sec_array_get_count(arrayA) != sec_array_get_count(arrayB)) {
742 return false;
743 }
744
745 __block bool equal = true;
746 (void)sec_array_apply(arrayA, ^bool(size_t indexA, sec_object_t objectA) {
747 return sec_array_apply(arrayB, ^bool(size_t indexB, sec_object_t objectB) {
748 if (indexA == indexB) {
749 sec_certificate_t certA = (sec_certificate_t)objectA;
750 sec_certificate_t certB = (sec_certificate_t)objectB;
751
752 SecCertificateRef certRefA = sec_certificate_copy_ref(certA);
753 SecCertificateRef certRefB = sec_certificate_copy_ref(certB);
754
755 if (certRefA == NULL && certRefB != NULL) {
756 equal = false;
757 } else if (certRefA != NULL && certRefB == NULL) {
758 equal = false;
759 } else if (certRefA == NULL && certRefB == NULL) {
760 // pass
761 } else {
762 equal &= CFEqual(certRefA, certRefB);
763 }
764
765 CFReleaseSafe(certRefA);
766 CFReleaseSafe(certRefB);
767
768 return equal;
769 }
770 return true;
771 });
772 });
773
774 return equal;
775 }
776
777 static bool
778 sec_protocol_xpc_object_are_equal(xpc_object_t objectA, xpc_object_t objectB)
779 {
780 if (objectA == NULL && objectB != NULL) {
781 return false;
782 } else if (objectA != NULL && objectB == NULL) {
783 return false;
784 } else if (objectA == NULL && objectB == NULL) {
785 return true;
786 } else {
787 return xpc_equal(objectA, objectB);
788 }
789 }
790
791 bool
792 sec_protocol_metadata_peers_are_equal(sec_protocol_metadata_t metadataA, sec_protocol_metadata_t metadataB)
793 {
794 SEC_PROTOCOL_METADATA_VALIDATE(metadataA, false);
795 SEC_PROTOCOL_METADATA_VALIDATE(metadataB, false);
796
797 return sec_protocol_metadata_access_handle(metadataA, ^bool(void *handleA) {
798 sec_protocol_metadata_content_t contentA = (sec_protocol_metadata_content_t)handleA;
799 SEC_PROTOCOL_METADATA_VALIDATE(contentA, false);
800
801 return sec_protocol_metadata_access_handle(metadataB, ^bool(void *handleB) {
802 sec_protocol_metadata_content_t contentB = (sec_protocol_metadata_content_t)handleB;
803 SEC_PROTOCOL_METADATA_VALIDATE(contentB, false);
804
805 // Relevant peer information includes: Certificate chain, public key, support signature algorithms, OCSP response, and distinguished names
806 if (!sec_protocol_sec_array_of_sec_certificate_are_equal(contentA->peer_certificate_chain, contentB->peer_certificate_chain)) {
807 return false;
808 }
809 if (!sec_protocol_dispatch_data_are_equal((dispatch_data_t)contentA->peer_public_key, (dispatch_data_t)contentB->peer_public_key)) {
810 return false;
811 }
812 if (!sec_protocol_xpc_object_are_equal((xpc_object_t)contentA->supported_signature_algorithms, (xpc_object_t)contentB->supported_signature_algorithms)) {
813 return false;
814 }
815 if (!sec_protocol_sec_array_of_dispatch_data_are_equal(contentA->ocsp_response, contentB->ocsp_response)) {
816 return false;
817 }
818 if (!sec_protocol_sec_array_of_dispatch_data_are_equal(contentA->distinguished_names, contentB->distinguished_names)) {
819 return false;
820 }
821
822 return true;
823 });
824 });
825 }
826
827 bool
828 sec_protocol_metadata_challenge_parameters_are_equal(sec_protocol_metadata_t metadataA, sec_protocol_metadata_t metadataB)
829 {
830 SEC_PROTOCOL_METADATA_VALIDATE(metadataA, false);
831 SEC_PROTOCOL_METADATA_VALIDATE(metadataB, false);
832
833 return sec_protocol_metadata_access_handle(metadataA, ^bool(void *handleA) {
834 sec_protocol_metadata_content_t contentA = (sec_protocol_metadata_content_t)handleA;
835 SEC_PROTOCOL_METADATA_VALIDATE(contentA, false);
836
837 return sec_protocol_metadata_access_handle(metadataB, ^bool(void *handleB) {
838 sec_protocol_metadata_content_t contentB = (sec_protocol_metadata_content_t)handleB;
839 SEC_PROTOCOL_METADATA_VALIDATE(contentB, false);
840
841 if (!sec_protocol_xpc_object_are_equal((xpc_object_t)contentA->supported_signature_algorithms, (xpc_object_t)contentB->supported_signature_algorithms)) {
842 return false;
843 }
844 if (!sec_protocol_sec_array_of_dispatch_data_are_equal(contentA->distinguished_names, contentB->distinguished_names)) {
845 return false;
846 }
847 if (!sec_protocol_dispatch_data_are_equal(contentA->request_certificate_types, contentB->request_certificate_types)) {
848 return false;
849 }
850
851 return true;
852 });
853 });
854 }
855
856 dispatch_data_t
857 sec_protocol_metadata_create_secret(sec_protocol_metadata_t metadata, size_t label_len,
858 const char *label, size_t exporter_length)
859 {
860 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
861 SEC_PROTOCOL_METADATA_VALIDATE(label_len, NULL);
862 SEC_PROTOCOL_METADATA_VALIDATE(label, NULL);
863 SEC_PROTOCOL_METADATA_VALIDATE(exporter_length, NULL);
864
865 __block dispatch_data_t secret = NULL;
866 sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
867 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
868 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
869
870 if (content->exporter_function && content->exporter_context) {
871 sec_protocol_metadata_exporter exporter = (sec_protocol_metadata_exporter)content->exporter_function;
872 secret = exporter(content->exporter_context, label_len, label, 0, NULL, exporter_length);
873 }
874 return true;
875 });
876 return secret;
877 }
878
879 dispatch_data_t
880 sec_protocol_metadata_create_secret_with_context(sec_protocol_metadata_t metadata, size_t label_len,
881 const char *label, size_t context_len,
882 const uint8_t *context, size_t exporter_length)
883 {
884 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
885 SEC_PROTOCOL_METADATA_VALIDATE(label_len, NULL);
886 SEC_PROTOCOL_METADATA_VALIDATE(label, NULL);
887 SEC_PROTOCOL_METADATA_VALIDATE(context_len, NULL);
888 SEC_PROTOCOL_METADATA_VALIDATE(context, NULL);
889 SEC_PROTOCOL_METADATA_VALIDATE(exporter_length, NULL);
890
891 __block dispatch_data_t secret = NULL;
892 sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
893 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
894 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
895
896 if (content->exporter_function && content->exporter_context) {
897 sec_protocol_metadata_exporter exporter = (sec_protocol_metadata_exporter)content->exporter_function;
898 secret = exporter(content->exporter_context, label_len, label, context_len, context, exporter_length);
899 }
900 return true;
901 });
902 return secret;
903 }
904
905 bool
906 sec_protocol_metadata_get_tls_false_start_used(sec_protocol_metadata_t metadata)
907 {
908 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
909
910 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
911 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
912 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
913 return content->false_start_used;
914 });
915 }
916
917 bool
918 sec_protocol_metadata_get_ticket_offered(sec_protocol_metadata_t metadata)
919 {
920 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
921
922 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
923 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
924 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
925 return content->ticket_offered;
926 });
927 }
928
929 bool
930 sec_protocol_metadata_get_ticket_received(sec_protocol_metadata_t metadata)
931 {
932 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
933
934 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
935 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
936 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
937 return content->ticket_received;
938 });
939 }
940
941 bool
942 sec_protocol_metadata_get_session_resumed(sec_protocol_metadata_t metadata)
943 {
944 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
945
946 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
947 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
948 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
949 return content->session_resumed;
950 });
951 }
952
953 bool
954 sec_protocol_metadata_get_session_renewed(sec_protocol_metadata_t metadata)
955 {
956 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
957
958 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
959 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
960 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
961 return content->session_renewed;
962 });
963 }
964
965 void *
966 sec_retain(void *obj)
967 {
968 if (obj != NULL) {
969 return os_retain(obj);
970 } else {
971 return NULL;
972 }
973 }
974
975 void
976 sec_release(void *obj)
977 {
978 if (obj != NULL) {
979 os_release(obj);
980 }
981 }