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