/ OSX / utilities / SecCFWrappers.h
SecCFWrappers.h
   1  /*
   2   * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
   3   *
   4   * @APPLE_LICENSE_HEADER_START@
   5   * 
   6   * This file contains Original Code and/or Modifications of Original Code
   7   * as defined in and that are subject to the Apple Public Source License
   8   * Version 2.0 (the 'License'). You may not use this file except in
   9   * compliance with the License. Please obtain a copy of the License at
  10   * http://www.opensource.apple.com/apsl/ and read it before using this
  11   * file.
  12   * 
  13   * The Original Code and all software distributed under the License are
  14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18   * Please see the License for the specific language governing rights and
  19   * limitations under the License.
  20   * 
  21   * @APPLE_LICENSE_HEADER_END@
  22   */
  23  
  24  
  25  #ifndef _SECCFWRAPPERS_H_
  26  #define _SECCFWRAPPERS_H_
  27  
  28  #include <CoreFoundation/CFRuntime.h>
  29  #include <CoreFoundation/CoreFoundation.h>
  30  
  31  #include "utilities/SecCFRelease.h"
  32  #include "utilities/debugging.h"
  33  #include "utilities/SecCFError.h"
  34  
  35  #include <IOKit/IOReturn.h>
  36  
  37  #include "utilities/simulatecrash_assert.h"
  38  #include <dispatch/dispatch.h>
  39  #include <stdlib.h>
  40  #include <string.h>
  41  #include <stdio.h>
  42  
  43  #include <corecrypto/ccdigest.h>
  44  
  45  #include <libaks.h>
  46  
  47  #if __has_feature(objc_arc)
  48  #define __SECBRIDGE  __bridge
  49  #else
  50  #define __SECBRIDGE
  51  #endif
  52  
  53  //
  54  // Convenience routines.
  55  //
  56  
  57  //
  58  // Macros for the pattern
  59  //
  60  // typedef struct _privateNewClass* NewClassRef;
  61  //
  62  // struct _privateNewClass {
  63  //      CFRuntimeBase _base;
  64  //      ... class additions
  65  // };
  66  //
  67  // kClassNameRegisterClass
  68  // kClassNameTypeID
  69  //
  70  // ClassNameGetTypeID()
  71  //
  72  // CFGiblisFor(NewClass);
  73  //
  74  // .. define NewClassDestroy
  75  // .. define NewClassCopyDescription
  76  //
  77  // .. use CFTypeAllocate(NewClass, _privateNewClass, allocator);
  78  //
  79  //
  80  
  81  // Call this to create a function that returns a singleton instance of type stype,
  82  // which is initialized once by calling doThisOnce, with result in its context.  Upon
  83  // completion body should assign to *result.
  84  
  85  extern CFStringRef kSecDebugFormatOption;
  86  
  87  extern CFDictionaryRef SecGetDebugDescriptionFormatOptions(void);
  88  
  89  typedef void (^SecBoolCFErrorCallback) (bool, CFErrorRef);
  90  
  91  #define CFGiblisGetSingleton(returnType, giblisClassName, result, doThisOnce) \
  92  returnType giblisClassName(void); \
  93  returnType giblisClassName(void) { \
  94      static dispatch_once_t s##giblisClassName##Once; \
  95      static returnType s##giblisClassName##Singleton; \
  96      returnType *result = &s##giblisClassName##Singleton; \
  97      dispatch_once(&s##giblisClassName##Once, doThisOnce); \
  98      return s##giblisClassName##Singleton; \
  99  }
 100  
 101  #define CFGiblisWithFunctions(gibliClassName, init_func, copy_func, finalize_func, equal_func, hash_func, copyFormattingDesc_func, copyDebugDesc_func, reclaim_func, refcount_func, run_once_block) \
 102  CFGiblisGetSingleton(CFTypeID, gibliClassName##GetTypeID, typeID, (^{ \
 103      void (^ const _onceBlock)(void) = (run_once_block); \
 104      static const CFRuntimeClass s##gibliClassName##Class = { \
 105          .version = (reclaim_func == NULL ? 0 : _kCFRuntimeResourcefulObject) \
 106                   | (refcount_func == NULL ? 0 : _kCFRuntimeCustomRefCount), \
 107          .className = #gibliClassName, \
 108          .init = init_func, \
 109          .copy = copy_func, \
 110          .finalize = finalize_func, \
 111          .equal = equal_func, \
 112          .hash = hash_func, \
 113          .copyFormattingDesc = copyFormattingDesc_func, \
 114          .copyDebugDesc = copyDebugDesc_func, \
 115          .reclaim = reclaim_func, \
 116          .refcount = refcount_func, \
 117      }; \
 118      *typeID = _CFRuntimeRegisterClass(&s##gibliClassName##Class); \
 119      if (_onceBlock) \
 120          _onceBlock(); \
 121  }))
 122  
 123  #define CFGiblisWithHashFor(gibliClassName) \
 124      static CFStringRef  gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
 125      static void         gibliClassName##Destroy(CFTypeRef cf); \
 126      static Boolean      gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
 127      static CFHashCode   gibliClassName##Hash(CFTypeRef cf); \
 128      static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
 129          return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\
 130      }\
 131      \
 132      CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, gibliClassName##Hash, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
 133  
 134  #define CFGiblisWithCompareFor(gibliClassName) \
 135      static CFStringRef  gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
 136      static void         gibliClassName##Destroy(CFTypeRef cf); \
 137      static Boolean      gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
 138      static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
 139          return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\
 140      }\
 141      \
 142      CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
 143  
 144  
 145  #define CFGiblisFor(gibliClassName) \
 146      static CFStringRef  gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
 147      static void         gibliClassName##Destroy(CFTypeRef cf); \
 148      static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
 149          return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\
 150      }\
 151      \
 152      CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, NULL, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
 153  
 154  #define CFTypeAllocateWithSpace(classType, space, allocator) \
 155      (classType##Ref) _CFRuntimeCreateInstance(allocator, classType##GetTypeID(), space, NULL)
 156  
 157  #define CFTypeAllocate(classType, internalType, allocator) \
 158      CFTypeAllocateWithSpace(classType, sizeof(internalType) - sizeof(CFRuntimeBase), allocator)
 159  
 160  #define SECWRAPPER_SENTINEL __attribute__((__sentinel__))
 161  
 162  __BEGIN_DECLS
 163  
 164  void withStringOfAbsoluteTime(CFAbsoluteTime at, void (^action)(CFStringRef decription));
 165  
 166  
 167  //
 168  // MARK: Call block function
 169  //
 170  
 171  
 172  static void apply_block_1(const void *value, void *context)
 173  {
 174      ((__SECBRIDGE void (^)(const void *value))context)(value);
 175  }
 176  
 177  static void apply_block_2(const void *key, const void *value, void *context)
 178  {
 179      ((__SECBRIDGE void (^)(const void *key, const void *value))context)(key, value);
 180  }
 181  
 182  //
 183  // MARK: Type checking
 184  //
 185  
 186  static inline bool isArray(CFTypeRef cfType) {
 187      return cfType && CFGetTypeID(cfType) == CFArrayGetTypeID();
 188  }
 189  
 190  static inline bool isSet(CFTypeRef cfType) {
 191      return cfType && CFGetTypeID(cfType) == CFSetGetTypeID();
 192  }
 193  
 194  static inline bool isData(CFTypeRef cfType) {
 195      return cfType && CFGetTypeID(cfType) == CFDataGetTypeID();
 196  }
 197  
 198  static inline bool isDate(CFTypeRef cfType) {
 199      return cfType && CFGetTypeID(cfType) == CFDateGetTypeID();
 200  }
 201  
 202  static inline bool isDictionary(CFTypeRef cfType) {
 203      return cfType && CFGetTypeID(cfType) == CFDictionaryGetTypeID();
 204  }
 205  
 206  static inline bool isNumber(CFTypeRef cfType) {
 207      return cfType && CFGetTypeID(cfType) == CFNumberGetTypeID();
 208  }
 209  
 210  static inline bool isNumberOfType(CFTypeRef cfType, CFNumberType number) {
 211      return isNumber(cfType) && CFNumberGetType((CFNumberRef)cfType) == number;
 212  }
 213  
 214  static inline bool isString(CFTypeRef cfType) {
 215      return cfType && CFGetTypeID(cfType) == CFStringGetTypeID();
 216  }
 217  
 218  static inline bool isBoolean(CFTypeRef cfType) {
 219      return cfType && CFGetTypeID(cfType) == CFBooleanGetTypeID();
 220  }
 221  
 222  static inline bool isNull(CFTypeRef cfType) {
 223      return cfType && CFGetTypeID(cfType) == CFNullGetTypeID();
 224  }
 225  
 226  // Usage: void foo(CFTypeRef value) { CFDataRef data = CFCast(CFData, value); }
 227  #define CFCast(type, value)                                               \
 228      ({ __typeof__(value) _v = (value); (_v != NULL) && CFGetTypeID(_v) == type ## GetTypeID() ? (type ## Ref)_v : NULL; })
 229  
 230  #define CFCastWithError(type, value, error)                                                      \
 231      ({ __typeof__(value) _v = (value); (_v != NULL) && CFGetTypeID(_v) == type ## GetTypeID() ?  \
 232          (type ## Ref)_v :                                                                        \
 233          (SecError(errSecParam, error, CFSTR("Unexpected type")), NULL); })
 234  
 235  //
 236  // MARK CFEqual Helpers
 237  //
 238  
 239  static inline bool CFEqualSafe(CFTypeRef left, CFTypeRef right)
 240  {
 241      if (left == NULL || right == NULL)
 242          return left == right;
 243      else
 244          return CFEqual(left, right);
 245  }
 246  
 247  
 248  //
 249  // MARK: Printing
 250  //
 251  
 252  static void fprint_string(FILE *file, CFStringRef string) {
 253      UInt8 buf[256];
 254      CFRange range = { .location = 0 };
 255      range.length = CFStringGetLength(string);
 256      while (range.length > 0) {
 257          CFIndex bytesUsed = 0;
 258          CFIndex converted = CFStringGetBytes(string, range, kCFStringEncodingUTF8, 0, false, buf, sizeof(buf), &bytesUsed);
 259          fwrite(buf, 1, bytesUsed, file);
 260          range.length -= converted;
 261          range.location += converted;
 262      }
 263  }
 264  
 265  static inline void cffprint_v(FILE *file, CFStringRef fmt, va_list args) CF_FORMAT_FUNCTION(2, 0);
 266  static void cffprint(FILE *file, CFStringRef fmt, ...) CF_FORMAT_FUNCTION(2,0);
 267  
 268  static inline void cffprint_v(FILE *file, CFStringRef fmt, va_list args) {
 269      CFStringRef line = CFStringCreateWithFormatAndArguments(NULL, NULL, fmt, args);
 270      fprint_string(file, line);
 271      CFRelease(line);
 272  }
 273  
 274  static inline void cffprint(FILE *file, CFStringRef fmt, ...) {
 275      va_list args;
 276      va_start(args, fmt);
 277      cffprint_v(file, fmt, args);
 278      va_end(args);
 279  }
 280  
 281  //
 282  // MARK: CFError Helpers
 283  //
 284  
 285  /* Return false if possibleError is set.  Propagates possibleError into *error
 286     if *error is NULL, otherwise releases possibleError. */
 287  static inline
 288  bool CFErrorPropagate(CFErrorRef possibleError CF_CONSUMED, CFErrorRef *error) {
 289      if (possibleError) {
 290          if (error && !*error) {
 291              *error = possibleError;
 292          } else {
 293              CFRelease(possibleError);
 294          }
 295          return false;
 296      }
 297      return true;
 298  }
 299  
 300  static inline bool CFErrorIsMalfunctioningKeybagError(CFErrorRef error){
 301      switch(CFErrorGetCode(error))
 302      {
 303          case(kAKSReturnError):
 304          case(kAKSReturnBusy):
 305          case(kAKSReturnNoPermission):
 306              break;
 307          default:
 308              return false;
 309      }
 310      return CFEqualSafe(CFErrorGetDomain(error), kSecKernDomain);
 311  }
 312  
 313  //
 314  // MARK: CFNumber Helpers
 315  //
 316  
 317  static inline CFNumberRef CFNumberCreateWithCFIndex(CFAllocatorRef allocator, CFIndex value)
 318  {
 319      return CFNumberCreate(allocator, kCFNumberCFIndexType, &value);
 320  }
 321  
 322  //
 323  // MARK: CFData Helpers
 324  //
 325  
 326  static inline CFMutableDataRef CFDataCreateMutableWithScratch(CFAllocatorRef allocator, CFIndex size) {
 327      CFMutableDataRef result = CFDataCreateMutable(allocator, 0);
 328      CFDataSetLength(result, size);
 329  
 330      return result;
 331  }
 332  
 333  static inline void CFDataAppend(CFMutableDataRef appendTo, CFDataRef dataToAppend)
 334  {
 335      CFDataAppendBytes(appendTo, CFDataGetBytePtr(dataToAppend), CFDataGetLength(dataToAppend));
 336  }
 337  
 338  static inline CFDataRef CFDataCreateReferenceFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
 339  {
 340      return CFDataCreateWithBytesNoCopy(allocator,
 341                                         CFDataGetBytePtr(sourceData) + range.location, range.length,
 342                                         kCFAllocatorNull);
 343  }
 344  
 345  static inline CFDataRef CFDataCreateCopyFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
 346  {
 347      return CFDataCreate(allocator, CFDataGetBytePtr(sourceData) + range.location, range.length);
 348  }
 349  
 350  CFDataRef CFDataCreateWithRandomBytes(size_t len);
 351  
 352  CFDataRef CFDataCreateWithInitializer(CFAllocatorRef allocator, CFIndex size, bool (^operation)(size_t size, uint8_t *buffer));
 353  
 354  static inline uint8_t* CFDataIncreaseLengthAndGetMutableBytes(CFMutableDataRef data, CFIndex extraLength)
 355  {
 356      CFIndex startOffset = CFDataGetLength(data);
 357  
 358      CFDataIncreaseLength(data, extraLength);
 359  
 360      return CFDataGetMutableBytePtr(data) + startOffset;
 361  }
 362  
 363  static inline uint8_t* CFDataGetMutablePastEndPtr(CFMutableDataRef theData)
 364  {
 365      return CFDataGetMutableBytePtr(theData) + CFDataGetLength(theData);
 366  }
 367  
 368  static inline const uint8_t* CFDataGetPastEndPtr(CFDataRef theData) {
 369      return CFDataGetBytePtr(theData) + CFDataGetLength(theData);
 370  }
 371  
 372  // This function compare DER data object, which take into account the length
 373  // of the data objects when doing the comparsion which item is "before" or "after"
 374  static inline CFComparisonResult CFDataCompareDERData(CFDataRef left, CFDataRef right)
 375  {
 376      const size_t left_size = CFDataGetLength(left);
 377      const size_t right_size = CFDataGetLength(right);
 378      const size_t shortest = (left_size <= right_size) ? left_size : right_size;
 379      
 380      int comparison = memcmp(CFDataGetBytePtr(left), CFDataGetBytePtr(right), shortest);
 381  
 382      if (comparison > 0 || (comparison == 0 && left_size > right_size))
 383          return kCFCompareGreaterThan;
 384      else if (comparison < 0 || (comparison == 0 && left_size < right_size))
 385          return kCFCompareLessThan;
 386      else
 387          return kCFCompareEqualTo;
 388  }
 389  
 390  static inline __deprecated_msg("please use CFEqual or CFDataCompareDERData") CFComparisonResult CFDataCompare(CFDataRef left, CFDataRef right) {
 391      return CFDataCompareDERData(left, right);
 392  }
 393  
 394  static inline CFDataRef CFDataCreateWithHash(CFAllocatorRef allocator, const struct ccdigest_info *di, const uint8_t *buffer, const uint8_t length) {
 395      CFMutableDataRef result = CFDataCreateMutableWithScratch(allocator, di->output_size);
 396  
 397      ccdigest(di, length, buffer, CFDataGetMutableBytePtr(result));
 398      
 399      return result;
 400  }
 401  
 402  
 403  static inline CFDataRef CFDataCreateCopyFromPositions(CFAllocatorRef allocator, CFDataRef source, CFIndex start, CFIndex end)
 404  {
 405      return CFDataCreateCopyFromRange(allocator, source, CFRangeMake(start, end - start));
 406  }
 407  
 408  static inline int nibletToByte(char niblet) {
 409      if(niblet >= '0' && niblet <= '9') return niblet - '0';
 410      if(niblet >= 'a' && niblet <= 'f') return niblet - 'a' + 10;
 411      if(niblet >= 'A' && niblet <= 'F') return niblet - 'A' + 10;
 412      return 0;
 413  }
 414  
 415  static inline CFDataRef CFDataCreateFromHexString(CFAllocatorRef allocator, CFStringRef sourceHex) {
 416      CFIndex sourceLen = CFStringGetLength(sourceHex);
 417      if((sourceLen % 2) != 0) return NULL;
 418      const char *src = CFStringGetCStringPtr(sourceHex, kCFStringEncodingUTF8);
 419      UInt8 bytes[sourceLen/2];
 420      for(int i = 0; i < sourceLen; i+=2) {
 421          bytes[i/2] = (UInt8) (nibletToByte(src[i]) * 16 + nibletToByte(src[i+1]));
 422      }
 423      return CFDataCreate(allocator, bytes, sourceLen/2);
 424  }
 425  
 426  
 427  //
 428  // MARK: CFString Helpers
 429  //
 430  
 431  CFComparisonResult CFStringCompareSafe(const void *val1, const void *val2, void *context);
 432  
 433  //
 434  // Turn a CFString into an allocated UTF8-encoded C string.
 435  //
 436  static inline char *CFStringToCString(CFStringRef inStr)
 437  {
 438      if (!inStr)
 439          return (char *)strdup("");
 440      CFRetain(inStr);        // compensate for release on exit
 441  
 442      // need to extract into buffer
 443      CFIndex length = CFStringGetLength(inStr);  // in 16-bit character units
 444      size_t len = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
 445      char *buffer = (char *)malloc(len);                 // pessimistic
 446      if (!CFStringGetCString(inStr, buffer, len, kCFStringEncodingUTF8))
 447          buffer[0] = 0;
 448  
 449      CFRelease(inStr);
 450      return buffer;
 451  }
 452  
 453  // runs operation with inStr as a zero terminated C string
 454  // in utf8 encoding passed to the operation block.
 455  void CFStringPerformWithCString(CFStringRef inStr, void(^operation)(const char *utf8Str));
 456  
 457  // runs operation with inStr as a zero terminated C string
 458  // in utf8 passed to the operation block, the length of
 459  // the string is also provided to the block.
 460  void CFStringPerformWithCStringAndLength(CFStringRef inStr, void(^operation)(const char *utf8Str, size_t utf8Length));
 461  
 462  void CFStringPerformWithUTF8CFData(CFStringRef inStr, void (^operation)(CFDataRef stringAsData));
 463  
 464  #include <CommonNumerics/CommonCRC.h>
 465  
 466  static inline void CFStringAppendEncryptedData(CFMutableStringRef s, CFDataRef edata)
 467  {
 468      const uint8_t *bytes = CFDataGetBytePtr(edata);
 469      CFIndex len = CFDataGetLength(edata);
 470      CFStringAppendFormat(s, 0, CFSTR("%04lx:"), len);
 471      if(len<=8) {
 472          for (CFIndex ix = 0; ix < len; ++ix) {
 473              CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
 474          }
 475      } else {
 476          uint64_t crc = 0;
 477          CNCRC(kCN_CRC_64_ECMA_182, bytes+8, len-8, &crc);
 478          for (CFIndex ix = 0; ix < 8; ++ix) {
 479              CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
 480          }
 481          CFStringAppendFormat(s, 0, CFSTR("...|%08llx"), crc);
 482      }
 483  }
 484  
 485  static inline void CFStringAppendHexData(CFMutableStringRef s, CFDataRef data) {
 486      const uint8_t *bytes = CFDataGetBytePtr(data);
 487      CFIndex len = CFDataGetLength(data);
 488      for (CFIndex ix = 0; ix < len; ++ix) {
 489          CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
 490      }
 491  }
 492  
 493  static inline CF_RETURNS_RETAINED CFStringRef CFDataCopyHexString(CFDataRef data) {
 494      CFMutableStringRef hexString = CFStringCreateMutable(kCFAllocatorDefault, 2 * CFDataGetLength(data));
 495      CFStringAppendHexData(hexString, data);
 496      return hexString;
 497  }
 498  
 499  static inline void CFDataPerformWithHexString(CFDataRef data, void (^operation)(CFStringRef dataString)) {
 500      CFStringRef hexString = data ? CFDataCopyHexString(data) : CFSTR("(null)");
 501      operation(hexString);
 502      CFRelease(hexString);
 503  }
 504  
 505  static inline void BufferPerformWithHexString(const UInt8 *bytes, CFIndex length, void (^operation)(CFStringRef dataString)) {
 506      CFDataRef bufferAsData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorNull);
 507      
 508      CFDataPerformWithHexString(bufferAsData, operation);
 509      
 510      CFReleaseNull(bufferAsData);
 511  }
 512  
 513  
 514  
 515  static inline void CFStringWriteToFile(CFStringRef inStr, FILE* file)
 516  {
 517      CFStringPerformWithCStringAndLength(inStr, ^(const char *utf8Str, size_t utf8Length) {
 518          fwrite(utf8Str, 1, utf8Length, file);
 519      });
 520  }
 521  
 522  static inline void CFStringWriteToFileWithNewline(CFStringRef inStr, FILE* file)
 523  {
 524      CFStringWriteToFile(inStr, file);
 525      fputc('\n', file);
 526  }
 527  
 528  static inline CFStringRef CFStringCreateTruncatedCopy(CFStringRef s, CFIndex len) {
 529      if(!s) return NULL;
 530      if(len >= CFStringGetLength(s)) return CFStringCreateCopy(kCFAllocatorDefault, s);
 531      return CFStringCreateWithSubstring(kCFAllocatorDefault, s, CFRangeMake(0, len));
 532  }
 533  
 534  //
 535  // MARK: CFCollectionHelpers
 536  //
 537  
 538  static inline
 539  const void *SecCFRetainForCollection(CFAllocatorRef __unused allocator, const void *value)
 540  {
 541      return CFRetain(value);
 542  }
 543  
 544  static inline
 545  void SecCFReleaseForCollection(CFAllocatorRef __unused allocator, const void *value)
 546  {
 547      CFRelease(value);
 548  }
 549  
 550  //
 551  // MARK: CFArray Helpers
 552  //
 553  
 554  static inline CFIndex CFArrayRemoveAllValue(CFMutableArrayRef array, const void* value)
 555  {
 556      CFIndex position = kCFNotFound;
 557      CFIndex numberRemoved = 0;
 558      
 559      position = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), value);
 560      while (position != kCFNotFound) {
 561          CFArrayRemoveValueAtIndex(array, position);
 562          ++numberRemoved;
 563          position = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), value);
 564      }
 565      
 566      return numberRemoved;
 567  }
 568  
 569  static inline void CFArrayAppendAll(CFMutableArrayRef array, CFArrayRef arrayToAppend) {
 570      CFArrayAppendArray(array, arrayToAppend, CFRangeMake(0, CFArrayGetCount(arrayToAppend)));
 571  }
 572  
 573  #define CFArrayForEachC(array, value) for (CFIndex _aCount = CFArrayGetCount(array), _aIX = 0;value = (__typeof__(value))(_aIX < _aCount ? CFArrayGetValueAtIndex(array, _aIX) : 0), _aIX < _aCount; ++_aIX)
 574  
 575  static inline void CFArrayForEach(CFArrayRef array, void (^operation)(const void *value)) {
 576      CFArrayApplyFunction(array, CFRangeMake(0, CFArrayGetCount(array)), apply_block_1, (__SECBRIDGE void *)operation);
 577  }
 578  
 579  static inline void CFArrayForEachReverse(CFArrayRef array, void (^operation)(const void *value)) {
 580      for(CFIndex count = CFArrayGetCount(array); count > 0; --count) {
 581          operation(CFArrayGetValueAtIndex(array, count - 1));
 582      }
 583  }
 584  
 585  static inline const void *CFArrayGetValueMatching(CFArrayRef array, bool (^match)(const void *value)) {
 586      CFIndex i, n = CFArrayGetCount(array);
 587      for (i = 0; i < n; ++i) {
 588          const void *value = CFArrayGetValueAtIndex(array, i);
 589          if (match(value)) {
 590              return value;
 591          }
 592      }
 593      return NULL;
 594  }
 595  
 596  static inline bool CFArrayHasValueMatching(CFArrayRef array, bool (^match)(const void *value)) {
 597      return CFArrayGetValueMatching(array, match) != NULL;
 598  }
 599  
 600  static inline void CFMutableArrayModifyValues(CFMutableArrayRef array, const void * (^process)(const void *value)) {
 601      CFIndex i, n = CFArrayGetCount(array);
 602      for (i = 0; i < n; ++i) {
 603          const void *value = CFArrayGetValueAtIndex(array, i);
 604          CFArraySetValueAtIndex(array, i, process(value));
 605      }
 606  }
 607  
 608  static inline void CFArraySubtract(CFMutableArrayRef from, CFArrayRef remove) {
 609      if (remove && from) {
 610          CFArrayForEach(remove, ^(const void *value) {
 611              CFArrayRemoveAllValue(from, value);
 612          });
 613      }
 614  }
 615  
 616  static inline CFMutableArrayRef CFArrayCreateDifference(CFAllocatorRef alloc, CFArrayRef set, CFArrayRef remove) {
 617      CFMutableArrayRef result;
 618      if (!set) {
 619          result = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
 620      } else {
 621          result = CFArrayCreateMutableCopy(alloc, 0, set);
 622          if (remove)
 623              CFArraySubtract(result, remove);
 624      }
 625  
 626      return result;
 627  }
 628  
 629  //
 630  // MARK: CFArray creation Var args helper functions.
 631  //
 632  static inline CFArrayRef CFArrayCreateCountedForVC(CFAllocatorRef allocator, const CFArrayCallBacks *cbs, CFIndex entries, va_list args)
 633  {
 634      CFMutableArrayRef array = CFArrayCreateMutable(allocator, entries, cbs);
 635      if (array == NULL) {
 636          return NULL;
 637      }
 638      for (CFIndex currentValue = 0; currentValue < entries; ++currentValue) {
 639          const void * value = va_arg(args, const void *);
 640          if (value == NULL) {
 641              value = kCFNull;
 642          }
 643          CFArrayAppendValue(array, value);
 644      }
 645  
 646      CFArrayRef constArray = CFArrayCreateCopy(allocator, array);
 647      CFRelease(array);
 648      return constArray;
 649  }
 650  
 651  static inline CFArrayRef CFArrayCreateForVC(CFAllocatorRef allocator, const CFArrayCallBacks *cbs, va_list args)
 652  {
 653      va_list count;
 654      va_copy(count, args);
 655  
 656      CFIndex entries = 0;
 657      while (NULL != va_arg(count, void*)) {
 658          entries += 1;
 659      }
 660  
 661      return CFArrayCreateCountedForVC(allocator, cbs, entries, args);
 662  }
 663  
 664  
 665  
 666  //
 667  // MARK: CFArray of CFTypes support
 668  //
 669  
 670  static inline CFMutableArrayRef CFArrayCreateMutableForCFTypesWithCapacity(CFAllocatorRef allocator, CFIndex capacity)
 671  {
 672      return CFArrayCreateMutable(allocator, capacity, &kCFTypeArrayCallBacks);
 673  }
 674  
 675  static inline CFMutableArrayRef SECWRAPPER_SENTINEL CFArrayCreateMutableForCFTypesWith(CFAllocatorRef allocator, ...)
 676  {
 677  
 678      va_list args;
 679      va_start(args, allocator);
 680      CFIndex capacity = 0;
 681      void* object = va_arg(args, void*);
 682  
 683      while (object != NULL) {
 684          object = va_arg(args, void*);
 685          capacity++;
 686      };
 687      
 688      va_end(args);
 689      
 690      CFMutableArrayRef result = CFArrayCreateMutableForCFTypesWithCapacity(allocator, capacity);
 691  
 692      va_start(args, allocator);
 693      object = va_arg(args, void*);
 694  
 695      while (object != NULL) {
 696          CFArrayAppendValue(result, object);
 697          object = va_arg(args, void*);
 698      };
 699      
 700      va_end(args);
 701      return result;
 702  }
 703  
 704  
 705  static inline CFMutableArrayRef CFArrayCreateMutableForCFTypes(CFAllocatorRef allocator)
 706  {
 707      return CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
 708  }
 709  
 710  static inline CFArrayRef SECWRAPPER_SENTINEL CFArrayCreateForCFTypes(CFAllocatorRef allocator, ...)
 711  {
 712      va_list args;
 713      va_start(args, allocator);
 714      CFArrayRef allocatedArray = CFArrayCreateForVC(allocator, &kCFTypeArrayCallBacks, args);
 715      va_end(args);
 716      return allocatedArray;
 717      
 718  }
 719  
 720  static inline CFArrayRef CFArrayCreateCountedForCFTypes(CFAllocatorRef allocator, CFIndex entries, ...)
 721  {
 722      va_list args;
 723      va_start(args, entries);
 724      CFArrayRef allocatedArray = CFArrayCreateCountedForVC(allocator, &kCFTypeArrayCallBacks, entries, args);
 725      va_end(args);
 726      return allocatedArray;
 727  }
 728  
 729  static inline CFArrayRef CFArrayCreateCountedForCFTypesV(CFAllocatorRef allocator, CFIndex entries, va_list args)
 730  {
 731      return CFArrayCreateCountedForVC(allocator, &kCFTypeArrayCallBacks, entries, args);
 732  }
 733  
 734  //
 735  // MARK: CFDictionary of CFTypes helpers
 736  //
 737  
 738  static void CFDictionarySetIfNonNull(CFMutableDictionaryRef dictionary, const void *key, const void *value) {
 739      if (value) {
 740          CFDictionarySetValue(dictionary, key, value);
 741      }
 742  }
 743  
 744  static inline CFDictionaryRef CFDictionaryCreateCountedForCFTypesV(CFAllocatorRef allocator, CFIndex entries, va_list args)
 745  {
 746      CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(allocator, entries,
 747                                                                    &kCFTypeDictionaryKeyCallBacks,
 748                                                                    &kCFTypeDictionaryValueCallBacks);
 749      if (dictionary == NULL) {
 750          return NULL;
 751      }
 752  
 753      for(CFIndex currentValue = 0; currentValue < entries; ++currentValue) {
 754          CFTypeRef key = va_arg(args, CFTypeRef);
 755          CFTypeRef value = va_arg(args, CFTypeRef);
 756          if (value == NULL) {
 757              value = kCFNull;
 758          }
 759          CFDictionarySetValue(dictionary, key, value);
 760      }
 761      
 762      CFDictionaryRef constDictionary = CFDictionaryCreateCopy(allocator, dictionary);
 763      CFRelease(dictionary);
 764      return constDictionary;
 765  }
 766  
 767  static inline CFDictionaryRef SECWRAPPER_SENTINEL CFDictionaryCreateForCFTypes(CFAllocatorRef allocator, ...)
 768  {
 769      va_list args;
 770      va_start(args, allocator);
 771  
 772      CFIndex entries = 0;
 773      while (NULL != va_arg(args, void*)) {
 774          entries += 2;
 775          (void) va_arg(args, void*);
 776      }
 777  
 778      entries /= 2;
 779      va_end(args);
 780      va_start(args, allocator);
 781      CFDictionaryRef allocatedDictionary = CFDictionaryCreateCountedForCFTypesV(allocator, entries, args);
 782      va_end(args);
 783      return allocatedDictionary;
 784  }
 785  
 786  static inline CFDictionaryRef CFDictionaryCreateCountedForCFTypes(CFAllocatorRef allocator, CFIndex entries, ...)
 787  {
 788      va_list args;
 789      va_start(args, entries);
 790      CFDictionaryRef allocatedDictionary = CFDictionaryCreateCountedForCFTypesV(allocator, entries, args);
 791      va_end(args);
 792  
 793      return allocatedDictionary;
 794  }
 795  
 796  static inline CFMutableDictionaryRef CFDictionaryCreateMutableForCFTypes(CFAllocatorRef allocator)
 797  {
 798      return CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 799  }
 800  
 801  static inline CFMutableDictionaryRef SECWRAPPER_SENTINEL CFDictionaryCreateMutableForCFTypesWith(CFAllocatorRef allocator, ...)
 802  {
 803      CFMutableDictionaryRef result = CFDictionaryCreateMutableForCFTypes(allocator);
 804  
 805      va_list args;
 806      va_start(args, allocator);
 807  
 808      void* key = va_arg(args, void*);
 809  
 810      while (key != NULL) {
 811          CFDictionarySetValue(result, key, va_arg(args, void*));
 812          key = va_arg(args, void*);
 813      };
 814      va_end(args);
 815      return result;
 816  }
 817  
 818  static inline CFMutableDictionaryRef SECWRAPPER_SENTINEL CFDictionaryCreateMutableForCFTypesWithSafe(CFAllocatorRef allocator, ...)
 819  {
 820      CFMutableDictionaryRef result = CFDictionaryCreateMutableForCFTypes(allocator);
 821  
 822      va_list args;
 823      va_start(args, allocator);
 824  
 825      void* key = va_arg(args, void*);
 826  
 827      while (key != NULL) {
 828          CFDictionarySetIfNonNull(result, key, va_arg(args, void*));
 829          key = va_arg(args, void*);
 830      };
 831      va_end(args);
 832      return result;
 833  }
 834  
 835  //
 836  // MARK: CFSet Helpers
 837  //
 838  
 839  static inline CFMutableSetRef CFSetCreateMutableForCFTypes(CFAllocatorRef allocator)
 840  {
 841      return CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks);
 842  }
 843  
 844  static inline bool CFSetIsEmpty(CFSetRef set) {
 845      return CFSetGetCount(set) == 0;
 846  }
 847  
 848  static inline void CFSetForEach(CFSetRef set, void (^operation)(const void *value)) {
 849      CFSetApplyFunction(set, apply_block_1, (__SECBRIDGE void *)operation);
 850  }
 851  
 852  static inline void CFSetUnion(CFMutableSetRef set, CFSetRef unionWith) {
 853      CFSetForEach(unionWith, ^(const void *value) {
 854          CFSetSetValue(set, value);
 855      });
 856  }
 857  
 858  static inline void CFSetSubtract(CFMutableSetRef set, CFSetRef subtract) {
 859      CFSetForEach(subtract, ^(const void *value) {
 860          CFSetRemoveValue(set, value);
 861      });
 862  }
 863  
 864  static inline bool CFSetIsSubset(CFSetRef smaller, CFSetRef bigger) {
 865      __block bool isSubset = true;
 866      CFSetForEach(smaller, ^(const void *value) {
 867          if (!CFSetContainsValue(bigger, value)) {
 868              isSubset = false;
 869          }
 870      });
 871  
 872      return isSubset;
 873  }
 874  
 875  static inline void CFSetSetValues(CFMutableSetRef set, CFArrayRef valuesToSet) {
 876      CFArrayForEach(valuesToSet, ^(const void *value) {
 877          CFSetSetValue(set, value);
 878      });
 879  }
 880  
 881  static inline CFMutableArrayRef CFSetCopyValues(CFSetRef set) {
 882      CFMutableArrayRef values = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
 883      
 884      CFSetForEach(set, ^(const void *value) {
 885          CFArrayAppendValue(values, value);
 886      });
 887      
 888      return values;
 889  }
 890  
 891  static inline bool CFSetIntersectionIsEmpty(CFSetRef set1, CFSetRef set2) {
 892      __block bool intersectionIsEmpty = true;
 893      if(set1 != NULL && set2 != NULL) {
 894          CFSetForEach(set1, ^(const void *value) {
 895              intersectionIsEmpty &= !CFSetContainsValue(set2, value);
 896          });
 897      }
 898      return intersectionIsEmpty;
 899  }
 900  
 901  static inline bool CFSetIntersects(CFSetRef set1, CFSetRef set2) {
 902      return !CFSetIntersectionIsEmpty(set1, set2);
 903  }
 904  
 905  static inline CFMutableSetRef CFSetCreateIntersection(CFAllocatorRef allocator, CFSetRef a, CFSetRef b) {
 906      CFMutableSetRef result = CFSetCreateMutableCopy(allocator, 0, a);
 907  
 908      CFSetRemoveAllValues(result);
 909      CFSetForEach(a, ^(const void *value) {
 910          if (CFSetContainsValue(b, value)) {
 911              CFSetAddValue(result, value);
 912          }
 913      });
 914  
 915      return result;
 916  }
 917  
 918  static inline CFSetRef CFSetCreateCopyOfArrayForCFTypes(CFArrayRef array) {
 919      CFIndex count = CFArrayGetCount(array);
 920      if (SIZE_MAX/sizeof(const void *) < (size_t)count) {
 921          return NULL;
 922      }
 923      const void **values = (const void **)malloc(sizeof(const void *) * count);
 924      CFArrayGetValues(array, CFRangeMake(0, count), values);
 925      CFSetRef set = CFSetCreate(CFGetAllocator(array), values, count, &kCFTypeSetCallBacks);
 926      free(values);
 927      return set;
 928  }
 929  
 930  static inline void CFSetTransferObject(CFTypeRef object, CFMutableSetRef from, CFMutableSetRef to) {
 931      CFSetAddValue(to, object);
 932      CFSetRemoveValue(from, object);
 933  }
 934  
 935  //
 936  // MARK: CFStringXxx Helpers
 937  //
 938  
 939  void CFStringArrayPerformWithDelimiterWithDescription(CFArrayRef strings, CFStringRef start, CFStringRef end, void (^action)(CFStringRef description));
 940  void CFStringArrayPerformWithDescription(CFArrayRef strings, void (^action)(CFStringRef description));
 941  void CFStringSetPerformWithDescription(CFSetRef set, void (^action)(CFStringRef description));
 942  
 943  //
 944  // MARK: CFDictionary Helpers
 945  //
 946  
 947  static inline void CFDictionaryForEach(CFDictionaryRef dictionary, void (^operation)(const void *key, const void *value)) {
 948      CFDictionaryApplyFunction(dictionary, apply_block_2, (__SECBRIDGE void *)operation);
 949  }
 950  
 951  CFStringRef CFDictionaryCopyCompactDescription(CFDictionaryRef dictionary);
 952  CFStringRef CFDictionaryCopySuperCompactDescription(CFDictionaryRef dictionary);
 953  
 954  //
 955  // MARK: CFCalendar helpers
 956  //
 957  
 958  void SecCFCalendarDoWithZuluCalendar(void(^action)(CFCalendarRef zuluCalendar));
 959  
 960  //
 961  // MARK: CFAbsoluteTime helpers
 962  //
 963  
 964  static inline CFAbsoluteTime CFAbsoluteTimeForCalendarMoment(CFCalendarRef cal, int year, int month, int day, int hour, int minute, int second) {
 965      CFAbsoluteTime at;
 966      CFCalendarComposeAbsoluteTime(cal, &at, "yMdHms", year, month, day, hour, minute, second);
 967      return at;
 968  }
 969  
 970  static inline CFAbsoluteTime CFAbsoluteTimeForCalendarDay(CFCalendarRef cal, int year, int month, int day) {
 971      CFAbsoluteTime at;
 972      CFCalendarComposeAbsoluteTime(cal, &at, "yMd", year, month, day);
 973      return at;
 974  }
 975  
 976  static inline CFAbsoluteTime CFAbsoluteTimeForGregorianMoment(CFTimeZoneRef tz, int year, int month, int day, int hour, int minute, int second)
 977  {
 978      CFCalendarRef cal = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar);
 979      CFCalendarSetTimeZone(cal, tz);
 980      CFAbsoluteTime at = CFAbsoluteTimeForCalendarMoment(cal, year, month, day, hour, minute, second);
 981      CFReleaseSafe(cal);
 982      return at;
 983  }
 984  
 985  static inline CFAbsoluteTime CFAbsoluteTimeForGregorianDay(CFTimeZoneRef tz, int year, int month, int day)
 986  {
 987      CFCalendarRef cal = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar);
 988      CFCalendarSetTimeZone(cal, tz);
 989      CFAbsoluteTime at = CFAbsoluteTimeForCalendarDay(cal, year, month, day);
 990      CFReleaseSafe(cal);
 991      return at;
 992  }
 993  
 994  static inline CFAbsoluteTime CFAbsoluteTimeForGregorianZuluMoment(int year, int month, int day, int hour, int minute, int second)
 995  {
 996      __block CFAbsoluteTime result = 0.0;
 997      SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
 998          result = CFAbsoluteTimeForCalendarMoment(zuluCalendar, year, month, day, hour, minute, second);
 999      });
1000      return result;
1001  }
1002  
1003  
1004  static inline CFAbsoluteTime CFAbsoluteTimeForGregorianZuluDay(int year, int month, int day)
1005  {
1006      __block CFAbsoluteTime result = 0.0;
1007      SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
1008          result = CFAbsoluteTimeForCalendarDay(zuluCalendar, year, month, day);
1009      });
1010      return result;
1011  }
1012  
1013  
1014  
1015  //
1016  // MARK: CFDate Helpers
1017  //
1018  
1019  static inline CFDateRef CFDateCreateForGregorianMoment(CFAllocatorRef allocator, CFTimeZoneRef tz, int year, int month, int day, int hour, int minute, int second)
1020  {
1021      return CFDateCreate(allocator, CFAbsoluteTimeForGregorianMoment(tz, year, month, day, hour, minute, second));
1022  }
1023  
1024  static inline CFDateRef CFDateCreateForGregorianDay(CFAllocatorRef allocator, CFTimeZoneRef tz, int year, int month, int day,
1025                                                      int __unused hour, int __unused minute, int __unused second)
1026  {
1027      return CFDateCreate(allocator, CFAbsoluteTimeForGregorianDay(tz, year, month, day));
1028  }
1029  
1030  static inline CFDateRef CFDateCreateForGregorianZuluMoment(CFAllocatorRef allocator, int year, int month, int day, int hour, int minute, int second)
1031  {
1032      return CFDateCreate(allocator, CFAbsoluteTimeForGregorianZuluMoment(year, month, day, hour, minute, second));
1033  }
1034  
1035  static inline CFDateRef CFDateCreateForGregorianZuluDay(CFAllocatorRef allocator, int year, int month, int day)
1036  {
1037      return CFDateCreate(allocator, CFAbsoluteTimeForGregorianZuluDay(year, month, day));
1038  }
1039  
1040  //
1041  // MARK: PropertyList Helpers
1042  //
1043  
1044  //
1045  // Crazy reading and writing stuff
1046  //
1047  
1048  static inline void CFPropertyListWriteToFile(CFPropertyListRef plist, CFURLRef file)
1049  {
1050      CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, file);
1051      CFErrorRef error = NULL;
1052      
1053      CFWriteStreamOpen(writeStream);
1054      CFPropertyListWrite(plist, writeStream, kCFPropertyListBinaryFormat_v1_0, 0, &error);
1055      if (error)
1056          secerror("Can't write plist: %@", error);
1057      
1058      CFReleaseNull(error);
1059      CFReleaseNull(writeStream);
1060  }
1061  
1062  static inline CF_RETURNS_RETAINED CFPropertyListRef CFPropertyListReadFromFile(CFURLRef file)
1063  {
1064      CFPropertyListRef result = NULL;
1065      CFErrorRef error = NULL;
1066      CFBooleanRef isRegularFile;
1067      if (!CFURLCopyResourcePropertyForKey(file, kCFURLIsRegularFileKey, &isRegularFile, &error)) {
1068          secinfo("plist", "file %@: %@", file, error);
1069      } else if (CFBooleanGetValue(isRegularFile)) {
1070          CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, file);
1071          if (readStream) {
1072              if (CFReadStreamOpen(readStream)) {
1073                  CFPropertyListFormat format;
1074                  result = CFPropertyListCreateWithStream(kCFAllocatorDefault, readStream, 0, kCFPropertyListMutableContainers, &format, &error);
1075                  if (!result) {
1076                      secerror("read plist from %@: %@", file, error);
1077                  }
1078              }
1079              CFRelease(readStream);
1080          }
1081      }
1082      CFReleaseNull(error);
1083      
1084      return result;
1085  }
1086  
1087  __END_DECLS
1088  
1089  #endif /* _SECCFWRAPPERS_H_ */