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