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