6 #import "utilities/SecCFRelease.h"
7 #import "utilities/SecCFWrappers.h"
9 #define OS_OBJECT_HAVE_OBJC_SUPPORT 1
11 #define SEC_NULL_BAD_INPUT ((void *_Nonnull)NULL)
12 #define SEC_NULL_OUT_OF_MEMORY SEC_NULL_BAD_INPUT
14 #define SEC_NIL_BAD_INPUT ((void *_Nonnull)nil)
15 #define SEC_NIL_OUT_OF_MEMORY SEC_NIL_BAD_INPUT
17 #define SEC_CONCRETE_CLASS_NAME(external_type) SecConcrete_##external_type
18 #define SEC_CONCRETE_PREFIX_STR "SecConcrete_"
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
24 #define SEC_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL_AND_VISBILITY(external_type, _protocol, visibility, ...) \
25 @protocol OS_OBJECT_CLASS(external_type) <_protocol> \
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\"") \
32 _Pragma("clang diagnostic pop") \
34 typedef int _useless_typedef_oio_##external_type
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__)
39 #define SEC_OBJECT_IMPL_INTERNAL_OBJC(external_type, ...) \
40 SEC_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL(external_type, NSObject, ##__VA_ARGS__)
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__)
45 #define SEC_OBJECT_IMPL 1
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);
57 #import "SecProtocolInternal.h"
58 #import <Security/SecProtocolPriv.h>
59 #import "SecProtocolTypesPriv.h"
61 #import <Foundation/Foundation.h>
62 #import <CoreFoundation/CoreFoundation.h>
63 #import <CoreFoundation/CFPriv.h>
66 #import <xpc/private.h>
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
78 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_array,
80 xpc_object_t xpc_array;
83 @implementation SEC_CONCRETE_CLASS_NAME(sec_array)
87 if ((self = [super init])) {
88 self->xpc_array = xpc_array_create(NULL, 0);
90 return SEC_NIL_OUT_OF_MEMORY;
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);
105 self->xpc_array = nil;
110 sec_array_create(void)
112 return [[SEC_CONCRETE_CLASS_NAME(sec_array) alloc] init];
116 sec_array_append(sec_array_t array, sec_object_t object)
119 array->xpc_array != NULL && xpc_get_type(array->xpc_array) == XPC_TYPE_ARRAY &&
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
128 sec_array_get_count(sec_array_t array)
131 array->xpc_array != NULL && xpc_get_type(array->xpc_array) == XPC_TYPE_ARRAY) {
132 return xpc_array_get_count(array->xpc_array);
138 sec_array_apply(sec_array_t array, sec_array_applier_t applier)
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));
152 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_identity,
154 SecIdentityRef identity;
156 sec_protocol_private_key_sign_t sign_block;
157 sec_protocol_private_key_decrypt_t decrypt_block;
158 dispatch_queue_t operation_queue;
161 @implementation SEC_CONCRETE_CLASS_NAME(sec_identity)
163 - (instancetype)initWithIdentity:(SecIdentityRef)_identity
165 if (_identity == NULL) {
166 return SEC_NIL_BAD_INPUT;
169 if ((self = [super init])) {
170 self->identity = __DECONST(SecIdentityRef, CFRetainSafe(_identity));
172 return SEC_NIL_OUT_OF_MEMORY;
177 - (instancetype)initWithIdentityAndCertificates:(SecIdentityRef)_identity certificates:(CFArrayRef)certificates
179 if (_identity == NULL) {
180 return SEC_NIL_BAD_INPUT;
183 if ((self = [super init])) {
184 self->identity = __DECONST(SecIdentityRef, CFRetainSafe(_identity));
185 self->certs = __DECONST(CFArrayRef, CFRetainSafe(certificates));
187 return SEC_NIL_OUT_OF_MEMORY;
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
195 if (certificates == NULL) {
196 return SEC_NIL_BAD_INPUT;
199 return SEC_NIL_BAD_INPUT;
201 if (decrypt == NULL) {
202 return SEC_NIL_BAD_INPUT;
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;
211 return SEC_NIL_OUT_OF_MEMORY;
218 if (self->identity != NULL) {
219 CFRelease(self->identity);
220 self->identity = NULL;
223 CFRelease(self->certs);
230 sec_identity_create(SecIdentityRef identity)
232 return [[SEC_CONCRETE_CLASS_NAME(sec_identity) alloc] initWithIdentity:identity];
236 sec_identity_create_with_certificates(SecIdentityRef identity, CFArrayRef certificates)
238 return [[SEC_CONCRETE_CLASS_NAME(sec_identity) alloc] initWithIdentityAndCertificates:identity certificates:certificates];
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)
247 return [[SEC_CONCRETE_CLASS_NAME(sec_identity) alloc] initWithCertificates:certificates signBlock:sign_block decryptBlock:decrypt_block queue:queue];
251 sec_identity_copy_ref(sec_identity_t object)
253 if (object == NULL) {
254 return SEC_NULL_BAD_INPUT;
256 if (object->identity != NULL) {
257 return __DECONST(SecIdentityRef, CFRetain(object->identity));
259 return SEC_NULL_BAD_INPUT;
263 sec_identity_copy_certificates_ref(sec_identity_t object)
265 if (object == NULL) {
266 return SEC_NULL_BAD_INPUT;
268 if (object->certs != NULL) {
269 return __DECONST(CFArrayRef, CFRetain(object->certs));
271 return SEC_NULL_BAD_INPUT;
275 sec_identity_access_certificates(sec_identity_t identity,
276 void (^handler)(sec_certificate_t certificate))
278 if (identity == NULL) {
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);
295 sec_identity_has_certificates(sec_identity_t identity)
297 if (identity == NULL) {
300 return identity->certs != NULL;
303 sec_protocol_private_key_sign_t
304 sec_identity_copy_private_key_sign_block(sec_identity_t object)
306 if (object == NULL) {
307 return SEC_NULL_BAD_INPUT;
309 if (object->sign_block != NULL) {
310 return object->sign_block;
312 return SEC_NIL_BAD_INPUT;
315 sec_protocol_private_key_decrypt_t
316 sec_identity_copy_private_key_decrypt_block(sec_identity_t object)
318 if (object == NULL) {
319 return SEC_NULL_BAD_INPUT;
321 if (object->decrypt_block != NULL) {
322 return object->decrypt_block;
324 return SEC_NIL_BAD_INPUT;
328 sec_identity_copy_private_key_queue(sec_identity_t object)
330 if (object == NULL) {
331 return SEC_NULL_BAD_INPUT;
333 if (object->operation_queue != nil) {
334 return object->operation_queue;
336 return SEC_NIL_BAD_INPUT;
342 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_certificate,
344 SecCertificateRef certificate;
347 @implementation SEC_CONCRETE_CLASS_NAME(sec_certificate)
349 - (instancetype)initWithCertificate:(SecCertificateRef)_certificate
351 if (_certificate == NULL) {
352 return SEC_NIL_BAD_INPUT;
355 if ((self = [super init])) {
356 self->certificate = __DECONST(SecCertificateRef, CFRetainSafe(_certificate));
358 return SEC_NIL_OUT_OF_MEMORY;
365 if (self->certificate != NULL) {
366 CFRelease(self->certificate);
367 self->certificate = NULL;
372 sec_certificate_create(SecCertificateRef certificate)
374 return [[SEC_CONCRETE_CLASS_NAME(sec_certificate) alloc] initWithCertificate:certificate];
378 sec_certificate_copy_ref(sec_certificate_t object)
380 if (object == NULL) {
381 return SEC_NULL_BAD_INPUT;
383 if (object->certificate != NULL) {
384 return __DECONST(SecCertificateRef, CFRetain(object->certificate));
386 return SEC_NULL_BAD_INPUT;
391 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_trust,
396 @implementation SEC_CONCRETE_CLASS_NAME(sec_trust)
398 - (instancetype)initWithTrust:(SecTrustRef)_trust
400 if (_trust == NULL) {
401 return SEC_NIL_BAD_INPUT;
404 if ((self = [super init])) {
405 self->trust = __DECONST(SecTrustRef, CFRetainSafe(_trust));
407 return SEC_NIL_OUT_OF_MEMORY;
414 if (self->trust != NULL) {
415 CFRelease(self->trust);
421 sec_trust_create(SecTrustRef trust)
423 return [[SEC_CONCRETE_CLASS_NAME(sec_trust) alloc] initWithTrust:trust];
427 sec_trust_copy_ref(sec_trust_t object)
429 if (object == NULL) {
430 return SEC_NULL_BAD_INPUT;
432 if (object->trust != NULL) {
433 return __DECONST(SecTrustRef, CFRetain(object->trust));
435 return SEC_NULL_BAD_INPUT;
441 _is_apple_bundle(void)
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."));
453 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_protocol_configuration_builder,
456 CFDictionaryRef dictionary;
460 @implementation SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration_builder)
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();
476 - (id)initWithDictionary:(CFDictionaryRef)dict
477 andInternalFlag:(bool)flag
479 if ((self = [super init])) {
480 self->dictionary = dict;
482 self->is_apple = flag;
489 sec_protocol_configuration_builder_t
490 sec_protocol_configuration_builder_copy_default()
492 return [[SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration_builder) alloc] init];
495 sec_protocol_configuration_builder_t
496 sec_protocol_configuration_builder_create(CFDictionaryRef dictionary, bool is_apple)
498 return [[SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration_builder) alloc] initWithDictionary:dictionary andInternalFlag:is_apple];
502 sec_protocol_configuration_builder_get_ats_dictionary(sec_protocol_configuration_builder_t builder)
504 return builder->dictionary;
508 sec_protocol_configuration_builder_get_is_apple_bundle(sec_protocol_configuration_builder_t builder)
510 return builder->is_apple;
513 SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_protocol_configuration,
515 xpc_object_t dictionary;
518 @implementation SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration)
521 if ((self = [super init])) {
522 self->dictionary = xpc_dictionary_create(NULL, NULL, 0);
527 static sec_protocol_configuration_t
528 sec_protocol_configuration_create(void)
530 return [[SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration) alloc] init];
533 sec_protocol_configuration_t
534 sec_protocol_configuration_create_with_builder(sec_protocol_configuration_builder_t builder)
536 sec_protocol_configuration_t configuration = sec_protocol_configuration_create();
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);
542 os_log_debug(OS_LOG_DEFAULT, "Building default configuration for third-party bundle");
543 sec_protocol_configuration_populate_secure_defaults(configuration);
546 sec_protocol_configuration_register_builtin_exceptions(configuration);
547 CFDictionaryRef dictionary = builder->dictionary;
549 os_log_debug(OS_LOG_DEFAULT, "Setting configuration overrides based on AppTransportSecurity exceptions");
550 sec_protocol_configuration_set_ats_overrides(configuration, dictionary);
552 os_log_debug(OS_LOG_DEFAULT, "Using default configuration settings");
555 os_log_error(OS_LOG_DEFAULT, "sec_protocol_configuration_create failed");
557 return configuration;
561 sec_protocol_configuration_get_map(sec_protocol_configuration_t configuration)
563 return configuration->dictionary;