SecProtocolTypes.m
1 // 2 // SecProtocolTypes.m 3 // Security 4 // 5 6 #import "utilities/SecCFRelease.h" 7 #import "utilities/SecCFWrappers.h" 8 9 #define OS_OBJECT_HAVE_OBJC_SUPPORT 1 10 11 #define SEC_NULL_BAD_INPUT ((void *_Nonnull)NULL) 12 #define SEC_NULL_OUT_OF_MEMORY SEC_NULL_BAD_INPUT 13 14 #define SEC_NIL_BAD_INPUT ((void *_Nonnull)nil) 15 #define SEC_NIL_OUT_OF_MEMORY SEC_NIL_BAD_INPUT 16 17 #define SEC_CONCRETE_CLASS_NAME(external_type) SecConcrete_##external_type 18 #define SEC_CONCRETE_PREFIX_STR "SecConcrete_" 19 20 #define SEC_OBJECT_DECL_INTERNAL_OBJC(external_type) \ 21 @class SEC_CONCRETE_CLASS_NAME(external_type); \ 22 typedef SEC_CONCRETE_CLASS_NAME(external_type) *external_type##_t 23 24 #define SEC_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL_AND_VISBILITY(external_type, _protocol, visibility, ...) \ 25 @protocol OS_OBJECT_CLASS(external_type) <_protocol> \ 26 @end \ 27 visibility \ 28 @interface SEC_CONCRETE_CLASS_NAME(external_type) : NSObject<OS_OBJECT_CLASS(external_type)> \ 29 _Pragma("clang diagnostic push") \ 30 _Pragma("clang diagnostic ignored \"-Wobjc-interface-ivars\"") \ 31 __VA_ARGS__ \ 32 _Pragma("clang diagnostic pop") \ 33 @end \ 34 typedef int _useless_typedef_oio_##external_type 35 36 #define SEC_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL(external_type, _protocol, ...) \ 37 SEC_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL_AND_VISBILITY(external_type, _protocol, ,__VA_ARGS__) 38 39 #define SEC_OBJECT_IMPL_INTERNAL_OBJC(external_type, ...) \ 40 SEC_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL(external_type, NSObject, ##__VA_ARGS__) 41 42 #define SEC_OBJECT_IMPL_INTERNAL_OBJC_WITH_VISIBILITY(external_type, visibility, ...) \ 43 SEC_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL_AND_VISBILITY(external_type, NSObject, visibility, ##__VA_ARGS__) 44 45 #define SEC_OBJECT_IMPL 1 46 47 SEC_OBJECT_DECL_INTERNAL_OBJC(sec_array); 48 SEC_OBJECT_DECL_INTERNAL_OBJC(sec_identity); 49 SEC_OBJECT_DECL_INTERNAL_OBJC(sec_trust); 50 SEC_OBJECT_DECL_INTERNAL_OBJC(sec_certificate); 51 SEC_OBJECT_DECL_INTERNAL_OBJC(sec_protocol_configuration_builder); 52 SEC_OBJECT_DECL_INTERNAL_OBJC(sec_object); 53 SEC_OBJECT_DECL_INTERNAL_OBJC(sec_protocol_options); 54 SEC_OBJECT_DECL_INTERNAL_OBJC(sec_protocol_metadata); 55 SEC_OBJECT_DECL_INTERNAL_OBJC(sec_protocol_configuration); 56 57 #import "SecProtocolInternal.h" 58 #import <Security/SecProtocolPriv.h> 59 #import "SecProtocolTypesPriv.h" 60 61 #import <Foundation/Foundation.h> 62 #import <CoreFoundation/CoreFoundation.h> 63 #import <CoreFoundation/CFPriv.h> 64 65 #import <os/log.h> 66 #import <xpc/private.h> 67 68 #import <os/object.h> 69 70 #ifndef SEC_ANALYZER_HIDE_DEADSTORE 71 # ifdef __clang_analyzer__ 72 # define SEC_ANALYZER_HIDE_DEADSTORE(var) do { if (var) {} } while (0) 73 # else // __clang_analyzer__ 74 # define SEC_ANALYZER_HIDE_DEADSTORE(var) do {} while (0) 75 # endif // __clang_analyzer__ 76 #endif // SEC_ANALYZER_HIDE_DEADSTORE 77 78 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_array, 79 { 80 xpc_object_t xpc_array; 81 }); 82 83 @implementation SEC_CONCRETE_CLASS_NAME(sec_array) 84 85 - (instancetype)init 86 { 87 if ((self = [super init])) { 88 self->xpc_array = xpc_array_create(NULL, 0); 89 } else { 90 return SEC_NIL_OUT_OF_MEMORY; 91 } 92 return self; 93 } 94 95 - (void)dealloc 96 { 97 if (self->xpc_array != nil) { 98 xpc_array_apply(self->xpc_array, ^bool(size_t index, __unused xpc_object_t value) { 99 void *pointer = xpc_array_get_pointer(self->xpc_array, index); 100 sec_object_t object = (sec_object_t)CFBridgingRelease(pointer); 101 SEC_ANALYZER_HIDE_DEADSTORE(object); 102 object = nil; 103 return true; 104 }); 105 self->xpc_array = nil; 106 } 107 } 108 109 sec_array_t 110 sec_array_create(void) 111 { 112 return [[SEC_CONCRETE_CLASS_NAME(sec_array) alloc] init]; 113 } 114 115 void 116 sec_array_append(sec_array_t array, sec_object_t object) 117 { 118 if (array != NULL && 119 array->xpc_array != NULL && xpc_get_type(array->xpc_array) == XPC_TYPE_ARRAY && 120 object != NULL) { 121 void *retained_pointer = __DECONST(void *, CFBridgingRetain(object)); 122 xpc_array_set_pointer(array->xpc_array, XPC_ARRAY_APPEND, retained_pointer); 123 // 'Leak' the retain, and save the pointer into the array 124 } 125 } 126 127 size_t 128 sec_array_get_count(sec_array_t array) 129 { 130 if (array != NULL && 131 array->xpc_array != NULL && xpc_get_type(array->xpc_array) == XPC_TYPE_ARRAY) { 132 return xpc_array_get_count(array->xpc_array); 133 } 134 return 0; 135 } 136 137 bool 138 sec_array_apply(sec_array_t array, sec_array_applier_t applier) 139 { 140 if (array != NULL && 141 array->xpc_array != NULL && xpc_get_type(array->xpc_array) == XPC_TYPE_ARRAY) { 142 return xpc_array_apply(array->xpc_array, ^bool(size_t index, __unused xpc_object_t value) { 143 void *pointer = xpc_array_get_pointer(array->xpc_array, index); 144 return applier(index, (__bridge sec_object_t)(pointer)); 145 }); 146 } 147 return false; 148 } 149 150 @end 151 152 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_identity, 153 { 154 SecIdentityRef identity; 155 CFArrayRef certs; 156 sec_protocol_private_key_sign_t sign_block; 157 sec_protocol_private_key_decrypt_t decrypt_block; 158 dispatch_queue_t operation_queue; 159 }); 160 161 @implementation SEC_CONCRETE_CLASS_NAME(sec_identity) 162 163 - (instancetype)initWithIdentity:(SecIdentityRef)_identity 164 { 165 if (_identity == NULL) { 166 return SEC_NIL_BAD_INPUT; 167 } 168 169 if ((self = [super init])) { 170 self->identity = __DECONST(SecIdentityRef, CFRetainSafe(_identity)); 171 } else { 172 return SEC_NIL_OUT_OF_MEMORY; 173 } 174 return self; 175 } 176 177 - (instancetype)initWithIdentityAndCertificates:(SecIdentityRef)_identity certificates:(CFArrayRef)certificates 178 { 179 if (_identity == NULL) { 180 return SEC_NIL_BAD_INPUT; 181 } 182 183 if ((self = [super init])) { 184 self->identity = __DECONST(SecIdentityRef, CFRetainSafe(_identity)); 185 self->certs = __DECONST(CFArrayRef, CFRetainSafe(certificates)); 186 } else { 187 return SEC_NIL_OUT_OF_MEMORY; 188 } 189 190 return self; 191 } 192 193 - (instancetype)initWithCertificates:(CFArrayRef)certificates signBlock:(sec_protocol_private_key_sign_t)sign decryptBlock:(sec_protocol_private_key_decrypt_t)decrypt queue:(dispatch_queue_t)queue 194 { 195 if (certificates == NULL) { 196 return SEC_NIL_BAD_INPUT; 197 } 198 if (sign == NULL) { 199 return SEC_NIL_BAD_INPUT; 200 } 201 if (decrypt == NULL) { 202 return SEC_NIL_BAD_INPUT; 203 } 204 205 if ((self = [super init])) { 206 self->certs = __DECONST(CFArrayRef, CFRetainSafe(certificates)); 207 self->sign_block = sign; 208 self->decrypt_block = decrypt; 209 self->operation_queue = queue; 210 } else { 211 return SEC_NIL_OUT_OF_MEMORY; 212 } 213 return self; 214 } 215 216 - (void)dealloc 217 { 218 if (self->identity != NULL) { 219 CFRelease(self->identity); 220 self->identity = NULL; 221 222 if (self->certs) { 223 CFRelease(self->certs); 224 } 225 self->certs = NULL; 226 } 227 } 228 229 sec_identity_t 230 sec_identity_create(SecIdentityRef identity) 231 { 232 return [[SEC_CONCRETE_CLASS_NAME(sec_identity) alloc] initWithIdentity:identity]; 233 } 234 235 sec_identity_t 236 sec_identity_create_with_certificates(SecIdentityRef identity, CFArrayRef certificates) 237 { 238 return [[SEC_CONCRETE_CLASS_NAME(sec_identity) alloc] initWithIdentityAndCertificates:identity certificates:certificates]; 239 } 240 241 sec_identity_t 242 sec_identity_create_with_certificates_and_external_private_key(CFArrayRef __nonnull certificates, 243 sec_protocol_private_key_sign_t sign_block, 244 sec_protocol_private_key_decrypt_t decrypt_block, 245 dispatch_queue_t queue) 246 { 247 return [[SEC_CONCRETE_CLASS_NAME(sec_identity) alloc] initWithCertificates:certificates signBlock:sign_block decryptBlock:decrypt_block queue:queue]; 248 } 249 250 SecIdentityRef 251 sec_identity_copy_ref(sec_identity_t object) 252 { 253 if (object == NULL) { 254 return SEC_NULL_BAD_INPUT; 255 } 256 if (object->identity != NULL) { 257 return __DECONST(SecIdentityRef, CFRetain(object->identity)); 258 } 259 return SEC_NULL_BAD_INPUT; 260 } 261 262 CFArrayRef 263 sec_identity_copy_certificates_ref(sec_identity_t object) 264 { 265 if (object == NULL) { 266 return SEC_NULL_BAD_INPUT; 267 } 268 if (object->certs != NULL) { 269 return __DECONST(CFArrayRef, CFRetain(object->certs)); 270 } 271 return SEC_NULL_BAD_INPUT; 272 } 273 274 bool 275 sec_identity_access_certificates(sec_identity_t identity, 276 void (^handler)(sec_certificate_t certificate)) 277 { 278 if (identity == NULL) { 279 return false; 280 } 281 if (identity->certs != NULL) { 282 CFArrayForEach(identity->certs, ^(const void *value) { 283 SecCertificateRef certificate_ref = (SecCertificateRef)value; 284 if (certificate_ref != NULL) { 285 sec_certificate_t certificate = sec_certificate_create(certificate_ref); 286 handler(certificate); 287 } 288 }); 289 return true; 290 } 291 return false; 292 } 293 294 bool 295 sec_identity_has_certificates(sec_identity_t identity) 296 { 297 if (identity == NULL) { 298 return false; 299 } 300 return identity->certs != NULL; 301 } 302 303 sec_protocol_private_key_sign_t 304 sec_identity_copy_private_key_sign_block(sec_identity_t object) 305 { 306 if (object == NULL) { 307 return SEC_NULL_BAD_INPUT; 308 } 309 if (object->sign_block != NULL) { 310 return object->sign_block; 311 } 312 return SEC_NIL_BAD_INPUT; 313 } 314 315 sec_protocol_private_key_decrypt_t 316 sec_identity_copy_private_key_decrypt_block(sec_identity_t object) 317 { 318 if (object == NULL) { 319 return SEC_NULL_BAD_INPUT; 320 } 321 if (object->decrypt_block != NULL) { 322 return object->decrypt_block; 323 } 324 return SEC_NIL_BAD_INPUT; 325 } 326 327 dispatch_queue_t 328 sec_identity_copy_private_key_queue(sec_identity_t object) 329 { 330 if (object == NULL) { 331 return SEC_NULL_BAD_INPUT; 332 } 333 if (object->operation_queue != nil) { 334 return object->operation_queue; 335 } 336 return SEC_NIL_BAD_INPUT; 337 } 338 339 340 @end 341 342 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_certificate, 343 { 344 SecCertificateRef certificate; 345 }); 346 347 @implementation SEC_CONCRETE_CLASS_NAME(sec_certificate) 348 349 - (instancetype)initWithCertificate:(SecCertificateRef)_certificate 350 { 351 if (_certificate == NULL) { 352 return SEC_NIL_BAD_INPUT; 353 } 354 355 if ((self = [super init])) { 356 self->certificate = __DECONST(SecCertificateRef, CFRetainSafe(_certificate)); 357 } else { 358 return SEC_NIL_OUT_OF_MEMORY; 359 } 360 return self; 361 } 362 363 - (void)dealloc 364 { 365 if (self->certificate != NULL) { 366 CFRelease(self->certificate); 367 self->certificate = NULL; 368 } 369 } 370 371 sec_certificate_t 372 sec_certificate_create(SecCertificateRef certificate) 373 { 374 return [[SEC_CONCRETE_CLASS_NAME(sec_certificate) alloc] initWithCertificate:certificate]; 375 } 376 377 SecCertificateRef 378 sec_certificate_copy_ref(sec_certificate_t object) 379 { 380 if (object == NULL) { 381 return SEC_NULL_BAD_INPUT; 382 } 383 if (object->certificate != NULL) { 384 return __DECONST(SecCertificateRef, CFRetain(object->certificate)); 385 } 386 return SEC_NULL_BAD_INPUT; 387 } 388 389 @end 390 391 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_trust, 392 { 393 SecTrustRef trust; 394 }); 395 396 @implementation SEC_CONCRETE_CLASS_NAME(sec_trust) 397 398 - (instancetype)initWithTrust:(SecTrustRef)_trust 399 { 400 if (_trust == NULL) { 401 return SEC_NIL_BAD_INPUT; 402 } 403 404 if ((self = [super init])) { 405 self->trust = __DECONST(SecTrustRef, CFRetainSafe(_trust)); 406 } else { 407 return SEC_NIL_OUT_OF_MEMORY; 408 } 409 return self; 410 } 411 412 - (void)dealloc 413 { 414 if (self->trust != NULL) { 415 CFRelease(self->trust); 416 self->trust = NULL; 417 } 418 } 419 420 sec_trust_t 421 sec_trust_create(SecTrustRef trust) 422 { 423 return [[SEC_CONCRETE_CLASS_NAME(sec_trust) alloc] initWithTrust:trust]; 424 } 425 426 SecTrustRef 427 sec_trust_copy_ref(sec_trust_t object) 428 { 429 if (object == NULL) { 430 return SEC_NULL_BAD_INPUT; 431 } 432 if (object->trust != NULL) { 433 return __DECONST(SecTrustRef, CFRetain(object->trust)); 434 } 435 return SEC_NULL_BAD_INPUT; 436 } 437 438 @end 439 440 static bool 441 _is_apple_bundle(void) 442 { 443 static dispatch_once_t onceToken; 444 static bool result = false; 445 dispatch_once(&onceToken, ^{ 446 CFBundleRef bundle = CFBundleGetMainBundle(); 447 CFStringRef bundleID = CFBundleGetIdentifier(bundle); 448 result = !bundleID || CFStringHasPrefix(bundleID, CFSTR("com.apple.")); 449 }); 450 return result; 451 } 452 453 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_protocol_configuration_builder, 454 { 455 @package 456 CFDictionaryRef dictionary; 457 bool is_apple; 458 }); 459 460 @implementation SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration_builder) 461 462 - (id)init 463 { 464 if (self = [super init]) { 465 CFBundleRef bundle = CFBundleGetMainBundle(); 466 if (bundle != NULL) { 467 CFTypeRef rawATS = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR(kATSInfoKey)); 468 self->dictionary = (CFDictionaryRef)rawATS; 469 CFRetainSafe(self->dictionary); 470 self->is_apple = _is_apple_bundle(); 471 } 472 } 473 return self; 474 } 475 476 - (id)initWithDictionary:(CFDictionaryRef)dict 477 andInternalFlag:(bool)flag 478 { 479 if ((self = [super init])) { 480 self->dictionary = dict; 481 CFRetainSafe(dict); 482 self->is_apple = flag; 483 } 484 return self; 485 } 486 487 @end 488 489 sec_protocol_configuration_builder_t 490 sec_protocol_configuration_builder_copy_default() 491 { 492 return [[SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration_builder) alloc] init]; 493 } 494 495 sec_protocol_configuration_builder_t 496 sec_protocol_configuration_builder_create(CFDictionaryRef dictionary, bool is_apple) 497 { 498 return [[SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration_builder) alloc] initWithDictionary:dictionary andInternalFlag:is_apple]; 499 } 500 501 CFDictionaryRef 502 sec_protocol_configuration_builder_get_ats_dictionary(sec_protocol_configuration_builder_t builder) 503 { 504 return builder->dictionary; 505 } 506 507 bool 508 sec_protocol_configuration_builder_get_is_apple_bundle(sec_protocol_configuration_builder_t builder) 509 { 510 return builder->is_apple; 511 } 512 513 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_protocol_configuration, 514 { 515 xpc_object_t dictionary; 516 }); 517 518 @implementation SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration) 519 520 - (id)init { 521 if ((self = [super init])) { 522 self->dictionary = xpc_dictionary_create(NULL, NULL, 0); 523 } 524 return self; 525 } 526 527 static sec_protocol_configuration_t 528 sec_protocol_configuration_create(void) 529 { 530 return [[SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration) alloc] init]; 531 } 532 533 sec_protocol_configuration_t 534 sec_protocol_configuration_create_with_builder(sec_protocol_configuration_builder_t builder) 535 { 536 sec_protocol_configuration_t configuration = sec_protocol_configuration_create(); 537 if (configuration) { 538 if (builder->is_apple) { 539 os_log_debug(OS_LOG_DEFAULT, "Building default configuration for first-party bundle"); 540 sec_protocol_configuration_populate_insecure_defaults(configuration); 541 } else { 542 os_log_debug(OS_LOG_DEFAULT, "Building default configuration for third-party bundle"); 543 sec_protocol_configuration_populate_secure_defaults(configuration); 544 } 545 546 sec_protocol_configuration_register_builtin_exceptions(configuration); 547 CFDictionaryRef dictionary = builder->dictionary; 548 if (dictionary) { 549 os_log_debug(OS_LOG_DEFAULT, "Setting configuration overrides based on AppTransportSecurity exceptions"); 550 sec_protocol_configuration_set_ats_overrides(configuration, dictionary); 551 } else { 552 os_log_debug(OS_LOG_DEFAULT, "Using default configuration settings"); 553 } 554 } else { 555 os_log_error(OS_LOG_DEFAULT, "sec_protocol_configuration_create failed"); 556 } 557 return configuration; 558 } 559 560 xpc_object_t 561 sec_protocol_configuration_get_map(sec_protocol_configuration_t configuration) 562 { 563 return configuration->dictionary; 564 } 565 566 @end