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