2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #ifndef _SECCFWRAPPERS_H_
26 #define _SECCFWRAPPERS_H_
28 #include <CoreFoundation/CFRuntime.h>
29 #include <CoreFoundation/CoreFoundation.h>
31 #include "utilities/SecCFRelease.h"
32 #include "utilities/debugging.h"
33 #include "utilities/SecCFError.h"
35 #include <IOKit/IOReturn.h>
37 #include "utilities/simulatecrash_assert.h"
38 #include <dispatch/dispatch.h>
43 #include <corecrypto/ccdigest.h>
47 #if __has_feature(objc_arc)
48 #define __SECBRIDGE __bridge
54 // Convenience routines.
58 // Macros for the pattern
60 // typedef struct _privateNewClass* NewClassRef;
62 // struct _privateNewClass {
63 // CFRuntimeBase _base;
64 // ... class additions
67 // kClassNameRegisterClass
70 // ClassNameGetTypeID()
72 // CFGiblisFor(NewClass);
74 // .. define NewClassDestroy
75 // .. define NewClassCopyDescription
77 // .. use CFTypeAllocate(NewClass, _privateNewClass, allocator);
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.
85 extern CFStringRef kSecDebugFormatOption
;
87 extern CFDictionaryRef
SecGetDebugDescriptionFormatOptions(void);
89 typedef void (^SecBoolCFErrorCallback
) (bool, CFErrorRef
);
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; \
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, \
110 .finalize = finalize_func, \
111 .equal = equal_func, \
113 .copyFormattingDesc = copyFormattingDesc_func, \
114 .copyDebugDesc = copyDebugDesc_func, \
115 .reclaim = reclaim_func, \
116 .refcount = refcount_func, \
118 *typeID = _CFRuntimeRegisterClass(&s##gibliClassName##Class); \
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());\
132 CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, gibliClassName##Hash, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
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());\
142 CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
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());\
152 CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, NULL, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
154 #define CFTypeAllocateWithSpace(classType, space, allocator) \
155 (classType##Ref) _CFRuntimeCreateInstance(allocator, classType##GetTypeID(), space, NULL)
157 #define CFTypeAllocate(classType, internalType, allocator) \
158 CFTypeAllocateWithSpace(classType, sizeof(internalType) - sizeof(CFRuntimeBase), allocator)
160 #define SECWRAPPER_SENTINEL __attribute__((__sentinel__))
164 void withStringOfAbsoluteTime(CFAbsoluteTime at
, void (^action
)(CFStringRef decription
));
168 // MARK: Call block function
172 static void apply_block_1(const void *value
, void *context
)
174 ((__SECBRIDGE
void (^)(const void *value
))context
)(value
);
177 static void apply_block_2(const void *key
, const void *value
, void *context
)
179 ((__SECBRIDGE
void (^)(const void *key
, const void *value
))context
)(key
, value
);
183 // MARK: Type checking
186 static inline bool isArray(CFTypeRef cfType
) {
187 return cfType
&& CFGetTypeID(cfType
) == CFArrayGetTypeID();
190 static inline bool isSet(CFTypeRef cfType
) {
191 return cfType
&& CFGetTypeID(cfType
) == CFSetGetTypeID();
194 static inline bool isData(CFTypeRef cfType
) {
195 return cfType
&& CFGetTypeID(cfType
) == CFDataGetTypeID();
198 static inline bool isDate(CFTypeRef cfType
) {
199 return cfType
&& CFGetTypeID(cfType
) == CFDateGetTypeID();
202 static inline bool isDictionary(CFTypeRef cfType
) {
203 return cfType
&& CFGetTypeID(cfType
) == CFDictionaryGetTypeID();
206 static inline bool isNumber(CFTypeRef cfType
) {
207 return cfType
&& CFGetTypeID(cfType
) == CFNumberGetTypeID();
210 static inline bool isNumberOfType(CFTypeRef cfType
, CFNumberType number
) {
211 return isNumber(cfType
) && CFNumberGetType((CFNumberRef
)cfType
) == number
;
214 static inline bool isString(CFTypeRef cfType
) {
215 return cfType
&& CFGetTypeID(cfType
) == CFStringGetTypeID();
218 static inline bool isBoolean(CFTypeRef cfType
) {
219 return cfType
&& CFGetTypeID(cfType
) == CFBooleanGetTypeID();
222 static inline bool isNull(CFTypeRef cfType
) {
223 return cfType
&& CFGetTypeID(cfType
) == CFNullGetTypeID();
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; })
230 #define CFCastWithError(type, value, error) \
231 ({ __typeof__(value) _v = (value); (_v != NULL) && CFGetTypeID(_v) == type ## GetTypeID() ? \
233 (SecError(errSecParam, error, CFSTR("Unexpected type")), NULL); })
236 // MARK CFEqual Helpers
239 static inline bool CFEqualSafe(CFTypeRef left
, CFTypeRef right
)
241 if (left
== NULL
|| right
== NULL
)
242 return left
== right
;
244 return CFEqual(left
, right
);
252 static void fprint_string(FILE *file
, CFStringRef string
) {
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
;
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);
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
);
274 static inline void cffprint(FILE *file
, CFStringRef fmt
, ...) {
277 cffprint_v(file
, fmt
, args
);
282 // MARK: CFError Helpers
285 /* Return false if possibleError is set. Propagates possibleError into *error
286 if *error is NULL, otherwise releases possibleError. */
288 bool CFErrorPropagate(CFErrorRef possibleError CF_CONSUMED
, CFErrorRef
*error
) {
290 if (error
&& !*error
) {
291 *error
= possibleError
;
293 CFRelease(possibleError
);
300 static inline bool CFErrorIsMalfunctioningKeybagError(CFErrorRef error
){
301 switch(CFErrorGetCode(error
))
303 case(kAKSReturnError
):
304 case(kAKSReturnBusy
):
305 case(kAKSReturnNoPermission
):
310 return CFEqualSafe(CFErrorGetDomain(error
), kSecKernDomain
);
314 // MARK: CFNumber Helpers
317 static inline CFNumberRef
CFNumberCreateWithCFIndex(CFAllocatorRef allocator
, CFIndex value
)
319 return CFNumberCreate(allocator
, kCFNumberCFIndexType
, &value
);
323 // MARK: CFData Helpers
326 static inline CFMutableDataRef
CFDataCreateMutableWithScratch(CFAllocatorRef allocator
, CFIndex size
) {
327 CFMutableDataRef result
= CFDataCreateMutable(allocator
, 0);
328 CFDataSetLength(result
, size
);
333 static inline void CFDataAppend(CFMutableDataRef appendTo
, CFDataRef dataToAppend
)
335 CFDataAppendBytes(appendTo
, CFDataGetBytePtr(dataToAppend
), CFDataGetLength(dataToAppend
));
338 static inline CFDataRef
CFDataCreateReferenceFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
)
340 return CFDataCreateWithBytesNoCopy(allocator
,
341 CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
,
345 static inline CFDataRef
CFDataCreateCopyFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
)
347 return CFDataCreate(allocator
, CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
);
350 CFDataRef
CFDataCreateWithRandomBytes(size_t len
);
352 CFDataRef
CFDataCreateWithInitializer(CFAllocatorRef allocator
, CFIndex size
, bool (^operation
)(size_t size
, uint8_t *buffer
));
354 static inline uint8_t* CFDataIncreaseLengthAndGetMutableBytes(CFMutableDataRef data
, CFIndex extraLength
)
356 CFIndex startOffset
= CFDataGetLength(data
);
358 CFDataIncreaseLength(data
, extraLength
);
360 return CFDataGetMutableBytePtr(data
) + startOffset
;
363 static inline uint8_t* CFDataGetMutablePastEndPtr(CFMutableDataRef theData
)
365 return CFDataGetMutableBytePtr(theData
) + CFDataGetLength(theData
);
368 static inline const uint8_t* CFDataGetPastEndPtr(CFDataRef theData
) {
369 return CFDataGetBytePtr(theData
) + CFDataGetLength(theData
);
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
)
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
;
380 int comparison
= memcmp(CFDataGetBytePtr(left
), CFDataGetBytePtr(right
), shortest
);
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
;
387 return kCFCompareEqualTo
;
390 static inline __deprecated_msg("please use CFEqual or CFDataCompareDERData") CFComparisonResult
CFDataCompare(CFDataRef left
, CFDataRef right
) {
391 return CFDataCompareDERData(left
, right
);
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
);
397 ccdigest(di
, length
, buffer
, CFDataGetMutableBytePtr(result
));
403 static inline CFDataRef
CFDataCreateCopyFromPositions(CFAllocatorRef allocator
, CFDataRef source
, CFIndex start
, CFIndex end
)
405 return CFDataCreateCopyFromRange(allocator
, source
, CFRangeMake(start
, end
- start
));
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;
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]));
423 return CFDataCreate(allocator
, bytes
, sourceLen
/2);
428 // MARK: CFString Helpers
431 CFComparisonResult
CFStringCompareSafe(const void *val1
, const void *val2
, void *context
);
434 // Turn a CFString into an allocated UTF8-encoded C string.
436 static inline char *CFStringToCString(CFStringRef inStr
)
439 return (char *)strdup("");
440 CFRetain(inStr
); // compensate for release on exit
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
))
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
));
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
));
462 void CFStringPerformWithUTF8CFData(CFStringRef inStr
, void (^operation
)(CFDataRef stringAsData
));
464 #include <CommonNumerics/CommonCRC.h>
466 static inline void CFStringAppendEncryptedData(CFMutableStringRef s
, CFDataRef edata
)
468 const uint8_t *bytes
= CFDataGetBytePtr(edata
);
469 CFIndex len
= CFDataGetLength(edata
);
470 CFStringAppendFormat(s
, 0, CFSTR("%04lx:"), len
);
472 for (CFIndex ix
= 0; ix
< len
; ++ix
) {
473 CFStringAppendFormat(s
, 0, CFSTR("%02X"), bytes
[ix
]);
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
]);
481 CFStringAppendFormat(s
, 0, CFSTR("...|%08llx"), crc
);
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
]);
493 static inline CF_RETURNS_RETAINED CFStringRef
CFDataCopyHexString(CFDataRef data
) {
494 CFMutableStringRef hexString
= CFStringCreateMutable(kCFAllocatorDefault
, 2 * CFDataGetLength(data
));
495 CFStringAppendHexData(hexString
, data
);
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
);
505 static inline void BufferPerformWithHexString(const UInt8
*bytes
, CFIndex length
, void (^operation
)(CFStringRef dataString
)) {
506 CFDataRef bufferAsData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, bytes
, length
, kCFAllocatorNull
);
508 CFDataPerformWithHexString(bufferAsData
, operation
);
510 CFReleaseNull(bufferAsData
);
515 static inline void CFStringWriteToFile(CFStringRef inStr
, FILE* file
)
517 CFStringPerformWithCStringAndLength(inStr
, ^(const char *utf8Str
, size_t utf8Length
) {
518 fwrite(utf8Str
, 1, utf8Length
, file
);
522 static inline void CFStringWriteToFileWithNewline(CFStringRef inStr
, FILE* file
)
524 CFStringWriteToFile(inStr
, file
);
528 static inline CFStringRef
CFStringCreateTruncatedCopy(CFStringRef s
, CFIndex len
) {
530 if(len
>= CFStringGetLength(s
)) return CFStringCreateCopy(kCFAllocatorDefault
, s
);
531 return CFStringCreateWithSubstring(kCFAllocatorDefault
, s
, CFRangeMake(0, len
));
535 // MARK: CFCollectionHelpers
539 const void *SecCFRetainForCollection(CFAllocatorRef __unused allocator
, const void *value
)
541 return CFRetain(value
);
545 void SecCFReleaseForCollection(CFAllocatorRef __unused allocator
, const void *value
)
551 // MARK: CFArray Helpers
554 static inline CFIndex
CFArrayRemoveAllValue(CFMutableArrayRef array
, const void* value
)
556 CFIndex position
= kCFNotFound
;
557 CFIndex numberRemoved
= 0;
559 position
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), value
);
560 while (position
!= kCFNotFound
) {
561 CFArrayRemoveValueAtIndex(array
, position
);
563 position
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), value
);
566 return numberRemoved
;
569 static inline void CFArrayAppendAll(CFMutableArrayRef array
, CFArrayRef arrayToAppend
) {
570 CFArrayAppendArray(array
, arrayToAppend
, CFRangeMake(0, CFArrayGetCount(arrayToAppend
)));
573 #define CFArrayForEachC(array, value) for (CFIndex _aCount = CFArrayGetCount(array), _aIX = 0;value = (__typeof__(value))(_aIX < _aCount ? CFArrayGetValueAtIndex(array, _aIX) : 0), _aIX < _aCount; ++_aIX)
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
);
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));
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
);
596 static inline bool CFArrayHasValueMatching(CFArrayRef array
, bool (^match
)(const void *value
)) {
597 return CFArrayGetValueMatching(array
, match
) != NULL
;
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
));
608 static inline void CFArraySubtract(CFMutableArrayRef from
, CFArrayRef remove
) {
609 if (remove
&& from
) {
610 CFArrayForEach(remove
, ^(const void *value
) {
611 CFArrayRemoveAllValue(from
, value
);
616 static inline CFMutableArrayRef
CFArrayCreateDifference(CFAllocatorRef alloc
, CFArrayRef set
, CFArrayRef remove
) {
617 CFMutableArrayRef result
;
619 result
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
621 result
= CFArrayCreateMutableCopy(alloc
, 0, set
);
623 CFArraySubtract(result
, remove
);
630 // MARK: CFArray creation Var args helper functions.
632 static inline CFArrayRef
CFArrayCreateCountedForVC(CFAllocatorRef allocator
, const CFArrayCallBacks
*cbs
, CFIndex entries
, va_list args
)
634 CFMutableArrayRef array
= CFArrayCreateMutable(allocator
, entries
, cbs
);
638 for (CFIndex currentValue
= 0; currentValue
< entries
; ++currentValue
) {
639 const void * value
= va_arg(args
, const void *);
643 CFArrayAppendValue(array
, value
);
646 CFArrayRef constArray
= CFArrayCreateCopy(allocator
, array
);
651 static inline CFArrayRef
CFArrayCreateForVC(CFAllocatorRef allocator
, const CFArrayCallBacks
*cbs
, va_list args
)
654 va_copy(count
, args
);
657 while (NULL
!= va_arg(count
, void*)) {
661 return CFArrayCreateCountedForVC(allocator
, cbs
, entries
, args
);
667 // MARK: CFArray of CFTypes support
670 static inline CFMutableArrayRef
CFArrayCreateMutableForCFTypesWithCapacity(CFAllocatorRef allocator
, CFIndex capacity
)
672 return CFArrayCreateMutable(allocator
, capacity
, &kCFTypeArrayCallBacks
);
675 static inline CFMutableArrayRef SECWRAPPER_SENTINEL
CFArrayCreateMutableForCFTypesWith(CFAllocatorRef allocator
, ...)
679 va_start(args
, allocator
);
680 CFIndex capacity
= 0;
681 void* object
= va_arg(args
, void*);
683 while (object
!= NULL
) {
684 object
= va_arg(args
, void*);
690 CFMutableArrayRef result
= CFArrayCreateMutableForCFTypesWithCapacity(allocator
, capacity
);
692 va_start(args
, allocator
);
693 object
= va_arg(args
, void*);
695 while (object
!= NULL
) {
696 CFArrayAppendValue(result
, object
);
697 object
= va_arg(args
, void*);
705 static inline CFMutableArrayRef
CFArrayCreateMutableForCFTypes(CFAllocatorRef allocator
)
707 return CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
710 static inline CFArrayRef SECWRAPPER_SENTINEL
CFArrayCreateForCFTypes(CFAllocatorRef allocator
, ...)
713 va_start(args
, allocator
);
714 CFArrayRef allocatedArray
= CFArrayCreateForVC(allocator
, &kCFTypeArrayCallBacks
, args
);
716 return allocatedArray
;
720 static inline CFArrayRef
CFArrayCreateCountedForCFTypes(CFAllocatorRef allocator
, CFIndex entries
, ...)
723 va_start(args
, entries
);
724 CFArrayRef allocatedArray
= CFArrayCreateCountedForVC(allocator
, &kCFTypeArrayCallBacks
, entries
, args
);
726 return allocatedArray
;
729 static inline CFArrayRef
CFArrayCreateCountedForCFTypesV(CFAllocatorRef allocator
, CFIndex entries
, va_list args
)
731 return CFArrayCreateCountedForVC(allocator
, &kCFTypeArrayCallBacks
, entries
, args
);
735 // MARK: CFDictionary of CFTypes helpers
738 static void CFDictionarySetIfNonNull(CFMutableDictionaryRef dictionary
, const void *key
, const void *value
) {
740 CFDictionarySetValue(dictionary
, key
, value
);
744 static inline CFDictionaryRef
CFDictionaryCreateCountedForCFTypesV(CFAllocatorRef allocator
, CFIndex entries
, va_list args
)
746 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(allocator
, entries
,
747 &kCFTypeDictionaryKeyCallBacks
,
748 &kCFTypeDictionaryValueCallBacks
);
749 if (dictionary
== NULL
) {
753 for(CFIndex currentValue
= 0; currentValue
< entries
; ++currentValue
) {
754 CFTypeRef key
= va_arg(args
, CFTypeRef
);
755 CFTypeRef value
= va_arg(args
, CFTypeRef
);
759 CFDictionarySetValue(dictionary
, key
, value
);
762 CFDictionaryRef constDictionary
= CFDictionaryCreateCopy(allocator
, dictionary
);
763 CFRelease(dictionary
);
764 return constDictionary
;
767 static inline CFDictionaryRef SECWRAPPER_SENTINEL
CFDictionaryCreateForCFTypes(CFAllocatorRef allocator
, ...)
770 va_start(args
, allocator
);
773 while (NULL
!= va_arg(args
, void*)) {
775 (void) va_arg(args
, void*);
780 va_start(args
, allocator
);
781 CFDictionaryRef allocatedDictionary
= CFDictionaryCreateCountedForCFTypesV(allocator
, entries
, args
);
783 return allocatedDictionary
;
786 static inline CFDictionaryRef
CFDictionaryCreateCountedForCFTypes(CFAllocatorRef allocator
, CFIndex entries
, ...)
789 va_start(args
, entries
);
790 CFDictionaryRef allocatedDictionary
= CFDictionaryCreateCountedForCFTypesV(allocator
, entries
, args
);
793 return allocatedDictionary
;
796 static inline CFMutableDictionaryRef
CFDictionaryCreateMutableForCFTypes(CFAllocatorRef allocator
)
798 return CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
801 static inline CFMutableDictionaryRef SECWRAPPER_SENTINEL
CFDictionaryCreateMutableForCFTypesWith(CFAllocatorRef allocator
, ...)
803 CFMutableDictionaryRef result
= CFDictionaryCreateMutableForCFTypes(allocator
);
806 va_start(args
, allocator
);
808 void* key
= va_arg(args
, void*);
810 while (key
!= NULL
) {
811 CFDictionarySetValue(result
, key
, va_arg(args
, void*));
812 key
= va_arg(args
, void*);
818 static inline CFMutableDictionaryRef SECWRAPPER_SENTINEL
CFDictionaryCreateMutableForCFTypesWithSafe(CFAllocatorRef allocator
, ...)
820 CFMutableDictionaryRef result
= CFDictionaryCreateMutableForCFTypes(allocator
);
823 va_start(args
, allocator
);
825 void* key
= va_arg(args
, void*);
827 while (key
!= NULL
) {
828 CFDictionarySetIfNonNull(result
, key
, va_arg(args
, void*));
829 key
= va_arg(args
, void*);
836 // MARK: CFSet Helpers
839 static inline CFMutableSetRef
CFSetCreateMutableForCFTypes(CFAllocatorRef allocator
)
841 return CFSetCreateMutable(allocator
, 0, &kCFTypeSetCallBacks
);
844 static inline bool CFSetIsEmpty(CFSetRef set
) {
845 return CFSetGetCount(set
) == 0;
848 static inline void CFSetForEach(CFSetRef set
, void (^operation
)(const void *value
)) {
849 CFSetApplyFunction(set
, apply_block_1
, (__SECBRIDGE
void *)operation
);
852 static inline void CFSetUnion(CFMutableSetRef set
, CFSetRef unionWith
) {
853 CFSetForEach(unionWith
, ^(const void *value
) {
854 CFSetSetValue(set
, value
);
858 static inline void CFSetSubtract(CFMutableSetRef set
, CFSetRef subtract
) {
859 CFSetForEach(subtract
, ^(const void *value
) {
860 CFSetRemoveValue(set
, value
);
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
)) {
875 static inline void CFSetSetValues(CFMutableSetRef set
, CFArrayRef valuesToSet
) {
876 CFArrayForEach(valuesToSet
, ^(const void *value
) {
877 CFSetSetValue(set
, value
);
881 static inline CFMutableArrayRef
CFSetCopyValues(CFSetRef set
) {
882 CFMutableArrayRef values
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
884 CFSetForEach(set
, ^(const void *value
) {
885 CFArrayAppendValue(values
, value
);
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
);
898 return intersectionIsEmpty
;
901 static inline bool CFSetIntersects(CFSetRef set1
, CFSetRef set2
) {
902 return !CFSetIntersectionIsEmpty(set1
, set2
);
905 static inline CFMutableSetRef
CFSetCreateIntersection(CFAllocatorRef allocator
, CFSetRef a
, CFSetRef b
) {
906 CFMutableSetRef result
= CFSetCreateMutableCopy(allocator
, 0, a
);
908 CFSetRemoveAllValues(result
);
909 CFSetForEach(a
, ^(const void *value
) {
910 if (CFSetContainsValue(b
, value
)) {
911 CFSetAddValue(result
, value
);
918 static inline CFSetRef
CFSetCreateCopyOfArrayForCFTypes(CFArrayRef array
) {
919 CFIndex count
= CFArrayGetCount(array
);
920 if (SIZE_MAX
/sizeof(const void *) < (size_t)count
) {
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
);
930 static inline void CFSetTransferObject(CFTypeRef object
, CFMutableSetRef from
, CFMutableSetRef to
) {
931 CFSetAddValue(to
, object
);
932 CFSetRemoveValue(from
, object
);
936 // MARK: CFStringXxx Helpers
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
));
944 // MARK: CFDictionary Helpers
947 static inline void CFDictionaryForEach(CFDictionaryRef dictionary
, void (^operation
)(const void *key
, const void *value
)) {
948 CFDictionaryApplyFunction(dictionary
, apply_block_2
, (__SECBRIDGE
void *)operation
);
951 CFStringRef
CFDictionaryCopyCompactDescription(CFDictionaryRef dictionary
);
952 CFStringRef
CFDictionaryCopySuperCompactDescription(CFDictionaryRef dictionary
);
955 // MARK: CFCalendar helpers
958 void SecCFCalendarDoWithZuluCalendar(void(^action
)(CFCalendarRef zuluCalendar
));
961 // MARK: CFAbsoluteTime helpers
964 static inline CFAbsoluteTime
CFAbsoluteTimeForCalendarMoment(CFCalendarRef cal
, int year
, int month
, int day
, int hour
, int minute
, int second
) {
966 CFCalendarComposeAbsoluteTime(cal
, &at
, "yMdHms", year
, month
, day
, hour
, minute
, second
);
970 static inline CFAbsoluteTime
CFAbsoluteTimeForCalendarDay(CFCalendarRef cal
, int year
, int month
, int day
) {
972 CFCalendarComposeAbsoluteTime(cal
, &at
, "yMd", year
, month
, day
);
976 static inline CFAbsoluteTime
CFAbsoluteTimeForGregorianMoment(CFTimeZoneRef tz
, int year
, int month
, int day
, int hour
, int minute
, int second
)
978 CFCalendarRef cal
= CFCalendarCreateWithIdentifier(NULL
, kCFGregorianCalendar
);
979 CFCalendarSetTimeZone(cal
, tz
);
980 CFAbsoluteTime at
= CFAbsoluteTimeForCalendarMoment(cal
, year
, month
, day
, hour
, minute
, second
);
985 static inline CFAbsoluteTime
CFAbsoluteTimeForGregorianDay(CFTimeZoneRef tz
, int year
, int month
, int day
)
987 CFCalendarRef cal
= CFCalendarCreateWithIdentifier(NULL
, kCFGregorianCalendar
);
988 CFCalendarSetTimeZone(cal
, tz
);
989 CFAbsoluteTime at
= CFAbsoluteTimeForCalendarDay(cal
, year
, month
, day
);
994 static inline CFAbsoluteTime
CFAbsoluteTimeForGregorianZuluMoment(int year
, int month
, int day
, int hour
, int minute
, int second
)
996 __block CFAbsoluteTime result
= 0.0;
997 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) {
998 result
= CFAbsoluteTimeForCalendarMoment(zuluCalendar
, year
, month
, day
, hour
, minute
, second
);
1004 static inline CFAbsoluteTime
CFAbsoluteTimeForGregorianZuluDay(int year
, int month
, int day
)
1006 __block CFAbsoluteTime result
= 0.0;
1007 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) {
1008 result
= CFAbsoluteTimeForCalendarDay(zuluCalendar
, year
, month
, day
);
1016 // MARK: CFDate Helpers
1019 static inline CFDateRef
CFDateCreateForGregorianMoment(CFAllocatorRef allocator
, CFTimeZoneRef tz
, int year
, int month
, int day
, int hour
, int minute
, int second
)
1021 return CFDateCreate(allocator
, CFAbsoluteTimeForGregorianMoment(tz
, year
, month
, day
, hour
, minute
, second
));
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
)
1027 return CFDateCreate(allocator
, CFAbsoluteTimeForGregorianDay(tz
, year
, month
, day
));
1030 static inline CFDateRef
CFDateCreateForGregorianZuluMoment(CFAllocatorRef allocator
, int year
, int month
, int day
, int hour
, int minute
, int second
)
1032 return CFDateCreate(allocator
, CFAbsoluteTimeForGregorianZuluMoment(year
, month
, day
, hour
, minute
, second
));
1035 static inline CFDateRef
CFDateCreateForGregorianZuluDay(CFAllocatorRef allocator
, int year
, int month
, int day
)
1037 return CFDateCreate(allocator
, CFAbsoluteTimeForGregorianZuluDay(year
, month
, day
));
1041 // MARK: PropertyList Helpers
1045 // Crazy reading and writing stuff
1048 static inline void CFPropertyListWriteToFile(CFPropertyListRef plist
, CFURLRef file
)
1050 CFWriteStreamRef writeStream
= CFWriteStreamCreateWithFile(kCFAllocatorDefault
, file
);
1051 CFErrorRef error
= NULL
;
1053 CFWriteStreamOpen(writeStream
);
1054 CFPropertyListWrite(plist
, writeStream
, kCFPropertyListBinaryFormat_v1_0
, 0, &error
);
1056 secerror("Can't write plist: %@", error
);
1058 CFReleaseNull(error
);
1059 CFReleaseNull(writeStream
);
1062 static inline CF_RETURNS_RETAINED CFPropertyListRef
CFPropertyListReadFromFile(CFURLRef file
)
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
);
1072 if (CFReadStreamOpen(readStream
)) {
1073 CFPropertyListFormat format
;
1074 result
= CFPropertyListCreateWithStream(kCFAllocatorDefault
, readStream
, 0, kCFPropertyListMutableContainers
, &format
, &error
);
1076 secerror("read plist from %@: %@", file
, error
);
1079 CFRelease(readStream
);
1082 CFReleaseNull(error
);
1089 #endif /* _SECCFWRAPPERS_H_ */