/ protocol / SecProtocolTypes.m
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