]> git.saurik.com Git - apple/security.git/blob - protocol/SecProtocol.c
Security-59306.11.20.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 #include <Security/SecProtocolTypesPriv.h>
10 #include "SecProtocolInternal.h"
11
12 #include <Security/SecureTransportPriv.h>
13
14 #include <Security/SecFramework.h>
15
16 #include <xpc/xpc.h>
17 #include <os/log.h>
18 #include <dlfcn.h>
19 #include <sys/param.h>
20
21 #define MAX_SEC_PROTOCOL_OPTIONS_KEY_LEN 128
22
23 // Options keys
24 #define SEC_PROTOCOL_OPTIONS_KEY_min_version "min_version"
25 #define SEC_PROTOCOL_OPTIONS_KEY_max_version "max_version"
26 #define SEC_PROTOCOL_OPTIONS_KEY_minimum_rsa_key_size "minimum_rsa_key_size"
27 #define SEC_PROTOCOL_OPTIONS_KEY_minimum_ecdsa_key_size "minimum_ecdsa_key_size"
28 #define SEC_PROTOCOL_OPTIONS_KEY_minimum_signature_algorithm "minimum_signature_algorithm"
29 #define SEC_PROTOCOL_OPTIONS_KEY_ats_required "ats_required"
30 #define SEC_PROTOCOL_OPTIONS_KEY_ats_minimum_tls_version_allowed "ats_minimum_tls_version_allowed"
31 #define SEC_PROTOCOL_OPTIONS_KEY_ats_non_pfs_ciphersuite_allowed "ats_non_pfs_ciphersuite_allowed"
32 #define SEC_PROTOCOL_OPTIONS_KEY_trusted_peer_certificate "trusted_peer_certificate"
33 #define SEC_PROTOCOL_OPTIONS_KEY_disable_sni "disable_sni"
34 #define SEC_PROTOCOL_OPTIONS_KEY_enable_fallback_attempt "enable_fallback_attempt"
35 #define SEC_PROTOCOL_OPTIONS_KEY_enable_false_start "enable_false_start"
36 #define SEC_PROTOCOL_OPTIONS_KEY_enable_tickets "enable_tickets"
37 #define SEC_PROTOCOL_OPTIONS_KEY_enable_sct "enable_sct"
38 #define SEC_PROTOCOL_OPTIONS_KEY_enable_ocsp "enable_ocsp"
39 #define SEC_PROTOCOL_OPTIONS_KEY_enforce_ev "enforce_ev"
40 #define SEC_PROTOCOL_OPTIONS_KEY_enable_resumption "enable_resumption"
41 #define SEC_PROTOCOL_OPTIONS_KEY_enable_renegotiation "enable_renegotiation"
42 #define SEC_PROTOCOL_OPTIONS_KEY_enable_early_data "enable_early_data"
43 #define SEC_PROTOCOL_OPTIONS_KEY_peer_authentication_required "peer_authentication_required"
44 #define SEC_PROTOCOL_OPTIONS_KEY_certificate_compression_enabled "certificate_compression_enabled"
45 #define SEC_PROTOCOL_OPTIONS_KEY_tls_SIKE503_exchange_enabled "tls_SIKE503_exchange_enabled"
46 #define SEC_PROTOCOL_OPTIONS_KEY_tls_HRSS_exchange_enabled "tls_HRSS_exchange_enabled"
47 #define SEC_PROTOCOL_OPTIONS_KEY_eddsa_enabled "eddsa_enabled"
48 #define SEC_PROTOCOL_OPTIONS_KEY_tls_delegated_credentials_enabled "tls_delegated_credentials_enabled"
49 #define SEC_PROTOCOL_OPTIONS_KEY_tls_grease_enabled "tls_grease_enabled"
50 #define SEC_PROTOCOL_OPTIONS_KEY_tls_ticket_request_count "tls_ticket_request_count"
51 #define SEC_PROTOCOL_OPTIONS_KEY_ciphersuites "ciphersuites"
52
53 // Metadata keys
54 #define SEC_PROTOCOL_METADATA_KEY_PROCESS_IDENTIFIER "process"
55 #define SEC_PROTOCOL_METADATA_KEY_CIPHERSUITE "cipher_name"
56 #define SEC_PROTOCOL_METADATA_KEY_FALLBACK_ENABLED "fallback"
57 #define SEC_PROTOCOL_METADATA_KEY_DH_GROUP_SIZE "dhe_size"
58 #define SEC_PROTOCOL_METADATA_KEY_NEGOTIATED_CURVE "neg_curve"
59 #define SEC_PROTOCOL_METADATA_KEY_PEER_CERTIFICATE_REQUEST_TYPE "cert_request_type"
60 #define SEC_PROTOCOL_METADATA_KEY_LOCAL_PRIVATE_KEY_TYPE "private_key_type"
61 #define SEC_PROTOCOL_METADATA_KEY_PEER_PUBLIC_KEY_TYPE "peer_public_key_type"
62 #define SEC_PROTOCOL_METADATA_KEY_NEGOTIATED_PROTOCOL "negotiated_protocol"
63 #define SEC_PROTOCOL_METADATA_KEY_ALPN_USED "alpn_used"
64 #define SEC_PROTOCOL_METADATA_KEY_NPN_USED "npn_used"
65 #define SEC_PROTOCOL_METADATA_KEY_PROTOCOL_VERSION "version"
66 #define SEC_PROTOCOL_METADATA_KEY_FALSE_START_ENABLED "false_start_enabled"
67 #define SEC_PROTOCOL_METADATA_KEY_FALSE_START_USED "false_start_used"
68 #define SEC_PROTOCOL_METADATA_KEY_TICKET_OFFERED "ticket_offered"
69 #define SEC_PROTOCOL_METADATA_KEY_TICKET_RECEIVED "ticket_received"
70 #define SEC_PROTOCOL_METADATA_KEY_SESSION_RESUMED "session_resumed"
71 #define SEC_PROTOCOL_METADATA_KEY_SESSION_RENEWED "session_renewed"
72 #define SEC_PROTOCOL_METADATA_KEY_RESUMPTION_ATTEMPTED "resumption_attempted"
73 #define SEC_PROTOCOL_METADATA_KEY_TICKET_LIFETIME "ticket_lifetime"
74 #define SEC_PROTOCOL_METADATA_KEY_MAX_EARLY_DATA_SUPPORTED "max_early_data_supported"
75 #define SEC_PROTOCOL_METADATA_KEY_OCSP_ENABLED "ocsp_enabled"
76 #define SEC_PROTOCOL_METADATA_KEY_OCSP_RECEIVED "ocsp_received"
77 #define SEC_PROTOCOL_METADATA_KEY_SCT_ENABLED "sct_enabled"
78 #define SEC_PROTOCOL_METADATA_KEY_SCT_RECEIVED "sct_received"
79 #define SEC_PROTOCOL_METADATA_KEY_RSA_SIGNATURE_REQUESTED "client_rsa_requested"
80 #define SEC_PROTOCOL_METADATA_KEY_ECDSA_SIGNATURE_REQUESTED "client_ecdsa_requested"
81 #define SEC_PROTOCOL_METADATA_KEY_FAILURE_ALERT_TYPE "alert_type"
82 #define SEC_PROTOCOL_METADATA_KEY_FAILURE_ALERT_CODE "alert_code"
83 #define SEC_PROTOCOL_METADATA_KEY_FAILURE_HANDSHAKE_STATE "handshake_state"
84 #define SEC_PROTOCOL_METADATA_KEY_FAILURE_STACK_ERROR "stack_error"
85 #define SEC_PROTOCOL_METADATA_KEY_DEFAULT_EMPTY_STRING "none"
86
87 #define CFReleaseSafe(value) \
88 if (value != NULL) { \
89 CFRelease(value); \
90 }
91
92 bool
93 sec_protocol_options_access_handle(sec_protocol_options_t options,
94 sec_access_block_t access_block)
95 {
96 static void *libnetworkImage = NULL;
97 static dispatch_once_t onceToken;
98 static bool (*_nw_protocol_options_access_handle)(void *, sec_access_block_t) = NULL;
99
100 dispatch_once(&onceToken, ^{
101 libnetworkImage = dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY | RTLD_LOCAL);
102 if (NULL != libnetworkImage) {
103 _nw_protocol_options_access_handle = (__typeof(_nw_protocol_options_access_handle))dlsym(libnetworkImage,
104 "nw_protocol_options_access_handle");
105 if (NULL == _nw_protocol_options_access_handle) {
106 os_log_error(OS_LOG_DEFAULT, "dlsym libnetwork nw_protocol_options_access_handle");
107 }
108 } else {
109 os_log_error(OS_LOG_DEFAULT, "dlopen libnetwork");
110 }
111 });
112
113 if (_nw_protocol_options_access_handle == NULL) {
114 return false;
115 }
116
117 return _nw_protocol_options_access_handle(options, access_block);
118 }
119
120 bool
121 sec_protocol_metadata_access_handle(sec_protocol_metadata_t options,
122 sec_access_block_t access_block)
123 {
124 static void *libnetworkImage = NULL;
125 static dispatch_once_t onceToken;
126 static bool (*_nw_protocol_metadata_access_handle)(void *, sec_access_block_t) = NULL;
127
128 dispatch_once(&onceToken, ^{
129 libnetworkImage = dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY | RTLD_LOCAL);
130 if (NULL != libnetworkImage) {
131 _nw_protocol_metadata_access_handle = (__typeof(_nw_protocol_metadata_access_handle))dlsym(libnetworkImage,
132 "nw_protocol_metadata_access_handle");
133 if (NULL == _nw_protocol_metadata_access_handle) {
134 os_log_error(OS_LOG_DEFAULT, "dlsym libnetwork _nw_protocol_metadata_access_handle");
135 }
136 } else {
137 os_log_error(OS_LOG_DEFAULT, "dlopen libnetwork");
138 }
139 });
140
141 if (_nw_protocol_metadata_access_handle == NULL) {
142 return false;
143 }
144
145 return _nw_protocol_metadata_access_handle(options, access_block);
146 }
147
148 #define SEC_PROTOCOL_OPTIONS_VALIDATE(o,r) \
149 if (o == NULL) { \
150 return r; \
151 }
152
153 #define SEC_PROTOCOL_METADATA_VALIDATE(m,r) \
154 if (((void *)m == NULL) || ((size_t)m == 0)) { \
155 return r; \
156 }
157
158 bool
159 sec_protocol_options_contents_are_equal(sec_protocol_options_content_t contentA, sec_protocol_options_content_t contentB)
160 {
161 if (contentA == contentB) {
162 return true;
163 }
164 if (contentA == NULL || contentB == NULL) {
165 return false;
166 }
167
168 sec_protocol_options_content_t optionsA = (sec_protocol_options_content_t)contentA;
169 sec_protocol_options_content_t optionsB = (sec_protocol_options_content_t)contentB;
170
171 // Check boolean and primitive field types first
172 #define CHECK_FIELD(field) \
173 if (optionsA->field != optionsB->field) { \
174 return false; \
175 }
176
177 CHECK_FIELD(min_version);
178 CHECK_FIELD(max_version);
179 CHECK_FIELD(minimum_rsa_key_size);
180 CHECK_FIELD(minimum_ecdsa_key_size);
181 CHECK_FIELD(minimum_signature_algorithm);
182 CHECK_FIELD(tls_ticket_request_count);
183 CHECK_FIELD(ats_required);
184 CHECK_FIELD(ats_minimum_tls_version_allowed);
185 CHECK_FIELD(ats_non_pfs_ciphersuite_allowed);
186 CHECK_FIELD(trusted_peer_certificate);
187 CHECK_FIELD(disable_sni);
188 CHECK_FIELD(enable_fallback_attempt);
189 CHECK_FIELD(enable_false_start);
190 CHECK_FIELD(enable_tickets);
191 CHECK_FIELD(enable_sct);
192 CHECK_FIELD(enable_ocsp);
193 CHECK_FIELD(enforce_ev);
194 CHECK_FIELD(enable_resumption);
195 CHECK_FIELD(enable_renegotiation);
196 CHECK_FIELD(enable_early_data);
197 CHECK_FIELD(peer_authentication_required);
198 CHECK_FIELD(certificate_compression_enabled);
199 CHECK_FIELD(tls_SIKE503_exchange_enabled);
200 CHECK_FIELD(tls_HRSS_exchange_enabled);
201 CHECK_FIELD(eddsa_enabled);
202 CHECK_FIELD(tls_delegated_credentials_enabled);
203 CHECK_FIELD(tls_grease_enabled);
204
205 #undef CHECK_FIELD
206
207 // Check callback block and queue pairs next
208 #define CHECK_BLOCK_QUEUE(block, queue) \
209 if (optionsA->block && optionsB->block) { \
210 if (optionsA->block != optionsB->block) { \
211 return false; \
212 } \
213 if (optionsA->queue != optionsB->queue) { \
214 return false; \
215 } \
216 } else if (optionsA->block || optionsB->block) { \
217 return false; \
218 }
219
220 CHECK_BLOCK_QUEUE(key_update_block, key_update_queue);
221 CHECK_BLOCK_QUEUE(psk_selection_block, psk_selection_queue);
222 CHECK_BLOCK_QUEUE(challenge_block, challenge_queue);
223 CHECK_BLOCK_QUEUE(verify_block, verify_queue);
224 CHECK_BLOCK_QUEUE(tls_secret_update_block, tls_secret_update_queue);
225
226 #undef CHECK_BLOCK_QUEUE
227
228 // Deep compare dispatch data fields
229 #define CHECK_DISPATCH_DATA(data) \
230 if (optionsA->data && optionsB->data) { \
231 if (false == sec_protocol_helper_dispatch_data_equal(optionsA->data, optionsB->data)) { \
232 return false; \
233 } \
234 } else if (optionsA->data || optionsB->data) { \
235 return false; \
236 }
237
238 CHECK_DISPATCH_DATA(dh_params);
239 CHECK_DISPATCH_DATA(quic_transport_parameters);
240 CHECK_DISPATCH_DATA(psk_identity_hint);
241
242 #undef CHECK_DISPATCH_DATA
243
244 // Deep compare XPC objects
245 #define CHECK_XPC_OBJECT(xpc) \
246 if (optionsA->xpc && optionsB->xpc) { \
247 if (false == xpc_equal(optionsA->xpc, optionsB->xpc)) { \
248 return false; \
249 } \
250 } else if (optionsA->xpc || optionsB->xpc) { \
251 return false; \
252 }
253
254 CHECK_XPC_OBJECT(application_protocols);
255 CHECK_XPC_OBJECT(ciphersuites);
256 CHECK_XPC_OBJECT(key_exchange_groups);
257 CHECK_XPC_OBJECT(pre_shared_keys);
258
259 #undef CHECK_XPC_OBJECT
260
261 // Deep compare all other fields
262 if (optionsA->server_name && optionsB->server_name) {
263 if (0 != strcmp(optionsA->server_name, optionsB->server_name)) {
264 return false;
265 }
266 } else if (optionsA->server_name || optionsB->server_name) {
267 return false;
268 }
269
270 if (optionsA->identity && optionsB->identity) {
271 SecIdentityRef identityA = sec_identity_copy_ref((sec_identity_t)optionsA->identity);
272 SecIdentityRef identityB = sec_identity_copy_ref((sec_identity_t)optionsB->identity);
273
274 if (false == CFEqual(identityA, identityB)) {
275 return false;
276 }
277
278 CFRelease(identityA);
279 CFRelease(identityB);
280 } else if (optionsA->identity || optionsB->identity) {
281 return false;
282 }
283
284 if (optionsA->output_handler_access_block && optionsB->output_handler_access_block) {
285 if (optionsA->output_handler_access_block != optionsB->output_handler_access_block) {
286 return false;
287 }
288 } else if (optionsA->output_handler_access_block || optionsB->output_handler_access_block) {
289 return false;
290 }
291
292 return true;
293 }
294
295 bool
296 sec_protocol_options_are_equal(sec_protocol_options_t handleA, sec_protocol_options_t handleB)
297 {
298 if (handleA == handleB) {
299 return true;
300 }
301 if (handleA == NULL || handleB == NULL) {
302 return false;
303 }
304
305 return sec_protocol_options_access_handle(handleA, ^bool(void *innerA) {
306 sec_protocol_options_content_t optionsA = (sec_protocol_options_content_t)innerA;
307 return sec_protocol_options_access_handle(handleB, ^bool(void *innerB) {
308 sec_protocol_options_content_t optionsB = (sec_protocol_options_content_t)innerB;
309 return sec_protocol_options_contents_are_equal(optionsA, optionsB);
310 });
311 });
312 }
313
314 void
315 sec_protocol_options_set_local_identity(sec_protocol_options_t options, sec_identity_t identity)
316 {
317 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
318
319 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
320 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
321 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
322
323 if (content->identity != NULL) {
324 sec_release(content->identity);
325 }
326 content->identity = sec_retain(identity);
327 return true;
328 });
329 }
330
331 void
332 sec_protocol_options_append_tls_ciphersuite(sec_protocol_options_t options, tls_ciphersuite_t ciphersuite)
333 {
334 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
335
336 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
337 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
338 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
339
340 if (content->ciphersuites == NULL) {
341 content->ciphersuites = xpc_array_create(NULL, 0);
342 }
343 xpc_array_set_uint64(content->ciphersuites, XPC_ARRAY_APPEND, (uint64_t)ciphersuite);
344 return true;
345 });
346 }
347
348 void
349 sec_protocol_options_add_tls_ciphersuite(sec_protocol_options_t options, SSLCipherSuite ciphersuite)
350 {
351 sec_protocol_options_append_tls_ciphersuite(options, (tls_ciphersuite_t)ciphersuite);
352 }
353
354 void
355 sec_protocol_options_append_tls_ciphersuite_group(sec_protocol_options_t options, tls_ciphersuite_group_t group)
356 {
357 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
358
359 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
360 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
361 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
362
363 // Fetch the list of ciphersuites associated with the ciphersuite group
364 size_t ciphersuite_count = 0;
365 const tls_ciphersuite_t *list = sec_protocol_helper_ciphersuite_group_to_ciphersuite_list(group, &ciphersuite_count);
366 if (list != NULL) {
367 if (content->ciphersuites == NULL) {
368 content->ciphersuites = xpc_array_create(NULL, 0);
369 }
370
371 for (size_t i = 0; i < ciphersuite_count; i++) {
372 tls_ciphersuite_t ciphersuite = list[i];
373 xpc_array_set_uint64(content->ciphersuites, XPC_ARRAY_APPEND, (uint64_t)ciphersuite);
374 }
375 }
376
377 return true;
378 });
379 }
380
381 void
382 sec_protocol_options_add_tls_ciphersuite_group(sec_protocol_options_t options, SSLCiphersuiteGroup group)
383 {
384 switch (group) {
385 case kSSLCiphersuiteGroupDefault:
386 return sec_protocol_options_append_tls_ciphersuite_group(options, tls_ciphersuite_group_default);
387 case kSSLCiphersuiteGroupCompatibility:
388 return sec_protocol_options_append_tls_ciphersuite_group(options, tls_ciphersuite_group_compatibility);
389 case kSSLCiphersuiteGroupLegacy:
390 return sec_protocol_options_append_tls_ciphersuite_group(options, tls_ciphersuite_group_legacy);
391 case kSSLCiphersuiteGroupATS:
392 return sec_protocol_options_append_tls_ciphersuite_group(options, tls_ciphersuite_group_ats);
393 case kSSLCiphersuiteGroupATSCompatibility:
394 return sec_protocol_options_append_tls_ciphersuite_group(options, tls_ciphersuite_group_ats_compatibility);
395 }
396 }
397
398 void
399 sec_protocol_options_clear_tls_ciphersuites(sec_protocol_options_t options)
400 {
401 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
402
403 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
404 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
405 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
406
407 if (content->ciphersuites != NULL) {
408 xpc_release(content->ciphersuites);
409 content->ciphersuites = NULL;
410 }
411 return true;
412 });
413 }
414
415 void
416 sec_protocol_options_set_tls_min_version(sec_protocol_options_t options, SSLProtocol version)
417 {
418 tls_protocol_version_t protocol_version = (tls_protocol_version_t)SSLProtocolGetVersionCodepoint(version);
419 if (protocol_version != 0) {
420 sec_protocol_options_set_min_tls_protocol_version(options, protocol_version);
421 }
422 }
423
424 void
425 sec_protocol_options_set_min_tls_protocol_version(sec_protocol_options_t options, tls_protocol_version_t version)
426 {
427 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
428
429 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
430 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
431 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
432
433 SSLProtocol converted_protocol = SSLProtocolFromVersionCodepoint(version);
434 content->min_version = converted_protocol;
435 return true;
436 });
437 }
438
439 tls_protocol_version_t
440 sec_protocol_options_get_default_min_tls_protocol_version(void)
441 {
442 return tls_protocol_version_TLSv10;
443 }
444
445 tls_protocol_version_t
446 sec_protocol_options_get_default_min_dtls_protocol_version(void)
447 {
448 return tls_protocol_version_DTLSv10;
449 }
450
451 void
452 sec_protocol_options_set_tls_max_version(sec_protocol_options_t options, SSLProtocol version)
453 {
454 tls_protocol_version_t protocol_version = (tls_protocol_version_t)SSLProtocolGetVersionCodepoint(version);
455 if (protocol_version != 0) {
456 sec_protocol_options_set_max_tls_protocol_version(options, protocol_version);
457 }
458 }
459
460 void
461 sec_protocol_options_set_max_tls_protocol_version(sec_protocol_options_t options, tls_protocol_version_t version)
462 {
463 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
464
465 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
466 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
467 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
468
469 SSLProtocol converted_protocol = SSLProtocolFromVersionCodepoint(version);
470 content->max_version = converted_protocol;
471 return true;
472 });
473 }
474
475 tls_protocol_version_t
476 sec_protocol_options_get_default_max_tls_protocol_version(void)
477 {
478 return tls_protocol_version_TLSv13;
479 }
480
481 tls_protocol_version_t
482 sec_protocol_options_get_default_max_dtls_protocol_version(void)
483 {
484 return tls_protocol_version_DTLSv12;
485 }
486
487 void
488 sec_protocol_options_add_tls_application_protocol(sec_protocol_options_t options, const char *application_protocol)
489 {
490 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
491 SEC_PROTOCOL_OPTIONS_VALIDATE(application_protocol,);
492
493 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
494 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
495 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
496
497 if (content->application_protocols == NULL) {
498 content->application_protocols = xpc_array_create(NULL, 0);
499 }
500 xpc_array_set_string(content->application_protocols, XPC_ARRAY_APPEND, application_protocol);
501 return true;
502 });
503 }
504
505 void
506 sec_protocol_options_set_tls_server_name(sec_protocol_options_t options, const char *server_name)
507 {
508 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
509 SEC_PROTOCOL_OPTIONS_VALIDATE(server_name,);
510
511 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
512 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
513 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
514
515 CFStringRef serverName = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingUTF8);
516 if (serverName == NULL) {
517 return false;
518 }
519 if (!SecFrameworkIsDNSName(serverName)) {
520 CFRelease(serverName);
521 return false;
522 }
523 CFRelease(serverName);
524
525 free(content->server_name);
526 content->server_name = strdup(server_name);
527 return true;
528 });
529 }
530
531 void
532 sec_protocol_options_set_tls_diffie_hellman_parameters(sec_protocol_options_t options, dispatch_data_t params)
533 {
534 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
535 SEC_PROTOCOL_OPTIONS_VALIDATE(params,);
536
537 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
538 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
539 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
540
541 if (content->dh_params) {
542 dispatch_release(content->dh_params);
543 }
544 content->dh_params = params;
545 dispatch_retain(params);
546 return true;
547 });
548 }
549
550 void
551 sec_protocol_options_add_pre_shared_key(sec_protocol_options_t options, dispatch_data_t psk, dispatch_data_t psk_identity)
552 {
553 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
554 SEC_PROTOCOL_OPTIONS_VALIDATE(psk,);
555 SEC_PROTOCOL_OPTIONS_VALIDATE(psk_identity,);
556
557 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
558 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
559 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
560
561 if (content->pre_shared_keys == NULL) {
562 content->pre_shared_keys = xpc_array_create(NULL, 0);
563 }
564
565 xpc_object_t psk_data = xpc_data_create_with_dispatch_data(psk);
566 xpc_object_t psk_identity_data = xpc_data_create_with_dispatch_data(psk_identity);
567
568 xpc_object_t tuple = xpc_array_create(NULL, 0);
569 xpc_array_set_value(tuple, XPC_ARRAY_APPEND, psk_data);
570 xpc_array_set_value(tuple, XPC_ARRAY_APPEND, psk_identity_data);
571 xpc_release(psk_data);
572 xpc_release(psk_identity_data);
573
574 xpc_array_set_value(content->pre_shared_keys, XPC_ARRAY_APPEND, tuple);
575 xpc_release(tuple);
576 return true;
577 });
578 }
579
580 void
581 sec_protocol_options_set_tls_pre_shared_key_identity_hint(sec_protocol_options_t options, dispatch_data_t psk_identity_hint)
582 {
583 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
584 SEC_PROTOCOL_OPTIONS_VALIDATE(psk_identity_hint,);
585
586 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
587 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
588 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
589
590 if (content->psk_identity_hint != NULL) {
591 dispatch_release(content->psk_identity_hint);
592 }
593
594 content->psk_identity_hint = psk_identity_hint;
595 dispatch_retain(psk_identity_hint);
596 return true;
597 });
598 }
599
600 void
601 sec_protocol_options_set_pre_shared_key_selection_block(sec_protocol_options_t options, sec_protocol_pre_shared_key_selection_t psk_selection_block, dispatch_queue_t psk_selection_queue)
602 {
603 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
604 SEC_PROTOCOL_OPTIONS_VALIDATE(psk_selection_block,);
605 SEC_PROTOCOL_OPTIONS_VALIDATE(psk_selection_queue,);
606
607 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
608 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
609 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
610
611 if (content->psk_selection_block != NULL) {
612 Block_release(content->psk_selection_block);
613 }
614 if (content->psk_selection_queue != NULL) {
615 dispatch_release(content->psk_selection_queue);
616 }
617
618 content->psk_selection_block = Block_copy(psk_selection_block);
619 content->psk_selection_queue = psk_selection_queue;
620 dispatch_retain(content->psk_selection_queue);
621 return true;
622 });
623 }
624
625 void
626 sec_protocol_options_set_tls_is_fallback_attempt(sec_protocol_options_t options, bool fallback_attempt)
627 {
628 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
629
630 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
631 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
632 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
633
634 content->enable_fallback_attempt = fallback_attempt;
635 content->enable_fallback_attempt_override = true;
636 return true;
637 });
638 }
639
640 void
641 sec_protocol_options_set_tls_tickets_enabled(sec_protocol_options_t options, bool tickets_enabled)
642 {
643 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
644
645 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
646 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
647 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
648
649 content->enable_tickets = tickets_enabled;
650 content->enable_tickets_override = true;
651 return true;
652 });
653 }
654
655 void
656 sec_protocol_options_set_tls_resumption_enabled(sec_protocol_options_t options, bool resumption_enabled)
657 {
658 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
659
660 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
661 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
662 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
663
664 content->enable_resumption = resumption_enabled;
665 content->enable_resumption_override = true;
666 return true;
667 });
668 }
669
670 void
671 sec_protocol_options_set_tls_false_start_enabled(sec_protocol_options_t options, bool false_start_enabled)
672 {
673 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
674
675 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
676 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
677 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
678
679 content->enable_false_start = false_start_enabled;
680 content->enable_false_start_override = true;
681 return true;
682 });
683 }
684
685 void
686 sec_protocol_options_set_tls_early_data_enabled(sec_protocol_options_t options, bool early_data_enabled)
687 {
688 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
689
690 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
691 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
692 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
693
694 content->enable_early_data = early_data_enabled;
695 content->enable_early_data_override = true;
696 return true;
697 });
698 }
699
700 void
701 sec_protocol_options_set_tls_sni_disabled(sec_protocol_options_t options, bool sni_disabled)
702 {
703 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
704
705 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
706 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
707 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
708
709 content->disable_sni = sni_disabled;
710 content->disable_sni_override = true;
711 return true;
712 });
713 }
714
715 void
716 sec_protocol_options_set_enforce_ev(sec_protocol_options_t options, bool enforce_ev)
717 {
718 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
719
720 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
721 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
722 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
723
724 content->enforce_ev = enforce_ev;
725 content->enforce_ev_override = true;
726 return true;
727 });
728 }
729
730 void
731 sec_protocol_options_set_tls_ocsp_enabled(sec_protocol_options_t options, bool ocsp_enabled)
732 {
733 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
734
735 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
736 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
737 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
738
739 content->enable_ocsp = ocsp_enabled;
740 content->enable_ocsp_override = true;
741 return true;
742 });
743 }
744
745 void
746 sec_protocol_options_set_tls_sct_enabled(sec_protocol_options_t options, bool sct_enabled)
747 {
748 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
749
750 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
751 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
752 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
753
754 content->enable_sct = sct_enabled;
755 content->enable_sct_override = true;
756 return true;
757 });
758 }
759
760 void
761 sec_protocol_options_set_tls_renegotiation_enabled(sec_protocol_options_t options, bool renegotiation_enabled)
762 {
763 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
764
765 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
766 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
767 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
768
769 content->enable_renegotiation = renegotiation_enabled;
770 content->enable_renegotiation_override = true;
771 return true;
772 });
773 }
774
775 void
776 sec_protocol_options_set_peer_authentication_required(sec_protocol_options_t options, bool peer_authentication_required)
777 {
778 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
779
780 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
781 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
782 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
783
784 content->peer_authentication_required = peer_authentication_required;
785 content->peer_authentication_override = true;
786 return true;
787 });
788 }
789
790 void
791 sec_protocol_options_set_key_update_block(sec_protocol_options_t options, sec_protocol_key_update_t update_block, dispatch_queue_t update_queue)
792 {
793 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
794 SEC_PROTOCOL_OPTIONS_VALIDATE(update_queue,);
795
796 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
797 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
798 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
799
800 if (content->key_update_block != NULL) {
801 Block_release(content->key_update_block);
802 }
803 if (content->key_update_queue != NULL) {
804 dispatch_release(content->key_update_queue);
805 }
806
807 content->key_update_block = Block_copy(update_block);
808 content->key_update_queue = Block_copy(update_queue);
809 dispatch_retain(content->key_update_queue);
810 return true;
811 });
812 }
813
814 void
815 sec_protocol_options_set_challenge_block(sec_protocol_options_t options, sec_protocol_challenge_t challenge_block, dispatch_queue_t challenge_queue)
816 {
817 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
818 SEC_PROTOCOL_OPTIONS_VALIDATE(challenge_queue,);
819
820 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
821 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
822 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
823
824 if (content->challenge_block != NULL) {
825 Block_release(content->challenge_block);
826 }
827 if (content->challenge_queue != NULL) {
828 dispatch_release(content->challenge_queue);
829 }
830
831 content->challenge_block = Block_copy(challenge_block);
832 content->challenge_queue = challenge_queue;
833 dispatch_retain(content->challenge_queue);
834 return true;
835 });
836 }
837
838 void
839 sec_protocol_options_set_verify_block(sec_protocol_options_t options, sec_protocol_verify_t verify_block, dispatch_queue_t verify_queue)
840 {
841 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
842 SEC_PROTOCOL_OPTIONS_VALIDATE(verify_queue,);
843
844 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
845 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
846 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
847
848 if (content->verify_block != NULL) {
849 Block_release(content->verify_block);
850 }
851 if (content->verify_queue != NULL) {
852 dispatch_release(content->verify_queue);
853 }
854
855 content->verify_block = Block_copy(verify_block);
856 content->verify_queue = verify_queue;
857 dispatch_retain(content->verify_queue);
858 return true;
859 });
860 }
861
862 void
863 sec_protocol_options_set_session_update_block(sec_protocol_options_t options, sec_protocol_session_update_t update_block, dispatch_queue_t update_queue)
864 {
865 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
866 SEC_PROTOCOL_OPTIONS_VALIDATE(update_block,);
867 SEC_PROTOCOL_OPTIONS_VALIDATE(update_queue,);
868
869 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
870 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
871 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
872
873 if (content->session_update_block != NULL) {
874 Block_release(content->session_update_block);
875 }
876 if (content->session_update_queue != NULL) {
877 dispatch_release(content->session_update_queue);
878 }
879
880 content->session_update_block = Block_copy(update_block);
881 content->session_update_queue = update_queue;
882 dispatch_retain(content->session_update_queue);
883 return true;
884 });
885 }
886
887 void
888 sec_protocol_options_set_tls_encryption_secret_update_block(sec_protocol_options_t options, sec_protocol_tls_encryption_secret_update_t update_block, dispatch_queue_t update_queue)
889 {
890 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
891 SEC_PROTOCOL_OPTIONS_VALIDATE(update_block,);
892 SEC_PROTOCOL_OPTIONS_VALIDATE(update_queue,);
893
894 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
895 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
896 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
897
898 if (content->tls_secret_update_block != NULL) {
899 Block_release(content->tls_secret_update_block);
900 }
901 if (content->tls_secret_update_queue != NULL) {
902 dispatch_release(content->tls_secret_update_queue);
903 }
904
905 content->tls_secret_update_block = Block_copy(update_block);
906 content->tls_secret_update_queue = update_queue;
907 dispatch_retain(content->tls_secret_update_queue);
908 return true;
909 });
910 }
911
912 void
913 sec_protocol_options_set_session_state(sec_protocol_options_t options, dispatch_data_t session_state)
914 {
915 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
916 SEC_PROTOCOL_OPTIONS_VALIDATE(session_state,);
917
918 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
919 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
920 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
921
922 if (content->session_state != NULL) {
923 dispatch_release(content->session_state);
924 }
925
926 content->session_state = session_state;
927 dispatch_retain(session_state);
928 return true;
929 });
930 }
931
932 void
933 sec_protocol_options_set_quic_transport_parameters(sec_protocol_options_t options, dispatch_data_t transport_parameters)
934 {
935 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
936 SEC_PROTOCOL_OPTIONS_VALIDATE(transport_parameters,);
937
938 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
939 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
940 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
941
942 if (content->quic_transport_parameters != NULL) {
943 dispatch_release(content->quic_transport_parameters);
944 }
945
946 content->quic_transport_parameters = transport_parameters;
947 dispatch_retain(transport_parameters);
948 return true;
949 });
950 }
951
952 void
953 sec_protocol_options_set_ats_required(sec_protocol_options_t options, bool required)
954 {
955 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
956
957 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
958 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
959 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
960
961 content->ats_required = required;
962 return true;
963 });
964 }
965
966 void
967 sec_protocol_options_set_minimum_rsa_key_size(sec_protocol_options_t options, size_t minimum_key_size)
968 {
969 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
970
971 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
972 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
973 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
974
975 content->minimum_rsa_key_size = minimum_key_size;
976 return true;
977 });
978 }
979
980 void
981 sec_protocol_options_set_minimum_ecdsa_key_size(sec_protocol_options_t options, size_t minimum_key_size)
982 {
983 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
984
985 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
986 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
987 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
988
989 content->minimum_ecdsa_key_size = minimum_key_size;
990 return true;
991 });
992 }
993
994 void
995 sec_protocol_options_set_minimum_signature_algorithm(sec_protocol_options_t options, SecSignatureHashAlgorithm algorithm)
996 {
997 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
998
999 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1000 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1001 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1002
1003 content->minimum_signature_algorithm = algorithm;
1004 return true;
1005 });
1006 }
1007
1008 void
1009 sec_protocol_options_set_trusted_peer_certificate(sec_protocol_options_t options, bool trusted_peer_certificate)
1010 {
1011 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1012
1013 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1014 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1015 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1016
1017 content->trusted_peer_certificate = trusted_peer_certificate;
1018 content->trusted_peer_certificate_override = true;
1019 return true;
1020 });
1021 }
1022
1023 void
1024 sec_protocol_options_set_private_key_blocks(sec_protocol_options_t options,
1025 sec_protocol_private_key_sign_t sign_block,
1026 sec_protocol_private_key_decrypt_t decrypt_block,
1027 dispatch_queue_t operation_queue)
1028 {
1029 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1030 SEC_PROTOCOL_OPTIONS_VALIDATE(sign_block,);
1031 SEC_PROTOCOL_OPTIONS_VALIDATE(decrypt_block,);
1032 SEC_PROTOCOL_OPTIONS_VALIDATE(operation_queue,);
1033
1034 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1035 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1036 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1037
1038 if (content->private_key_sign_block != NULL) {
1039 Block_release(content->private_key_sign_block);
1040 }
1041 if (content->private_key_decrypt_block != NULL) {
1042 Block_release(content->private_key_decrypt_block);
1043 }
1044 if (content->private_key_queue != NULL) {
1045 dispatch_release(content->private_key_queue);
1046 }
1047
1048 content->private_key_sign_block = Block_copy(sign_block);
1049 content->private_key_decrypt_block = Block_copy(decrypt_block);
1050 content->private_key_queue = operation_queue;
1051 dispatch_retain(content->private_key_queue);
1052
1053 return true;
1054 });
1055 }
1056
1057 void
1058 sec_protocol_options_set_local_certificates(sec_protocol_options_t options, sec_array_t certificates)
1059 {
1060 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1061 SEC_PROTOCOL_OPTIONS_VALIDATE(certificates,);
1062
1063 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1064 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1065 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1066
1067 if (content->certificates != NULL) {
1068 sec_release(content->certificates);
1069 }
1070
1071 content->certificates = certificates;
1072 sec_retain(content->certificates);
1073 return true;
1074 });
1075 }
1076
1077 void
1078 sec_protocol_options_set_tls_certificate_compression_enabled(sec_protocol_options_t options, bool certificate_compression_enabled)
1079 {
1080 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1081
1082 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1083 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1084 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1085
1086 content->certificate_compression_enabled = certificate_compression_enabled;
1087 return true;
1088 });
1089 }
1090
1091 void
1092 sec_protocol_options_set_output_handler_access_block(sec_protocol_options_t options,
1093 sec_protocol_output_handler_access_block_t access_block)
1094 {
1095 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1096 SEC_PROTOCOL_OPTIONS_VALIDATE(access_block,);
1097
1098 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1099 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1100 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1101
1102 content->output_handler_access_block = Block_copy(access_block);
1103 return true;
1104 });
1105 }
1106
1107 void
1108 sec_protocol_options_tls_handshake_message_callback(sec_protocol_options_t options, sec_protocol_tls_handshake_message_handler_t handler, dispatch_queue_t queue)
1109 {
1110 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1111 SEC_PROTOCOL_OPTIONS_VALIDATE(handler,);
1112 SEC_PROTOCOL_OPTIONS_VALIDATE(queue,);
1113
1114 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1115 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1116 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1117
1118 if (content->handshake_message_callback != NULL) {
1119 Block_release(content->handshake_message_callback);
1120 }
1121 if (content->handshake_message_callback_queue != NULL) {
1122 dispatch_release(content->handshake_message_callback_queue);
1123 }
1124
1125 content->handshake_message_callback = Block_copy(handler);
1126 content->handshake_message_callback_queue = queue;
1127 dispatch_retain(content->handshake_message_callback_queue);
1128
1129 return true;
1130 });
1131 }
1132
1133 void
1134 sec_protocol_options_set_tls_SIKE503_exchange_enabled(sec_protocol_options_t options, bool tls_SIKE503_exchange_enabled)
1135 {
1136 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1137
1138 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1139 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1140 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1141
1142 content->tls_SIKE503_exchange_enabled = tls_SIKE503_exchange_enabled;
1143 return true;
1144 });
1145 }
1146
1147 void
1148 sec_protocol_options_set_tls_HRSS_exchange_enabled(sec_protocol_options_t options, bool tls_HRSS_exchange_enabled)
1149 {
1150 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1151
1152 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1153 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1154 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1155
1156 content->tls_HRSS_exchange_enabled = tls_HRSS_exchange_enabled;
1157 return true;
1158 });
1159 }
1160
1161 void
1162 sec_protocol_options_set_eddsa_enabled(sec_protocol_options_t options, bool eddsa_enabled)
1163 {
1164 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1165
1166 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1167 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1168 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1169
1170 content->eddsa_enabled = eddsa_enabled;
1171 return true;
1172 });
1173 }
1174
1175 void
1176 sec_protocol_options_set_tls_delegated_credentials_enabled(sec_protocol_options_t options, bool tls_delegated_credentials_enabled)
1177 {
1178 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1179
1180 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1181 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1182 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1183
1184 content->tls_delegated_credentials_enabled = tls_delegated_credentials_enabled;
1185 return true;
1186 });
1187 }
1188
1189 void
1190 sec_protocol_options_set_tls_grease_enabled(sec_protocol_options_t options, bool tls_grease_enabled)
1191 {
1192 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1193
1194 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1195 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1196 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1197
1198 content->tls_grease_enabled = tls_grease_enabled;
1199 return true;
1200 });
1201 }
1202
1203 void
1204 sec_protocol_options_set_tls_ticket_request_count(sec_protocol_options_t options, uint8_t tls_ticket_request_count)
1205 {
1206 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1207
1208 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1209 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1210 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1211
1212 content->tls_ticket_request_count = tls_ticket_request_count;
1213 return true;
1214 });
1215 }
1216
1217 void
1218 sec_protocol_options_set_ats_non_pfs_ciphersuite_allowed(sec_protocol_options_t options, bool ats_non_pfs_ciphersuite_allowed)
1219 {
1220 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1221
1222 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1223 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1224 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1225
1226 content->ats_non_pfs_ciphersuite_allowed = ats_non_pfs_ciphersuite_allowed;
1227 return true;
1228 });
1229 }
1230
1231 void
1232 sec_protocol_options_set_ats_minimum_tls_version_allowed(sec_protocol_options_t options, bool ats_minimum_tls_version_allowed)
1233 {
1234 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1235
1236 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1237 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1238 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1239
1240 content->ats_minimum_tls_version_allowed = ats_minimum_tls_version_allowed;
1241 return true;
1242 });
1243 }
1244
1245 void
1246 sec_protocol_options_append_tls_key_exchange_group(sec_protocol_options_t options, tls_key_exchange_group_t group)
1247 {
1248 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1249
1250 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1251 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1252 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1253
1254 if (content->key_exchange_groups == NULL) {
1255 content->key_exchange_groups = xpc_array_create(NULL, 0);
1256 }
1257 xpc_array_set_uint64(content->key_exchange_groups, XPC_ARRAY_APPEND, (uint64_t)group);
1258 return true;
1259 });
1260 }
1261
1262 void
1263 sec_protocol_options_add_tls_key_exchange_group(sec_protocol_options_t options, SSLKeyExchangeGroup group)
1264 {
1265 return sec_protocol_options_append_tls_key_exchange_group(options, (tls_key_exchange_group_t)group);
1266 }
1267
1268 void
1269 sec_protocol_options_append_tls_key_exchange_group_set(sec_protocol_options_t options, tls_key_exchange_group_set_t set)
1270 {
1271 SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
1272
1273 (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
1274 sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
1275 SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
1276
1277 if (content->key_exchange_groups == NULL) {
1278 content->key_exchange_groups = xpc_array_create(NULL, 0);
1279 }
1280
1281 // Fetch the list of ciphersuites associated with the ciphersuite group
1282 size_t group_set_count = 0;
1283 const tls_key_exchange_group_t *group_set = sec_protocol_helper_tls_key_exchange_group_set_to_key_exchange_group_list(set, &group_set_count);
1284 if (group_set != NULL) {
1285 for (size_t i = 0; i < group_set_count; i++) {
1286 tls_key_exchange_group_t group = group_set[i];
1287 xpc_array_set_uint64(content->key_exchange_groups, XPC_ARRAY_APPEND, (uint64_t)group);
1288 }
1289 }
1290
1291 return true;
1292 });
1293 }
1294
1295 void
1296 sec_protocol_options_add_tls_key_exchange_group_set(sec_protocol_options_t options, SSLKeyExchangeGroupSet set)
1297 {
1298 switch (set) {
1299 case kSSLKeyExchangeGroupSetDefault:
1300 sec_protocol_options_append_tls_key_exchange_group_set(options, tls_key_exchange_group_set_default);
1301 break;
1302 case kSSLKeyExchangeGroupSetCompatibility:
1303 sec_protocol_options_append_tls_key_exchange_group_set(options, tls_key_exchange_group_set_compatibility);
1304 break;
1305 case kSSLKeyExchangeGroupSetLegacy:
1306 sec_protocol_options_append_tls_key_exchange_group_set(options, tls_key_exchange_group_set_legacy);
1307 break;
1308 }
1309 }
1310
1311 const char *
1312 sec_protocol_metadata_get_negotiated_protocol(sec_protocol_metadata_t metadata)
1313 {
1314 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
1315
1316 __block const char *negotiated_protocol = NULL;
1317 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1318 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1319 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1320 negotiated_protocol = content->negotiated_protocol;
1321 return true;
1322 });
1323
1324 return negotiated_protocol;
1325 }
1326
1327 const char *
1328 sec_protocol_metadata_get_server_name(sec_protocol_metadata_t metadata)
1329 {
1330 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
1331
1332 __block const char *server_name = NULL;
1333 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1334 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1335 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1336 server_name = content->server_name;
1337 return true;
1338 });
1339
1340 return server_name;
1341 }
1342
1343 uint64_t
1344 sec_protocol_metadata_get_handshake_time_ms(sec_protocol_metadata_t metadata)
1345 {
1346 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0);
1347
1348 __block uint64_t time = 0;
1349 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
1350 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
1351 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
1352 time = metadata_content->handshake_time;
1353 return true;
1354 });
1355
1356 return time;
1357 }
1358
1359 uint64_t
1360 sec_protocol_metadata_get_handshake_byte_count(sec_protocol_metadata_t metadata)
1361 {
1362 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0);
1363
1364 __block uint64_t count = 0;
1365 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
1366 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
1367 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
1368 count = metadata_content->total_byte_count;
1369 return true;
1370 });
1371
1372 return count;
1373 }
1374
1375 uint64_t
1376 sec_protocol_metadata_get_handshake_sent_byte_count(sec_protocol_metadata_t metadata)
1377 {
1378 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0);
1379
1380 __block uint64_t count = 0;
1381 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
1382 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
1383 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
1384 count = metadata_content->sent_byte_count;
1385 return true;
1386 });
1387
1388 return count;
1389 }
1390
1391 uint64_t
1392 sec_protocol_metadata_get_handshake_received_byte_count(sec_protocol_metadata_t metadata)
1393 {
1394 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0);
1395
1396 __block uint64_t count = 0;
1397 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
1398 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
1399 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
1400 count = metadata_content->received_byte_count;
1401 return true;
1402 });
1403
1404 return count;
1405 }
1406
1407 size_t
1408 sec_protocol_metadata_get_handshake_read_stall_count(sec_protocol_metadata_t metadata)
1409 {
1410 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0);
1411
1412 __block size_t count = 0;
1413 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
1414 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
1415 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
1416 count = metadata_content->read_stall_count;
1417 return true;
1418 });
1419
1420 return count;
1421 }
1422
1423 size_t
1424 sec_protocol_metadata_get_handshake_write_stall_count(sec_protocol_metadata_t metadata)
1425 {
1426 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0);
1427
1428 __block size_t count = 0;
1429 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
1430 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
1431 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
1432 count = metadata_content->write_stall_count;
1433 return true;
1434 });
1435
1436 return count;
1437 }
1438
1439 size_t
1440 sec_protocol_metadata_get_handshake_async_call_count(sec_protocol_metadata_t metadata)
1441 {
1442 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0);
1443
1444 __block size_t count = 0;
1445 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
1446 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
1447 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
1448 count = metadata_content->async_call_count;
1449 return true;
1450 });
1451
1452 return count;
1453 }
1454
1455 bool
1456 sec_protocol_metadata_access_peer_certificate_chain(sec_protocol_metadata_t metadata,
1457 void (^handler)(sec_certificate_t certficate))
1458 {
1459 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1460 SEC_PROTOCOL_METADATA_VALIDATE(handler, false);
1461
1462 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1463 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1464 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1465 if (content->peer_certificate_chain == NULL) {
1466 return false;
1467 }
1468 sec_array_t array = content->peer_certificate_chain;
1469 sec_array_apply(array, ^bool(__unused size_t index, sec_object_t object) {
1470 handler((sec_certificate_t)object);
1471 return true;
1472 });
1473 return true;
1474 });
1475 }
1476
1477 dispatch_data_t
1478 sec_protocol_metadata_copy_peer_public_key(sec_protocol_metadata_t metadata)
1479 {
1480 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
1481
1482 __block dispatch_data_t peer_public_key = NULL;
1483 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1484 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1485 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1486 peer_public_key = ((dispatch_data_t)content->peer_public_key);
1487 if (peer_public_key) {
1488 dispatch_retain(peer_public_key);
1489 }
1490 return true;
1491 });
1492
1493 return peer_public_key;
1494 }
1495
1496 tls_protocol_version_t
1497 sec_protocol_metadata_get_negotiated_tls_protocol_version(sec_protocol_metadata_t metadata)
1498 {
1499 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0x0000);
1500
1501 __block tls_protocol_version_t protocol_version = 0x0000;
1502 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1503 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1504 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1505 protocol_version = SSLProtocolGetVersionCodepoint(content->negotiated_protocol_version);
1506 return true;
1507 });
1508
1509 return protocol_version;
1510 }
1511
1512 SSLProtocol
1513 sec_protocol_metadata_get_negotiated_protocol_version(sec_protocol_metadata_t metadata)
1514 {
1515 SEC_PROTOCOL_METADATA_VALIDATE(metadata, kSSLProtocolUnknown);
1516
1517 __block SSLProtocol protocol_version = kSSLProtocolUnknown;
1518 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1519 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1520 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1521 protocol_version = content->negotiated_protocol_version;
1522 return true;
1523 });
1524
1525 return protocol_version;
1526 }
1527
1528 tls_ciphersuite_t
1529 sec_protocol_metadata_get_negotiated_tls_ciphersuite(sec_protocol_metadata_t metadata)
1530 {
1531 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0xFFFF);
1532
1533 __block tls_ciphersuite_t negotiated_ciphersuite = SSL_NO_SUCH_CIPHERSUITE;
1534 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1535 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1536 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1537 negotiated_ciphersuite = content->negotiated_ciphersuite;
1538 return true;
1539 });
1540
1541 return negotiated_ciphersuite;
1542 }
1543
1544 SSLCipherSuite
1545 sec_protocol_metadata_get_negotiated_ciphersuite(sec_protocol_metadata_t metadata)
1546 {
1547 return (SSLCipherSuite)sec_protocol_metadata_get_negotiated_tls_ciphersuite(metadata);
1548 }
1549
1550 bool
1551 sec_protocol_metadata_get_early_data_accepted(sec_protocol_metadata_t metadata)
1552 {
1553 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1554
1555 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1556 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1557 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1558 return content->early_data_accepted;
1559 });
1560 }
1561
1562 bool
1563 sec_protocol_metadata_access_supported_signature_algorithms(sec_protocol_metadata_t metadata,
1564 void (^handler)(uint16_t signature_algorithm))
1565 {
1566 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1567 SEC_PROTOCOL_METADATA_VALIDATE(handler, false);
1568
1569 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1570 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1571 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1572 if (content->supported_signature_algorithms == NULL) {
1573 return false;
1574 }
1575 xpc_object_t array = content->supported_signature_algorithms;
1576 xpc_array_apply(array, ^bool(__unused size_t index, xpc_object_t _Nonnull value) {
1577 handler((uint16_t)xpc_uint64_get_value(value));
1578 return true;
1579 });
1580 return true;
1581 });
1582 }
1583
1584 bool
1585 sec_protocol_metadata_access_ocsp_response(sec_protocol_metadata_t metadata,
1586 void (^handler)(dispatch_data_t ocsp_data))
1587 {
1588 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1589 SEC_PROTOCOL_METADATA_VALIDATE(handler, false);
1590
1591 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1592 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1593 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1594 if (content->ocsp_response == NULL) {
1595 return false;
1596 }
1597 sec_array_t array = content->ocsp_response;
1598 sec_array_apply(array, ^bool(__unused size_t index, sec_object_t object) {
1599 handler((dispatch_data_t)object);
1600 return true;
1601 });
1602 return true;
1603 });
1604 }
1605
1606 bool
1607 sec_protocol_metadata_access_distinguished_names(sec_protocol_metadata_t metadata,
1608 void (^handler)(dispatch_data_t distinguished_name))
1609 {
1610 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1611 SEC_PROTOCOL_METADATA_VALIDATE(handler, false);
1612
1613 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1614 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1615 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1616 if (content->distinguished_names == NULL) {
1617 return false;
1618 }
1619 sec_array_t array = content->distinguished_names;
1620 sec_array_apply(array, ^bool(__unused size_t index, sec_object_t object) {
1621 handler((dispatch_data_t)object);
1622 return true;
1623 });
1624 return true;
1625 });
1626 }
1627
1628 static dispatch_data_t
1629 create_dispatch_data_from_xpc_data(xpc_object_t xpc_data)
1630 {
1631 if (!xpc_data) {
1632 return nil;
1633 }
1634
1635 size_t data_len = xpc_data_get_length(xpc_data);
1636 if (data_len == 0) {
1637 return nil;
1638 }
1639
1640 uint8_t *data_buffer = malloc(data_len);
1641 if (!data_buffer) {
1642 return nil;
1643 }
1644
1645 size_t copied_count = xpc_data_get_bytes(xpc_data, data_buffer, 0, data_len);
1646 if (copied_count != data_len) {
1647 free(data_buffer);
1648 return nil;
1649 }
1650
1651 dispatch_data_t data = dispatch_data_create(data_buffer, data_len, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
1652 free(data_buffer);
1653
1654 return data;
1655 }
1656
1657 bool
1658 sec_protocol_metadata_access_pre_shared_keys(sec_protocol_metadata_t metadata,
1659 void (^handler)(dispatch_data_t psk, dispatch_data_t _Nullable psk_identity))
1660 {
1661 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1662 SEC_PROTOCOL_METADATA_VALIDATE(handler, false);
1663
1664 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1665 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1666 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1667 if (content->pre_shared_keys == NULL) {
1668 return false;
1669 }
1670 xpc_array_apply(content->pre_shared_keys, ^bool(size_t index, xpc_object_t _Nonnull tuple) {
1671 if (xpc_array_get_count(tuple) == 2) {
1672 xpc_object_t xpc_psk_data = xpc_array_get_value(tuple, 0);
1673 xpc_object_t xpc_psk_identity_data = xpc_array_get_value(tuple, 1);
1674
1675 dispatch_data_t psk_data = create_dispatch_data_from_xpc_data(xpc_psk_data);
1676 dispatch_data_t psk_identity_data = create_dispatch_data_from_xpc_data(xpc_psk_identity_data);
1677 if (!psk_data || !psk_identity_data) {
1678 // Skip and return early if we can't create a PSK or identity from the provided data. Something's wrong.
1679 return false;
1680 }
1681
1682 handler(psk_data, psk_identity_data);
1683 }
1684 return true;
1685 });
1686 return true;
1687 });
1688 }
1689
1690 static bool
1691 sec_protocol_dispatch_data_are_equal(dispatch_data_t left, dispatch_data_t right)
1692 {
1693 if (!left || !right || left == right) {
1694 return left == right;
1695 }
1696 if (dispatch_data_get_size(left) != dispatch_data_get_size(right)) {
1697 return false;
1698 }
1699
1700 __block bool equal = true;
1701 dispatch_data_apply(left, ^bool(__unused dispatch_data_t _Nonnull lregion, size_t loffset, const void * _Nonnull lbuffer, size_t lsize) {
1702 dispatch_data_apply(right, ^bool(__unused dispatch_data_t _Nonnull rregion, size_t roffset, const void * _Nonnull rbuffer, size_t rsize) {
1703 // There is some overlap
1704 const size_t start = MAX(loffset, roffset);
1705 const size_t end = MIN(loffset + lsize, roffset + rsize);
1706 if (start < end) {
1707 equal = memcmp(&((const uint8_t*)rbuffer)[start - roffset], &((const uint8_t*)lbuffer)[start - loffset], end - start) == 0;
1708 } else {
1709 if (roffset > loffset + lsize) {
1710 // Iteration of right has gone past where we're at on left, bail out of inner apply
1711 // left |---|
1712 // right |---|
1713 return false;
1714 } else if (roffset + rsize < loffset) {
1715 // Iteration of right has not yet reached where we're at on left, keep going
1716 // left |---|
1717 // right |--|
1718 return true;
1719 }
1720 }
1721 return equal;
1722 });
1723 return equal;
1724 });
1725 return equal;
1726 }
1727
1728 static bool
1729 sec_protocol_sec_array_of_dispatch_data_are_equal(sec_array_t arrayA, sec_array_t arrayB)
1730 {
1731 if (sec_array_get_count(arrayA) != sec_array_get_count(arrayB)) {
1732 return false;
1733 }
1734
1735 __block bool equal = true;
1736 (void)sec_array_apply(arrayA, ^bool(size_t indexA, sec_object_t objectA) {
1737 return sec_array_apply(arrayB, ^bool(size_t indexB, sec_object_t objectB) {
1738 if (indexA == indexB) {
1739 dispatch_data_t dataA = (dispatch_data_t)objectA;
1740 dispatch_data_t dataB = (dispatch_data_t)objectB;
1741 equal &= sec_protocol_dispatch_data_are_equal(dataA, dataB);
1742 return equal;
1743 }
1744 return true;
1745 });
1746 });
1747
1748 return equal;
1749 }
1750
1751 static bool
1752 sec_protocol_sec_array_of_sec_certificate_are_equal(sec_array_t arrayA, sec_array_t arrayB)
1753 {
1754 if (sec_array_get_count(arrayA) != sec_array_get_count(arrayB)) {
1755 return false;
1756 }
1757
1758 __block bool equal = true;
1759 (void)sec_array_apply(arrayA, ^bool(size_t indexA, sec_object_t objectA) {
1760 return sec_array_apply(arrayB, ^bool(size_t indexB, sec_object_t objectB) {
1761 if (indexA == indexB) {
1762 sec_certificate_t certA = (sec_certificate_t)objectA;
1763 sec_certificate_t certB = (sec_certificate_t)objectB;
1764
1765 SecCertificateRef certRefA = sec_certificate_copy_ref(certA);
1766 SecCertificateRef certRefB = sec_certificate_copy_ref(certB);
1767
1768 if (certRefA == NULL && certRefB != NULL) {
1769 equal = false;
1770 } else if (certRefA != NULL && certRefB == NULL) {
1771 equal = false;
1772 } else if (certRefA == NULL && certRefB == NULL) {
1773 // pass
1774 } else {
1775 equal &= CFEqual(certRefA, certRefB);
1776 }
1777
1778 CFReleaseSafe(certRefA);
1779 CFReleaseSafe(certRefB);
1780
1781 return equal;
1782 }
1783 return true;
1784 });
1785 });
1786
1787 return equal;
1788 }
1789
1790 static bool
1791 sec_protocol_xpc_object_are_equal(xpc_object_t objectA, xpc_object_t objectB)
1792 {
1793 if (objectA == NULL && objectB != NULL) {
1794 return false;
1795 } else if (objectA != NULL && objectB == NULL) {
1796 return false;
1797 } else if (objectA == NULL && objectB == NULL) {
1798 return true;
1799 } else {
1800 return xpc_equal(objectA, objectB);
1801 }
1802 }
1803
1804 bool
1805 sec_protocol_metadata_peers_are_equal(sec_protocol_metadata_t metadataA, sec_protocol_metadata_t metadataB)
1806 {
1807 SEC_PROTOCOL_METADATA_VALIDATE(metadataA, false);
1808 SEC_PROTOCOL_METADATA_VALIDATE(metadataB, false);
1809
1810 return sec_protocol_metadata_access_handle(metadataA, ^bool(void *handleA) {
1811 sec_protocol_metadata_content_t contentA = (sec_protocol_metadata_content_t)handleA;
1812 SEC_PROTOCOL_METADATA_VALIDATE(contentA, false);
1813
1814 return sec_protocol_metadata_access_handle(metadataB, ^bool(void *handleB) {
1815 sec_protocol_metadata_content_t contentB = (sec_protocol_metadata_content_t)handleB;
1816 SEC_PROTOCOL_METADATA_VALIDATE(contentB, false);
1817
1818 // Relevant peer information includes: Certificate chain, public key, support signature algorithms, OCSP response, and distinguished names
1819 if (!sec_protocol_sec_array_of_sec_certificate_are_equal(contentA->peer_certificate_chain, contentB->peer_certificate_chain)) {
1820 return false;
1821 }
1822 if (!sec_protocol_dispatch_data_are_equal((dispatch_data_t)contentA->peer_public_key, (dispatch_data_t)contentB->peer_public_key)) {
1823 return false;
1824 }
1825 if (!sec_protocol_xpc_object_are_equal((xpc_object_t)contentA->supported_signature_algorithms, (xpc_object_t)contentB->supported_signature_algorithms)) {
1826 return false;
1827 }
1828 if (!sec_protocol_sec_array_of_dispatch_data_are_equal(contentA->ocsp_response, contentB->ocsp_response)) {
1829 return false;
1830 }
1831 if (!sec_protocol_sec_array_of_dispatch_data_are_equal(contentA->distinguished_names, contentB->distinguished_names)) {
1832 return false;
1833 }
1834
1835 return true;
1836 });
1837 });
1838 }
1839
1840 bool
1841 sec_protocol_metadata_challenge_parameters_are_equal(sec_protocol_metadata_t metadataA, sec_protocol_metadata_t metadataB)
1842 {
1843 SEC_PROTOCOL_METADATA_VALIDATE(metadataA, false);
1844 SEC_PROTOCOL_METADATA_VALIDATE(metadataB, false);
1845
1846 return sec_protocol_metadata_access_handle(metadataA, ^bool(void *handleA) {
1847 sec_protocol_metadata_content_t contentA = (sec_protocol_metadata_content_t)handleA;
1848 SEC_PROTOCOL_METADATA_VALIDATE(contentA, false);
1849
1850 return sec_protocol_metadata_access_handle(metadataB, ^bool(void *handleB) {
1851 sec_protocol_metadata_content_t contentB = (sec_protocol_metadata_content_t)handleB;
1852 SEC_PROTOCOL_METADATA_VALIDATE(contentB, false);
1853
1854 if (!sec_protocol_xpc_object_are_equal((xpc_object_t)contentA->supported_signature_algorithms, (xpc_object_t)contentB->supported_signature_algorithms)) {
1855 return false;
1856 }
1857 if (!sec_protocol_sec_array_of_dispatch_data_are_equal(contentA->distinguished_names, contentB->distinguished_names)) {
1858 return false;
1859 }
1860 if (!sec_protocol_dispatch_data_are_equal(contentA->request_certificate_types, contentB->request_certificate_types)) {
1861 return false;
1862 }
1863
1864 return true;
1865 });
1866 });
1867 }
1868
1869 dispatch_data_t
1870 sec_protocol_metadata_create_secret(sec_protocol_metadata_t metadata, size_t label_len,
1871 const char *label, size_t exporter_length)
1872 {
1873 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
1874 SEC_PROTOCOL_METADATA_VALIDATE(label_len, NULL);
1875 SEC_PROTOCOL_METADATA_VALIDATE(label, NULL);
1876 SEC_PROTOCOL_METADATA_VALIDATE(exporter_length, NULL);
1877
1878 __block dispatch_data_t secret = NULL;
1879 sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1880 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1881 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1882
1883 if (content->exporter_function && content->exporter_context) {
1884 sec_protocol_metadata_exporter exporter = (sec_protocol_metadata_exporter)content->exporter_function;
1885 secret = exporter(content->exporter_context, label_len, label, 0, NULL, exporter_length);
1886 }
1887 return true;
1888 });
1889 return secret;
1890 }
1891
1892 dispatch_data_t
1893 sec_protocol_metadata_create_secret_with_context(sec_protocol_metadata_t metadata, size_t label_len,
1894 const char *label, size_t context_len,
1895 const uint8_t *context, size_t exporter_length)
1896 {
1897 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
1898 SEC_PROTOCOL_METADATA_VALIDATE(label_len, NULL);
1899 SEC_PROTOCOL_METADATA_VALIDATE(label, NULL);
1900 SEC_PROTOCOL_METADATA_VALIDATE(context_len, NULL);
1901 SEC_PROTOCOL_METADATA_VALIDATE(context, NULL);
1902 SEC_PROTOCOL_METADATA_VALIDATE(exporter_length, NULL);
1903
1904 __block dispatch_data_t secret = NULL;
1905 sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1906 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1907 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1908
1909 if (content->exporter_function && content->exporter_context) {
1910 sec_protocol_metadata_exporter exporter = (sec_protocol_metadata_exporter)content->exporter_function;
1911 secret = exporter(content->exporter_context, label_len, label, context_len, context, exporter_length);
1912 }
1913 return true;
1914 });
1915 return secret;
1916 }
1917
1918 bool
1919 sec_protocol_metadata_get_tls_false_start_used(sec_protocol_metadata_t metadata)
1920 {
1921 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1922
1923 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1924 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1925 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1926 return content->false_start_used;
1927 });
1928 }
1929
1930 bool
1931 sec_protocol_metadata_get_ticket_offered(sec_protocol_metadata_t metadata)
1932 {
1933 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1934
1935 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1936 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1937 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1938 return content->ticket_offered;
1939 });
1940 }
1941
1942 bool
1943 sec_protocol_metadata_get_ticket_received(sec_protocol_metadata_t metadata)
1944 {
1945 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1946
1947 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1948 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1949 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1950 return content->ticket_received;
1951 });
1952 }
1953
1954 bool
1955 sec_protocol_metadata_get_session_resumed(sec_protocol_metadata_t metadata)
1956 {
1957 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1958
1959 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1960 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1961 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1962 return content->session_resumed;
1963 });
1964 }
1965
1966 bool
1967 sec_protocol_metadata_get_session_renewed(sec_protocol_metadata_t metadata)
1968 {
1969 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
1970
1971 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1972 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1973 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1974 return content->session_renewed;
1975 });
1976 }
1977
1978 SSLConnectionStrength
1979 sec_protocol_metadata_get_connection_strength(sec_protocol_metadata_t metadata)
1980 {
1981 SEC_PROTOCOL_METADATA_VALIDATE(metadata, SSLConnectionStrengthNonsecure);
1982
1983 __block SSLConnectionStrength strength = SSLConnectionStrengthNonsecure;
1984 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
1985 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
1986 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
1987
1988 // TLSv1.2 and higher are considered strong. Anything less than TLSv1.2 is considered weak at best.
1989 #pragma clang diagnostic push
1990 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1991 SSLProtocol version = content->negotiated_protocol_version;
1992 if (version >= kTLSProtocol12) {
1993 strength = SSLConnectionStrengthStrong;
1994 } else if (version == kTLSProtocol11 || version == kTLSProtocol1) {
1995 strength = SSLConnectionStrengthWeak;
1996 } else {
1997 strength = SSLConnectionStrengthNonsecure;
1998 }
1999
2000 // Legacy ciphersuites make the connection weak, for now. We may consider changing this to nonsecure.
2001 SSLCipherSuite ciphersuite = content->negotiated_ciphersuite;
2002 if (strength != SSLConnectionStrengthNonsecure &&
2003 SSLCiphersuiteGroupContainsCiphersuite(kSSLCiphersuiteGroupLegacy, ciphersuite)) {
2004 strength = SSLConnectionStrengthWeak;
2005 }
2006 #pragma clang diagnostic pop
2007
2008 return true;
2009 });
2010
2011 return strength;
2012 }
2013
2014 dispatch_data_t
2015 sec_protocol_metadata_copy_serialized_session(sec_protocol_metadata_t metadata)
2016 {
2017 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
2018
2019 __block dispatch_data_t session = NULL;
2020 sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
2021 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
2022 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
2023
2024 if (content->session_exporter_function && content->session_exporter_context) {
2025 sec_protocol_metadata_session_exporter exporter = (sec_protocol_metadata_session_exporter)content->session_exporter_function;
2026 session = exporter(content->session_exporter_context);
2027 }
2028 return true;
2029 });
2030 return session;
2031 }
2032
2033 static const char *_options_uint64_keys[] = {
2034 SEC_PROTOCOL_OPTIONS_KEY_min_version,
2035 SEC_PROTOCOL_OPTIONS_KEY_max_version,
2036 SEC_PROTOCOL_OPTIONS_KEY_minimum_rsa_key_size,
2037 SEC_PROTOCOL_OPTIONS_KEY_minimum_ecdsa_key_size,
2038 SEC_PROTOCOL_OPTIONS_KEY_minimum_signature_algorithm,
2039 SEC_PROTOCOL_OPTIONS_KEY_tls_ticket_request_count,
2040 };
2041 static const size_t _options_uint64_keys_len = sizeof(_options_uint64_keys) / sizeof(_options_uint64_keys[0]);
2042
2043 static const char *_options_bool_keys[] = {
2044 SEC_PROTOCOL_OPTIONS_KEY_ats_required,
2045 SEC_PROTOCOL_OPTIONS_KEY_ats_minimum_tls_version_allowed,
2046 SEC_PROTOCOL_OPTIONS_KEY_ats_non_pfs_ciphersuite_allowed,
2047 SEC_PROTOCOL_OPTIONS_KEY_trusted_peer_certificate,
2048 SEC_PROTOCOL_OPTIONS_KEY_disable_sni,
2049 SEC_PROTOCOL_OPTIONS_KEY_enable_fallback_attempt,
2050 SEC_PROTOCOL_OPTIONS_KEY_enable_false_start,
2051 SEC_PROTOCOL_OPTIONS_KEY_enable_tickets,
2052 SEC_PROTOCOL_OPTIONS_KEY_enable_sct,
2053 SEC_PROTOCOL_OPTIONS_KEY_enable_ocsp,
2054 SEC_PROTOCOL_OPTIONS_KEY_enforce_ev,
2055 SEC_PROTOCOL_OPTIONS_KEY_enable_resumption,
2056 SEC_PROTOCOL_OPTIONS_KEY_enable_renegotiation,
2057 SEC_PROTOCOL_OPTIONS_KEY_enable_early_data,
2058 SEC_PROTOCOL_OPTIONS_KEY_peer_authentication_required,
2059 SEC_PROTOCOL_OPTIONS_KEY_certificate_compression_enabled,
2060 SEC_PROTOCOL_OPTIONS_KEY_tls_SIKE503_exchange_enabled,
2061 SEC_PROTOCOL_OPTIONS_KEY_tls_HRSS_exchange_enabled,
2062 SEC_PROTOCOL_OPTIONS_KEY_eddsa_enabled,
2063 SEC_PROTOCOL_OPTIONS_KEY_tls_delegated_credentials_enabled,
2064 SEC_PROTOCOL_OPTIONS_KEY_tls_grease_enabled,
2065
2066 };
2067 static const size_t _options_bool_keys_len = sizeof(_options_bool_keys) / sizeof(_options_bool_keys[0]);
2068
2069 static bool
2070 _dictionary_has_key(xpc_object_t dict, const char *target_key)
2071 {
2072 if (xpc_get_type(dict) != XPC_TYPE_DICTIONARY) {
2073 return false;
2074 }
2075
2076 return !xpc_dictionary_apply(dict, ^bool(const char * _Nonnull key, xpc_object_t _Nonnull value) {
2077 if (strncmp(key, target_key, strlen(target_key)) == 0) {
2078 return false;
2079 }
2080 return true;
2081 });
2082 }
2083
2084 static bool
2085 _arrays_uint64_contents_are_equal(xpc_object_t arrayA, xpc_object_t arrayB)
2086 {
2087 if (xpc_array_get_count(arrayA) != xpc_array_get_count(arrayB)) {
2088 return false;
2089 }
2090
2091 return xpc_array_apply(arrayA, ^bool(size_t indexA, xpc_object_t _Nonnull valueA) {
2092 uint64_t raw_valueA = xpc_array_get_uint64(arrayA, indexA);
2093
2094 bool contains_value = !xpc_array_apply(arrayB, ^bool(size_t indexB, xpc_object_t _Nonnull valueB) {
2095 uint64_t raw_valueB = xpc_array_get_uint64(arrayB, indexB);
2096 if (raw_valueA == raw_valueB) {
2097 return false;
2098 }
2099 return true;
2100 });
2101
2102 if (!contains_value) {
2103 return false;
2104 }
2105
2106 return true;
2107 });
2108 }
2109
2110 static bool
2111 _options_config_matches_partial_config(xpc_object_t full, xpc_object_t partial)
2112 {
2113 SEC_PROTOCOL_METADATA_VALIDATE(full, false);
2114 SEC_PROTOCOL_METADATA_VALIDATE(partial, false);
2115
2116 return xpc_dictionary_apply(partial, ^bool(const char * _Nonnull entry_key, xpc_object_t _Nonnull value) {
2117 size_t entry_key_len = strnlen(entry_key, MAX_SEC_PROTOCOL_OPTIONS_KEY_LEN);
2118
2119 for (size_t i = 0; i < _options_uint64_keys_len; i++) {
2120 const char *key = _options_uint64_keys[i];
2121 if (strncmp(entry_key, key, MAX(entry_key_len, strlen(key))) == 0) {
2122 if (_dictionary_has_key(full, key)) {
2123 if (xpc_dictionary_get_uint64(full, key) != xpc_dictionary_get_uint64(partial, key)) {
2124 return false;
2125 }
2126 } else {
2127 return false;
2128 }
2129 }
2130 }
2131
2132 for (size_t i = 0; i < _options_bool_keys_len; i++) {
2133 const char *key = _options_bool_keys[i];
2134 if (strncmp(entry_key, key, MAX(entry_key_len, strlen(key))) == 0) {
2135 if (_dictionary_has_key(full, key)) {
2136 if (xpc_dictionary_get_bool(full, key) != xpc_dictionary_get_bool(partial, key)) {
2137 return false;
2138 }
2139 } else {
2140 return false;
2141 }
2142 }
2143 }
2144
2145 // Now check for ciphersuite options, as these are not expressed via serialized configs
2146 if (strncmp(entry_key, SEC_PROTOCOL_OPTIONS_KEY_ciphersuites, entry_key_len) == 0) {
2147 if (xpc_get_type(value) == XPC_TYPE_ARRAY) {
2148 bool matching = xpc_dictionary_apply(full, ^bool(const char * _Nonnull full_key, xpc_object_t _Nonnull full_value) {
2149 if (strncmp(full_key, SEC_PROTOCOL_OPTIONS_KEY_ciphersuites, entry_key_len) == 0) {
2150 if (xpc_get_type(full_value) == XPC_TYPE_ARRAY) {
2151 return _arrays_uint64_contents_are_equal(value, full_value);
2152 }
2153 }
2154 return true;
2155 });
2156
2157 if (!matching) {
2158 return false;
2159 }
2160 }
2161 }
2162
2163 return true;
2164 });
2165 }
2166
2167 static bool
2168 _serialize_options(xpc_object_t dictionary, sec_protocol_options_content_t options_content)
2169 {
2170 #define xpc_dictionary_set_string_default(d, key, value, default) \
2171 do { \
2172 if (value != NULL) { \
2173 xpc_dictionary_set_string(d, key, value); \
2174 } else { \
2175 xpc_dictionary_set_string(d, key, default); \
2176 } \
2177 } while (0);
2178
2179 #define EXPAND_PARAMETER(field) \
2180 SEC_PROTOCOL_OPTIONS_KEY_##field , options_content->field
2181
2182 xpc_dictionary_set_uint64(dictionary, EXPAND_PARAMETER(min_version));
2183 xpc_dictionary_set_uint64(dictionary, EXPAND_PARAMETER(max_version));
2184 xpc_dictionary_set_uint64(dictionary, EXPAND_PARAMETER(minimum_rsa_key_size));
2185 xpc_dictionary_set_uint64(dictionary, EXPAND_PARAMETER(minimum_ecdsa_key_size));
2186 xpc_dictionary_set_uint64(dictionary, EXPAND_PARAMETER(minimum_signature_algorithm));
2187 xpc_dictionary_set_uint64(dictionary, EXPAND_PARAMETER(tls_ticket_request_count));
2188
2189 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(ats_required));
2190 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(ats_minimum_tls_version_allowed));
2191 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(ats_non_pfs_ciphersuite_allowed));
2192 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(trusted_peer_certificate));
2193 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(disable_sni));
2194 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enable_fallback_attempt));
2195 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enable_false_start));
2196 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enable_tickets));
2197 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enable_sct));
2198 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enable_ocsp));
2199 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enforce_ev));
2200 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enable_resumption));
2201 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enable_renegotiation));
2202 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enable_early_data));
2203 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(peer_authentication_required));
2204 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(certificate_compression_enabled));
2205 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(tls_SIKE503_exchange_enabled));
2206 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(tls_HRSS_exchange_enabled));
2207 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(eddsa_enabled));
2208 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(tls_delegated_credentials_enabled));
2209 xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(tls_grease_enabled));
2210
2211 #undef EXPAND_PARAMETER
2212 #undef xpc_dictionary_set_string_default
2213
2214 return true;
2215 }
2216
2217 static struct _options_bool_key_setter {
2218 const char *key;
2219 void (*setter_pointer)(sec_protocol_options_t, bool);
2220 } _options_bool_key_setters[] = {
2221 {
2222 .key = SEC_PROTOCOL_OPTIONS_KEY_ats_required,
2223 .setter_pointer = sec_protocol_options_set_ats_required,
2224 },
2225 {
2226 .key = SEC_PROTOCOL_OPTIONS_KEY_ats_minimum_tls_version_allowed,
2227 .setter_pointer = sec_protocol_options_set_ats_minimum_tls_version_allowed,
2228 },
2229 {
2230 .key = SEC_PROTOCOL_OPTIONS_KEY_ats_non_pfs_ciphersuite_allowed,
2231 .setter_pointer = sec_protocol_options_set_ats_non_pfs_ciphersuite_allowed,
2232 },
2233 {
2234 .key = SEC_PROTOCOL_OPTIONS_KEY_trusted_peer_certificate,
2235 .setter_pointer = sec_protocol_options_set_trusted_peer_certificate,
2236 },
2237 {
2238 .key = SEC_PROTOCOL_OPTIONS_KEY_disable_sni,
2239 .setter_pointer = sec_protocol_options_set_tls_sni_disabled
2240 },
2241 {
2242 .key = SEC_PROTOCOL_OPTIONS_KEY_enable_fallback_attempt,
2243 .setter_pointer = sec_protocol_options_set_tls_is_fallback_attempt,
2244 },
2245 {
2246 .key = SEC_PROTOCOL_OPTIONS_KEY_enable_false_start,
2247 .setter_pointer = sec_protocol_options_set_tls_false_start_enabled,
2248 },
2249 {
2250 .key = SEC_PROTOCOL_OPTIONS_KEY_enable_tickets,
2251 .setter_pointer = sec_protocol_options_set_tls_tickets_enabled,
2252 },
2253 {
2254 .key = SEC_PROTOCOL_OPTIONS_KEY_enable_sct,
2255 .setter_pointer = sec_protocol_options_set_tls_sct_enabled
2256 },
2257 {
2258 .key = SEC_PROTOCOL_OPTIONS_KEY_enable_ocsp,
2259 .setter_pointer = sec_protocol_options_set_tls_ocsp_enabled,
2260 },
2261 {
2262 .key = SEC_PROTOCOL_OPTIONS_KEY_enforce_ev,
2263 .setter_pointer = sec_protocol_options_set_enforce_ev,
2264 },
2265 {
2266 .key = SEC_PROTOCOL_OPTIONS_KEY_enable_resumption,
2267 .setter_pointer = sec_protocol_options_set_tls_resumption_enabled,
2268 },
2269 {
2270 .key = SEC_PROTOCOL_OPTIONS_KEY_enable_renegotiation,
2271 .setter_pointer = sec_protocol_options_set_tls_renegotiation_enabled,
2272 },
2273 {
2274 .key = SEC_PROTOCOL_OPTIONS_KEY_enable_early_data,
2275 .setter_pointer = sec_protocol_options_set_tls_early_data_enabled,
2276 },
2277 {
2278 .key = SEC_PROTOCOL_OPTIONS_KEY_peer_authentication_required,
2279 .setter_pointer = sec_protocol_options_set_peer_authentication_required,
2280 },
2281 {
2282 .key = SEC_PROTOCOL_OPTIONS_KEY_certificate_compression_enabled,
2283 .setter_pointer = sec_protocol_options_set_tls_certificate_compression_enabled,
2284 },
2285 {
2286 .key = SEC_PROTOCOL_OPTIONS_KEY_tls_SIKE503_exchange_enabled,
2287 .setter_pointer = sec_protocol_options_set_tls_SIKE503_exchange_enabled,
2288 },
2289 {
2290 .key = SEC_PROTOCOL_OPTIONS_KEY_tls_HRSS_exchange_enabled,
2291 .setter_pointer = sec_protocol_options_set_tls_HRSS_exchange_enabled,
2292 },
2293 {
2294 .key = SEC_PROTOCOL_OPTIONS_KEY_eddsa_enabled,
2295 .setter_pointer = sec_protocol_options_set_eddsa_enabled,
2296 },
2297 {
2298 .key = SEC_PROTOCOL_OPTIONS_KEY_tls_delegated_credentials_enabled,
2299 .setter_pointer = sec_protocol_options_set_tls_delegated_credentials_enabled,
2300 },
2301 {
2302 .key = SEC_PROTOCOL_OPTIONS_KEY_tls_grease_enabled,
2303 .setter_pointer = sec_protocol_options_set_tls_grease_enabled,
2304 },
2305 };
2306 static const size_t _options_bool_key_setters_len = sizeof(_options_bool_key_setters) / sizeof(_options_bool_key_setters[0]);
2307
2308 static struct _options_uint64_key_setter {
2309 const char *key;
2310 void (*setter_pointer)(sec_protocol_options_t, uint64_t);
2311 } _options_uint64_key_setters[] = {
2312 #pragma clang diagnostic push
2313 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2314 {
2315 .key = SEC_PROTOCOL_OPTIONS_KEY_min_version,
2316 .setter_pointer = (void (*)(sec_protocol_options_t, uint64_t))sec_protocol_options_set_tls_min_version
2317 },
2318 {
2319 .key = SEC_PROTOCOL_OPTIONS_KEY_max_version,
2320 .setter_pointer = (void (*)(sec_protocol_options_t, uint64_t))sec_protocol_options_set_tls_max_version
2321 },
2322 #pragma clang diagnostic pop
2323 {
2324 .key = SEC_PROTOCOL_OPTIONS_KEY_minimum_rsa_key_size,
2325 .setter_pointer = (void (*)(sec_protocol_options_t, uint64_t))sec_protocol_options_set_minimum_rsa_key_size,
2326 },
2327 {
2328 .key = SEC_PROTOCOL_OPTIONS_KEY_minimum_ecdsa_key_size,
2329 .setter_pointer = (void (*)(sec_protocol_options_t, uint64_t))sec_protocol_options_set_minimum_ecdsa_key_size,
2330 },
2331 {
2332 .key = SEC_PROTOCOL_OPTIONS_KEY_minimum_signature_algorithm,
2333 .setter_pointer = (void (*)(sec_protocol_options_t, uint64_t))sec_protocol_options_set_minimum_signature_algorithm,
2334 },
2335 {
2336 .key = SEC_PROTOCOL_OPTIONS_KEY_tls_ticket_request_count,
2337 .setter_pointer = (void (*)(sec_protocol_options_t, uint64_t))sec_protocol_options_set_tls_ticket_request_count,
2338 },
2339 };
2340 static const size_t _options_uint64_key_setters_len = sizeof(_options_uint64_key_setters) / sizeof(_options_uint64_key_setters[0]);
2341
2342 static bool
2343 _apply_config_options(sec_protocol_options_t options, xpc_object_t config)
2344 {
2345 return sec_protocol_options_access_handle(options, ^bool(void *options_handle) {
2346 sec_protocol_options_content_t options_content = (sec_protocol_options_content_t)options_handle;
2347 SEC_PROTOCOL_METADATA_VALIDATE(options_content, false);
2348 return xpc_dictionary_apply(config, ^bool(const char * _Nonnull key, xpc_object_t _Nonnull value) {
2349
2350 size_t key_len = strnlen(key, MAX_SEC_PROTOCOL_OPTIONS_KEY_LEN);
2351 for (size_t i = 0; i < _options_bool_key_setters_len; i++) {
2352 const char *setter_key = _options_bool_key_setters[i].key;
2353 size_t setter_key_len = strnlen(setter_key, MAX_SEC_PROTOCOL_OPTIONS_KEY_LEN);
2354 if (strncmp(setter_key, key, MAX(key_len, setter_key_len)) == 0) {
2355 _options_bool_key_setters[i].setter_pointer(options, xpc_dictionary_get_bool(config, key));
2356 }
2357 }
2358
2359 for (size_t i = 0; i < _options_uint64_key_setters_len; i++) {
2360 const char *setter_key = _options_uint64_key_setters[i].key;
2361 size_t setter_key_len = strnlen(setter_key, MAX_SEC_PROTOCOL_OPTIONS_KEY_LEN);
2362 if (strncmp(setter_key, key, MAX(key_len, setter_key_len)) == 0) {
2363 _options_uint64_key_setters[i].setter_pointer(options, xpc_dictionary_get_uint64(config, key));
2364 }
2365 }
2366
2367 // Now check for ciphersuite options, as these are not expressed via serialized configs
2368 if (strncmp(key, SEC_PROTOCOL_OPTIONS_KEY_ciphersuites, key_len) == 0) {
2369 if (xpc_get_type(value) == XPC_TYPE_ARRAY) {
2370 xpc_array_apply(value, ^bool(size_t index, xpc_object_t _Nonnull ciphersuite_value) {
2371 SSLCipherSuite ciphersuite = (SSLCipherSuite)xpc_array_get_uint64(value, index);
2372 sec_protocol_options_append_tls_ciphersuite(options, ciphersuite);
2373 return true;
2374 });
2375 }
2376 }
2377
2378 return true;
2379 });
2380 });
2381 }
2382
2383 static bool
2384 _serialize_metadata(xpc_object_t dictionary, sec_protocol_metadata_content_t metadata_content)
2385 {
2386 #define xpc_dictionary_set_string_default(d, key, value, default) \
2387 do { \
2388 if (value != NULL) { \
2389 xpc_dictionary_set_string(d, key, value); \
2390 } else { \
2391 xpc_dictionary_set_string(d, key, default); \
2392 } \
2393 } while (0);
2394
2395 xpc_dictionary_set_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_CIPHERSUITE, metadata_content->negotiated_ciphersuite);
2396 xpc_dictionary_set_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_PROTOCOL_VERSION, metadata_content->negotiated_protocol_version);
2397 xpc_dictionary_set_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_TICKET_LIFETIME, metadata_content->ticket_lifetime);
2398
2399 xpc_dictionary_set_string_default(dictionary, SEC_PROTOCOL_METADATA_KEY_PEER_PUBLIC_KEY_TYPE,
2400 metadata_content->peer_public_key_type, SEC_PROTOCOL_METADATA_KEY_DEFAULT_EMPTY_STRING);
2401 xpc_dictionary_set_string_default(dictionary, SEC_PROTOCOL_METADATA_KEY_NEGOTIATED_CURVE,
2402 metadata_content->negotiated_curve, SEC_PROTOCOL_METADATA_KEY_DEFAULT_EMPTY_STRING);
2403 xpc_dictionary_set_string_default(dictionary, SEC_PROTOCOL_METADATA_KEY_PEER_CERTIFICATE_REQUEST_TYPE,
2404 metadata_content->certificate_request_type, SEC_PROTOCOL_METADATA_KEY_DEFAULT_EMPTY_STRING);
2405 xpc_dictionary_set_string_default(dictionary, SEC_PROTOCOL_METADATA_KEY_NEGOTIATED_PROTOCOL,
2406 metadata_content->negotiated_protocol, SEC_PROTOCOL_METADATA_KEY_DEFAULT_EMPTY_STRING);
2407
2408 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_FALSE_START_USED, metadata_content->false_start_used);
2409 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_SESSION_RESUMED, metadata_content->session_resumed);
2410 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_TICKET_OFFERED, metadata_content->ticket_offered);
2411 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_TICKET_RECEIVED, metadata_content->ticket_received);
2412 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_SESSION_RENEWED, metadata_content->session_renewed);
2413 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_RESUMPTION_ATTEMPTED, metadata_content->resumption_attempted);
2414 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_ALPN_USED, metadata_content->alpn_used);
2415 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_NPN_USED, metadata_content->npn_used);
2416 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_OCSP_ENABLED, metadata_content->ocsp_enabled);
2417 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_OCSP_RECEIVED, metadata_content->ocsp_response != NULL);
2418 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_SCT_ENABLED, metadata_content->sct_enabled);
2419 xpc_dictionary_set_bool(dictionary, SEC_PROTOCOL_METADATA_KEY_SCT_RECEIVED, metadata_content->signed_certificate_timestamps != NULL);
2420
2421 #undef xpc_dictionary_set_string_default
2422
2423 return true;
2424 }
2425
2426 static bool
2427 _serialize_success_with_options(xpc_object_t dictionary, sec_protocol_metadata_content_t metadata_content, sec_protocol_options_content_t options_content)
2428 {
2429 if (!_serialize_options(dictionary, options_content)) {
2430 return false;
2431 }
2432 if (!_serialize_metadata(dictionary, metadata_content)) {
2433 return false;
2434 }
2435 return true;
2436 }
2437
2438 static bool
2439 _serialize_failure_with_options(xpc_object_t dictionary, sec_protocol_metadata_content_t metadata_content, sec_protocol_options_content_t options_content)
2440 {
2441 xpc_dictionary_set_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_FAILURE_ALERT_TYPE, metadata_content->alert_type);
2442 xpc_dictionary_set_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_FAILURE_ALERT_CODE, metadata_content->alert_code);
2443 xpc_dictionary_set_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_FAILURE_HANDSHAKE_STATE, metadata_content->handshake_state);
2444 xpc_dictionary_set_uint64(dictionary, SEC_PROTOCOL_METADATA_KEY_FAILURE_STACK_ERROR, metadata_content->stack_error);
2445
2446 return true;
2447 }
2448
2449 xpc_object_t
2450 sec_protocol_metadata_serialize_with_options(sec_protocol_metadata_t metadata, sec_protocol_options_t options)
2451 {
2452 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
2453 SEC_PROTOCOL_METADATA_VALIDATE(options, NULL);
2454
2455 __block xpc_object_t dictionary = xpc_dictionary_create(NULL, NULL, 0);
2456 if (dictionary == NULL) {
2457 return NULL;
2458 }
2459
2460 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
2461 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
2462 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
2463
2464 return sec_protocol_options_access_handle(options, ^bool(void *options_handle) {
2465 sec_protocol_options_content_t options_content = (sec_protocol_options_content_t)options_handle;
2466 SEC_PROTOCOL_METADATA_VALIDATE(options_content, false);
2467
2468 if (metadata_content->failure) {
2469 return _serialize_failure_with_options(dictionary, metadata_content, options_content);
2470 } else {
2471 return _serialize_success_with_options(dictionary, metadata_content, options_content);
2472 }
2473 });
2474 });
2475
2476 return dictionary;
2477 }
2478
2479 dispatch_data_t
2480 sec_protocol_metadata_copy_quic_transport_parameters(sec_protocol_metadata_t metadata)
2481 {
2482 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
2483
2484 __block dispatch_data_t copied_parameters = NULL;
2485 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
2486 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
2487 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
2488 if (metadata_content->quic_transport_parameters) {
2489 copied_parameters = metadata_content->quic_transport_parameters;
2490 dispatch_retain(copied_parameters);
2491 }
2492 return true;
2493 });
2494
2495 return copied_parameters;
2496 }
2497
2498 bool
2499 sec_protocol_metadata_get_tls_certificate_compression_used(sec_protocol_metadata_t metadata)
2500 {
2501 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
2502
2503 __block bool certificate_compression_used = false;
2504 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
2505 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
2506 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
2507 certificate_compression_used = metadata_content->certificate_compression_used;
2508 return true;
2509 });
2510
2511 return certificate_compression_used;
2512 }
2513
2514 uint16_t
2515 sec_protocol_metadata_get_tls_certificate_compression_algorithm(sec_protocol_metadata_t metadata)
2516 {
2517 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0);
2518
2519 __block uint16_t certificate_compression_algorithm = 0;
2520 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
2521 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
2522 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
2523 certificate_compression_algorithm = metadata_content->certificate_compression_algorithm;
2524 return true;
2525 });
2526
2527 return certificate_compression_algorithm;
2528 }
2529
2530 uint64_t
2531 sec_protocol_metadata_get_handshake_rtt(sec_protocol_metadata_t metadata)
2532 {
2533 SEC_PROTOCOL_METADATA_VALIDATE(metadata, 0);
2534
2535 __block uint64_t rtt = 0;
2536 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
2537 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
2538 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
2539 rtt = metadata_content->handshake_rtt;
2540 return true;
2541 });
2542
2543 return rtt;
2544 }
2545
2546 sec_trust_t
2547 sec_protocol_metadata_copy_sec_trust(sec_protocol_metadata_t metadata)
2548 {
2549 SEC_PROTOCOL_METADATA_VALIDATE(metadata, nil);
2550
2551 __block sec_trust_t trust = nil;
2552 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
2553 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
2554 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
2555 if (metadata_content->trust_ref != nil) {
2556 trust = metadata_content->trust_ref;
2557 sec_retain(trust);
2558 }
2559 return true;
2560 });
2561
2562 return trust;
2563 }
2564
2565 sec_identity_t
2566 sec_protocol_metadata_copy_sec_identity(sec_protocol_metadata_t metadata)
2567 {
2568 SEC_PROTOCOL_METADATA_VALIDATE(metadata, nil);
2569
2570 __block sec_identity_t identity = nil;
2571 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *metadata_handle) {
2572 sec_protocol_metadata_content_t metadata_content = (sec_protocol_metadata_content_t)metadata_handle;
2573 SEC_PROTOCOL_METADATA_VALIDATE(metadata_content, false);
2574 if (metadata_content->identity != nil) {
2575 identity = metadata_content->identity;
2576 sec_retain(identity);
2577 }
2578 return true;
2579 });
2580
2581 return identity;
2582 }
2583
2584 bool
2585 sec_protocol_metadata_access_sent_certificates(sec_protocol_metadata_t metadata,
2586 void (^handler)(sec_certificate_t certificate))
2587 {
2588 SEC_PROTOCOL_METADATA_VALIDATE(metadata, false);
2589 SEC_PROTOCOL_METADATA_VALIDATE(handler, false);
2590
2591 return sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
2592 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
2593 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
2594
2595 if (content->identity != nil && sec_identity_has_certificates(content->identity)) {
2596 return sec_identity_access_certificates(content->identity, handler);
2597 }
2598
2599 if (content->sent_certificate_chain != NULL) {
2600 return sec_array_apply(content->sent_certificate_chain, ^bool(__unused size_t index, sec_object_t object) {
2601 handler((sec_certificate_t)object);
2602 return true;
2603 });
2604 }
2605
2606 return false;
2607 });
2608 }
2609
2610 const char *
2611 sec_protocol_metadata_get_tls_negotiated_group(sec_protocol_metadata_t metadata)
2612 {
2613 SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL);
2614
2615 __block const char *negotiated_curve = NULL;
2616 (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) {
2617 sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle;
2618 SEC_PROTOCOL_METADATA_VALIDATE(content, false);
2619 negotiated_curve = content->negotiated_curve;
2620 return true;
2621 });
2622
2623 return negotiated_curve;
2624 }
2625
2626 void *
2627 sec_retain(void *obj)
2628 {
2629 if (obj != NULL) {
2630 return os_retain(obj);
2631 } else {
2632 return NULL;
2633 }
2634 }
2635
2636 void
2637 sec_release(void *obj)
2638 {
2639 if (obj != NULL) {
2640 os_release(obj);
2641 }
2642 }
2643
2644 xpc_object_t
2645 sec_protocol_options_create_config(sec_protocol_options_t options)
2646 {
2647 SEC_PROTOCOL_METADATA_VALIDATE(options, NULL);
2648
2649 __block xpc_object_t dictionary = xpc_dictionary_create(NULL, NULL, 0);
2650 if (dictionary == NULL) {
2651 return NULL;
2652 }
2653
2654 bool serialized = sec_protocol_options_access_handle(options, ^bool(void *options_handle) {
2655 sec_protocol_options_content_t options_content = (sec_protocol_options_content_t)options_handle;
2656 SEC_PROTOCOL_METADATA_VALIDATE(options_content, false);
2657
2658 if (_serialize_options(dictionary, options_content)) {
2659 xpc_dictionary_set_value(dictionary, SEC_PROTOCOL_OPTIONS_KEY_ciphersuites, options_content->ciphersuites);
2660 return true;
2661 }
2662
2663 return false;
2664 });
2665
2666 if (serialized) {
2667 return dictionary; // retained reference
2668 } else {
2669 xpc_release(dictionary);
2670 return NULL;
2671 }
2672 }
2673
2674 bool
2675 sec_protocol_options_matches_config(sec_protocol_options_t options, xpc_object_t config)
2676 {
2677 SEC_PROTOCOL_METADATA_VALIDATE(options, false);
2678 SEC_PROTOCOL_METADATA_VALIDATE(config, false);
2679
2680 if (xpc_get_type(config) != XPC_TYPE_DICTIONARY) {
2681 return false;
2682 }
2683
2684 xpc_object_t options_config = sec_protocol_options_create_config(options);
2685 if (options_config == NULL) {
2686 return false;
2687 }
2688
2689 bool match = _options_config_matches_partial_config(options_config, config);
2690 xpc_release(options_config);
2691
2692 return match;
2693 }
2694
2695 bool
2696 sec_protocol_options_apply_config(sec_protocol_options_t options, xpc_object_t config)
2697 {
2698 SEC_PROTOCOL_METADATA_VALIDATE(options, false);
2699 SEC_PROTOCOL_METADATA_VALIDATE(config, false);
2700
2701 if (xpc_get_type(config) != XPC_TYPE_DICTIONARY) {
2702 return false;
2703 }
2704
2705 return _apply_config_options(options, config);
2706 }