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