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