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_ */