2 //  SecProtocolConfiguration.m
 
   6 #import "SecProtocolInternal.h"
 
   7 #import <Security/SecProtocolObject.h>
 
   8 #import <Security/SecProtocolConfiguration.h>
 
   9 #import <Security/SecureTransportPriv.h>
 
  10 #import <CoreFoundation/CFPriv.h>
 
  11 #import <Foundation/Foundation.h>
 
  13 #define MINIMUM_RSA_KEY_SIZE 2048
 
  14 #define MINIMUM_ECDSA_KEY_SIZE 2048
 
  15 #define MINIMUM_HASH_ALGORITHM kSecSignatureHashAlgorithmSHA256
 
  16 #define MINIMUM_PROTOCOL kTLSProtocol12
 
  21     static const char *processName = NULL;
 
  22     static dispatch_once_t onceToken;
 
  23     dispatch_once(&onceToken, ^{
 
  24         const char **procName = _CFGetProgname();
 
  25         processName = *procName;
 
  31 process_matches_target(const char *target_process)
 
  33     if (target_process == NULL) {
 
  37     const char *process = get_running_process();
 
  38     if (process != NULL) {
 
  39         return (strlen(target_process) == strlen(process) &&
 
  40                 strncmp(process, target_process, strlen(target_process)) == 0);
 
  48     static bool is_WebKit = false;
 
  49     static dispatch_once_t onceToken;
 
  50     dispatch_once(&onceToken, ^{
 
  51         is_WebKit = process_matches_target("com.apple.WebKit");
 
  57 client_is_mediaserverd()
 
  59     static bool is_mediaserverd = false;
 
  60     static dispatch_once_t onceToken;
 
  61     dispatch_once(&onceToken, ^{
 
  62         is_mediaserverd = process_matches_target("mediaserverd");
 
  64     return is_mediaserverd;
 
  67 sec_protocol_configuration_t
 
  68 sec_protocol_configuration_copy_singleton(void)
 
  70     static dispatch_once_t onceToken;
 
  71     static sec_protocol_configuration_t singleton = nil;
 
  72     dispatch_once(&onceToken, ^{
 
  73         singleton = sec_protocol_configuration_create_with_builder(sec_protocol_configuration_builder_copy_default());
 
  78 static sec_protocol_options_t
 
  79 sec_protocol_configuration_copy_transformed_options_with_ats_minimums(sec_protocol_options_t options)
 
  81     sec_protocol_options_set_ats_required(options, true);
 
  82     sec_protocol_options_set_trusted_peer_certificate(options, true);
 
  83     sec_protocol_options_set_minimum_rsa_key_size(options, MINIMUM_RSA_KEY_SIZE);
 
  84     sec_protocol_options_set_minimum_ecdsa_key_size(options, MINIMUM_ECDSA_KEY_SIZE);
 
  85     sec_protocol_options_set_minimum_signature_algorithm(options, MINIMUM_HASH_ALGORITHM);
 
  86     sec_protocol_options_set_min_tls_protocol_version(options, tls_protocol_version_TLSv12);
 
  90 sec_protocol_options_t
 
  91 sec_protocol_configuration_copy_transformed_options(__unused sec_protocol_configuration_t config, sec_protocol_options_t options)
 
  93     sec_protocol_options_clear_tls_ciphersuites(options);
 
  94     sec_protocol_options_append_tls_ciphersuite_group(options, tls_ciphersuite_group_ats);
 
  95     return sec_protocol_configuration_copy_transformed_options_with_ats_minimums(options);
 
  99 _find_parent_domain(const char *domain)
 
 101     size_t domain_len = strlen(domain);
 
 103     while (index < domain_len) {
 
 104         // Once we hit a dot, the parent domain begins at the next segment.
 
 105         if (domain[index] == '.' && index < domain_len) {
 
 109         // Skip over all characters that are not dots.
 
 116 static sec_protocol_options_t
 
 117 sec_protocol_configuration_copy_transformed_options_for_host_internal(sec_protocol_configuration_t config, sec_protocol_options_t options,
 
 118                                                                 const char *host, bool parent_domain)
 
 120     xpc_object_t map = sec_protocol_configuration_get_map(config);
 
 125     xpc_object_t domain_map = xpc_dictionary_get_dictionary(map, kExceptionDomains);
 
 126     if (domain_map == nil) {
 
 130     xpc_object_t entry = xpc_dictionary_get_dictionary(domain_map, host);
 
 132         const char *parent_host = _find_parent_domain(host);
 
 133         if (parent_host != NULL) {
 
 134             return sec_protocol_configuration_copy_transformed_options_for_host_internal(config, options, parent_host, true);
 
 137         // If we could not find a matching domain, apply the default connection properties.
 
 138         return sec_protocol_configuration_copy_transformed_options(config, options);
 
 141     bool pfs_required = xpc_dictionary_get_bool(entry, kExceptionRequiresForwardSecrecy);
 
 143         sec_protocol_options_clear_tls_ciphersuites(options);
 
 144         sec_protocol_options_append_tls_ciphersuite_group(options, tls_ciphersuite_group_ats);
 
 146         // Otherwise, record the fact that non-PFS ciphersuites are permitted. 
 
 147         // This does not mean that the caller actually configured a non-PFS ciphersuite.
 
 148         sec_protocol_options_set_ats_non_pfs_ciphersuite_allowed(options, true);
 
 151     tls_protocol_version_t minimum_protocol = (SSLProtocol)xpc_dictionary_get_int64(entry, kExceptionMinimumTLSVersion);
 
 152     if (minimum_protocol != 0) {
 
 153         // Record the fact that an excepted TLS version was configured.
 
 154         sec_protocol_options_set_min_tls_protocol_version(options, minimum_protocol);
 
 155         sec_protocol_options_set_ats_minimum_tls_version_allowed(options, true);
 
 161 sec_protocol_options_t
 
 162 sec_protocol_configuration_copy_transformed_options_for_host(sec_protocol_configuration_t config, sec_protocol_options_t options, const char *host)
 
 164     return sec_protocol_configuration_copy_transformed_options_for_host_internal(config, sec_protocol_configuration_copy_transformed_options_with_ats_minimums(options), host, false);
 
 168 sec_protocol_configuration_tls_required(sec_protocol_configuration_t config)
 
 170     xpc_object_t map = sec_protocol_configuration_get_map(config);
 
 176     bool allows_media_loads = xpc_dictionary_get_bool(map, kAllowsArbitraryLoadsForMedia);
 
 177     if (allows_media_loads && client_is_mediaserverd()) {
 
 181     bool allows_web_loads = xpc_dictionary_get_bool(map, kAllowsArbitraryLoadsInWebContent);
 
 182     if (allows_web_loads && client_is_WebKit()) {
 
 186     return !xpc_dictionary_get_bool(map, kAllowsArbitraryLoads);
 
 190 sec_protocol_configuration_tls_required_for_host_internal(sec_protocol_configuration_t config, const char *host, bool parent_domain)
 
 192     xpc_object_t map = sec_protocol_configuration_get_map(config);
 
 198     xpc_object_t domain_map = xpc_dictionary_get_dictionary(map, kExceptionDomains);
 
 199     if (domain_map == nil) {
 
 200         // Absent per-domain exceptions, use the default.
 
 201         return sec_protocol_configuration_tls_required(config);
 
 204     xpc_object_t entry = xpc_dictionary_get_dictionary(domain_map, host);
 
 206         const char *parent_host = _find_parent_domain(host);
 
 207         if (parent_host != NULL) {
 
 208             return sec_protocol_configuration_tls_required_for_host_internal(config, parent_host, true);
 
 210         return sec_protocol_configuration_tls_required(config);
 
 213     bool requires_tls = !xpc_dictionary_get_bool(entry, kExceptionAllowsInsecureHTTPLoads);
 
 214     bool includes_subdomains = !xpc_dictionary_get_bool(entry, kExceptionAllowsInsecureHTTPLoads);
 
 216     if (parent_domain && !includes_subdomains) {
 
 217         // If this domain's exceptions do not apply to subdomains, then default to the application default policy.
 
 218         return sec_protocol_configuration_tls_required(config);
 
 225 sec_protocol_configuration_tls_required_for_host(sec_protocol_configuration_t config, const char *host)
 
 227     return sec_protocol_configuration_tls_required_for_host_internal(config, host, false);
 
 231 sec_protocol_configuration_tls_required_for_address(sec_protocol_configuration_t config, const char *address)
 
 233     xpc_object_t map = sec_protocol_configuration_get_map(config);
 
 239     return !xpc_dictionary_get_bool(map, kAllowsLocalNetworking);
 
 242 static tls_protocol_version_t
 
 243 sec_protocol_configuration_protocol_string_to_version(const char *protocol)
 
 245     if (protocol == NULL) {
 
 249     const char *tlsv10 = "TLSv1.0";
 
 250     const char *tlsv11 = "TLSv1.1";
 
 251     const char *tlsv12 = "TLSv1.2";
 
 252     const char *tlsv13 = "TLSv1.3";
 
 254     if (strlen(protocol) == strlen(tlsv10) && strncmp(protocol, tlsv10, strlen(protocol)) == 0) {
 
 255         return tls_protocol_version_TLSv10;
 
 256     } else if (strlen(protocol) == strlen(tlsv11) && strncmp(protocol, tlsv11, strlen(protocol)) == 0) {
 
 257         return tls_protocol_version_TLSv11;
 
 258     } else if (strlen(protocol) == strlen(tlsv12) && strncmp(protocol, tlsv12, strlen(protocol)) == 0) {
 
 259         return tls_protocol_version_TLSv12;
 
 260     } else if (strlen(protocol) == strlen(tlsv13) && strncmp(protocol, tlsv13, strlen(protocol)) == 0) {
 
 261         return tls_protocol_version_TLSv13;
 
 268 sec_protocol_configuration_register_builtin_exception(xpc_object_t dict, const char *name,
 
 269                                                       tls_protocol_version_t protocol, bool requires_pfs,
 
 270                                                       bool allows_http, bool includes_subdomains, bool require_ct)
 
 272     xpc_object_t domain_map = xpc_dictionary_get_dictionary(dict, kExceptionDomains);
 
 274         xpc_object_t entry = xpc_dictionary_create(NULL, NULL, 0);
 
 275         xpc_dictionary_set_value(entry, kExceptionDomains, domain_map);
 
 277         xpc_dictionary_set_bool(entry, kIncludesSubdomains, includes_subdomains);
 
 278         xpc_dictionary_set_int64(entry, kExceptionMinimumTLSVersion, protocol);
 
 279         xpc_dictionary_set_bool(entry, kExceptionAllowsInsecureHTTPLoads, allows_http);
 
 280         xpc_dictionary_set_bool(entry, kExceptionRequiresForwardSecrecy, requires_pfs);
 
 282         xpc_dictionary_set_value(domain_map, name, entry);
 
 287 sec_protocol_configuration_register_builtin_exceptions(sec_protocol_configuration_t config)
 
 289     xpc_object_t dict = sec_protocol_configuration_get_map(config);
 
 290     sec_protocol_configuration_register_builtin_exception(dict, "apple.com", tls_protocol_version_TLSv12, false, true, true, true);
 
 291     sec_protocol_configuration_register_builtin_exception(dict, "ls.apple.com", tls_protocol_version_TLSv10, false, true, true, true);
 
 292     sec_protocol_configuration_register_builtin_exception(dict, "gs.apple.com", tls_protocol_version_TLSv10, false, true, true, true);
 
 293     sec_protocol_configuration_register_builtin_exception(dict, "geo.apple.com", tls_protocol_version_TLSv10, false, true, true, true);
 
 294     sec_protocol_configuration_register_builtin_exception(dict, "is.autonavi.com", tls_protocol_version_TLSv10, false, true, true, true);
 
 295     sec_protocol_configuration_register_builtin_exception(dict, "apple-mapkit.com", tls_protocol_version_TLSv10, false, true, true, true);
 
 296     sec_protocol_configuration_register_builtin_exception(dict, "setup.icloud.com", tls_protocol_version_TLSv12, false, true, true, true);
 
 300 sec_protocol_configuration_populate_insecure_defaults(sec_protocol_configuration_t config)
 
 302     xpc_object_t dict = sec_protocol_configuration_get_map(config);
 
 303     xpc_object_t domain_map = xpc_dictionary_create(NULL, NULL, 0);
 
 304     xpc_dictionary_set_value(dict, kExceptionDomains, domain_map);
 
 306     xpc_dictionary_set_bool(dict, kAllowsArbitraryLoadsInWebContent, true);
 
 307     xpc_dictionary_set_bool(dict, kAllowsArbitraryLoadsForMedia, true);
 
 308     xpc_dictionary_set_bool(dict, kAllowsLocalNetworking, true);
 
 309     xpc_dictionary_set_bool(dict, kAllowsArbitraryLoads, true);
 
 313 sec_protocol_configuration_populate_secure_defaults(sec_protocol_configuration_t config)
 
 315     xpc_object_t dict = sec_protocol_configuration_get_map(config);
 
 316     xpc_object_t domain_map = xpc_dictionary_create(NULL, NULL, 0);
 
 317     xpc_dictionary_set_value(dict, kExceptionDomains, domain_map);
 
 319     xpc_dictionary_set_bool(dict, kAllowsArbitraryLoadsInWebContent, false);
 
 320     xpc_dictionary_set_bool(dict, kAllowsArbitraryLoadsForMedia, false);
 
 321     xpc_dictionary_set_bool(dict, kAllowsLocalNetworking, false);
 
 322     xpc_dictionary_set_bool(dict, kAllowsArbitraryLoads, false);
 
 326 sec_protocol_configuration_set_ats_overrides(sec_protocol_configuration_t config, CFDictionaryRef plist)
 
 332 #define BOOLEAN_FOR_KEY(dictionary, key, value, default) \
 
 333     bool value = default; \
 
 335         NSNumber *nsValue = [dictionary valueForKey:[[NSString alloc] initWithFormat:@"%s", key]]; \
 
 337             value = [nsValue boolValue]; \
 
 340 #define STRING_FOR_KEY(dictionary, key, value, default) \
 
 341     NSString *value = default; \
 
 343         NSString *nsValue = [dictionary valueForKey:[[NSString alloc] initWithFormat:@"%s", key]]; \
 
 349     xpc_object_t dict = sec_protocol_configuration_get_map(config);
 
 354     NSDictionary *plist_dictionary = (__bridge NSDictionary *)plist;
 
 355     BOOLEAN_FOR_KEY(plist_dictionary, kAllowsArbitraryLoads, arbitrary_loads, false);
 
 356     BOOLEAN_FOR_KEY(plist_dictionary, kAllowsArbitraryLoadsInWebContent, web_loads, false);
 
 357     BOOLEAN_FOR_KEY(plist_dictionary, kAllowsArbitraryLoadsForMedia, media_loads, false);
 
 358     BOOLEAN_FOR_KEY(plist_dictionary, kAllowsLocalNetworking, local_networking, false);
 
 360     xpc_dictionary_set_bool(dict, kAllowsArbitraryLoads, arbitrary_loads);
 
 361     xpc_dictionary_set_bool(dict, kAllowsArbitraryLoadsInWebContent, web_loads);
 
 362     xpc_dictionary_set_bool(dict, kAllowsArbitraryLoadsForMedia, media_loads);
 
 363     xpc_dictionary_set_bool(dict, kAllowsLocalNetworking, local_networking);
 
 365     NSDictionary *exception_domains = [plist_dictionary valueForKey:[[NSString alloc] initWithFormat:@"%s", kExceptionDomains]];
 
 366     if (exception_domains == nil) {
 
 370     xpc_object_t domain_map = xpc_dictionary_get_dictionary(dict, kExceptionDomains);
 
 371     if (domain_map == nil) {
 
 372         // The domain map MUST be present during initialziation
 
 376     [exception_domains enumerateKeysAndObjectsUsingBlock:^(id _key, id _obj, BOOL *stop) {
 
 377         NSString *domain = (NSString *)_key;
 
 378         NSDictionary *entry = (NSDictionary *)_obj;
 
 380             // Exception domains MUST have ATS information set.
 
 384         xpc_object_t entry_map = xpc_dictionary_create(NULL, NULL, 0);
 
 386         BOOLEAN_FOR_KEY(entry_map, kExceptionAllowsInsecureHTTPLoads, allows_http, false);
 
 387         BOOLEAN_FOR_KEY(entry_map, kIncludesSubdomains, includes_subdomains, false);
 
 388         BOOLEAN_FOR_KEY(entry_map, kExceptionRequiresForwardSecrecy, requires_pfs, false);
 
 389         STRING_FOR_KEY(entry_map, kExceptionMinimumTLSVersion, minimum_tls, @"TLSv1.2");
 
 391         xpc_dictionary_set_bool(entry_map, kIncludesSubdomains, includes_subdomains);
 
 392         xpc_dictionary_set_bool(entry_map, kExceptionAllowsInsecureHTTPLoads, allows_http);
 
 393         xpc_dictionary_set_bool(entry_map, kExceptionRequiresForwardSecrecy, requires_pfs);
 
 394         xpc_dictionary_set_int64(entry_map, kExceptionMinimumTLSVersion, sec_protocol_configuration_protocol_string_to_version([minimum_tls cStringUsingEncoding:NSUTF8StringEncoding]));
 
 395         xpc_dictionary_set_value(domain_map, [domain cStringUsingEncoding:NSUTF8StringEncoding], entry_map);
 
 398 #undef STRING_FOR_KEY
 
 399 #undef BOOLEAN_FOR_KEY