]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/SecCFWrappers.c
Security-59306.11.20.tar.gz
[apple/security.git] / OSX / utilities / SecCFWrappers.c
1 /*
2 * Copyright (c) 2012,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 #include <utilities/SecCFWrappers.h>
26 #include <utilities/SecBuffer.h>
27 #include <CommonCrypto/CommonCryptor.h>
28 #include <CommonCrypto/CommonRandom.h>
29
30 CFStringRef kSecDebugFormatOption = CFSTR("debug");
31
32 //
33 // Global singleton CopyDebugDescription format dictionary getter.
34 //
35 CFGiblisGetSingleton(CFDictionaryRef, SecGetDebugDescriptionFormatOptions, formatOption, ^{
36 const void *k[] = { kSecDebugFormatOption };
37 const void *v[] = { kCFBooleanTrue };
38 *formatOption = CFDictionaryCreate(kCFAllocatorDefault, k, v, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
39 })
40
41 //
42 // Smart comparator for strings that matches sorting functions
43 //
44
45 CFComparisonResult CFStringCompareSafe(const void *val1, const void *val2, void *context) {
46 if (!isString(val1))
47 return kCFCompareLessThan;
48 if (!isString(val2))
49 return kCFCompareGreaterThan;
50
51 return CFStringCompare(val1, val2, 0);
52 }
53
54 void CFStringArrayPerformWithDelimiterWithDescription(CFArrayRef strings, CFStringRef start, CFStringRef end, void (^action)(CFStringRef description)) {
55 if(!strings) {
56 action(CFSTR("null"));
57 } else {
58 __block CFMutableStringRef description = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, start);
59 __block CFStringRef separator = CFSTR("");
60
61 CFArrayForEach(strings, ^(const void *value) {
62 CFStringAppendFormat(description, NULL, CFSTR("%@%@"), separator, value);
63 separator = CFSTR(", ");
64 });
65
66 CFStringAppend(description, end);
67
68 action(description);
69
70 CFReleaseNull(description);
71 }
72 }
73
74
75 void CFStringArrayPerformWithDescription(CFArrayRef strings, void (^action)(CFStringRef description)) {
76 CFStringArrayPerformWithDelimiterWithDescription(strings, CFSTR("["), CFSTR("]"), action);
77 }
78
79 static void
80 appendDescriptionToArray(const void *value, void *context)
81 {
82 CFTypeRef obj = (CFTypeRef)value;
83 CFMutableArrayRef array = (CFMutableArrayRef)context;
84 CFStringRef desc;
85
86 if (CFGetTypeID(obj) == CFStringGetTypeID()) {
87 CFArrayAppendValue(array, obj);
88 } else {
89 desc = CFCopyDescription(obj);
90 if (desc != NULL) {
91 CFArrayAppendValue(array, desc);
92 CFRelease(desc);
93 } else {
94 CFArrayAppendValue(array, CFSTR("null"));
95 }
96 }
97 }
98
99 void CFStringSetPerformWithDescription(CFSetRef set, void (^action)(CFStringRef description)) {
100 if(!set) {
101 action(CFSTR("null"));
102 } else {
103 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, CFSetGetCount(set), &kCFTypeArrayCallBacks);
104
105 CFSetApplyFunction(set, appendDescriptionToArray, keys);
106
107 CFArraySortValues(keys, CFRangeMake(0, CFArrayGetCount(keys)), (CFComparatorFunction)&CFStringCompare, NULL);
108
109 CFStringArrayPerformWithDelimiterWithDescription(keys, CFSTR("{("), CFSTR(")}"), action);
110
111 CFReleaseNull(keys);
112 }
113 }
114
115 //
116 // Global sigleton Zulu time. Must be serialized since it is really a CFMutableCalendarRef
117 // <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
118 //
119 static dispatch_queue_t fqueue_cf;
120 static CFCalendarRef sZuluCalendar = NULL;
121
122 static dispatch_queue_t SecCFCalendarGetZuluQueue() {
123 static dispatch_once_t onceToken;
124 dispatch_once(&onceToken, ^{
125 fqueue_cf = dispatch_queue_create("ZuluCalendar", DISPATCH_QUEUE_SERIAL);
126 });
127 return fqueue_cf;
128 }
129
130 static CFCalendarRef SecCFCalendarGetZulu() {
131 static dispatch_once_t onceToken;
132 dispatch_once(&onceToken, ^{
133 sZuluCalendar = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar);
134 CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0);
135 CFCalendarSetTimeZone(sZuluCalendar, tz);
136 if (tz)
137 CFRelease(tz);
138 });
139 return sZuluCalendar;
140 }
141
142 void SecCFCalendarDoWithZuluCalendar(void(^action)(CFCalendarRef zuluCalendar)) {
143 dispatch_sync(SecCFCalendarGetZuluQueue(), ^{
144 action(SecCFCalendarGetZulu());
145 });
146 }
147
148 void CFStringPerformWithCStringAndLength(CFStringRef inStr, void(^operation)(const char *utf8String, size_t utf8Length)) {
149 const char *cstr = CFStringGetCStringPtr(inStr, kCFStringEncodingUTF8);
150 if (cstr) {
151 operation(cstr, strlen(cstr));
152 } else {
153 CFIndex neededLen = 0;
154 CFRange range = { 0, CFStringGetLength(inStr) };
155
156 CFStringGetBytes(inStr, range, kCFStringEncodingUTF8,
157 0, FALSE, NULL, 0, &neededLen);
158
159 // + 1 bytes for the '\0' we're adding.
160 PerformWithBuffer(neededLen + 1, ^(size_t size, uint8_t *buf) {
161 if (buf) {
162 CFIndex usedLen;
163 CFStringGetBytes(inStr, range, kCFStringEncodingUTF8,
164 0, FALSE, (UInt8 *)buf, neededLen, &usedLen);
165 assert(usedLen == neededLen);
166 buf[usedLen] = 0;
167 operation((const char *) buf, (size_t)usedLen);
168 }
169 });
170 }
171 }
172
173 void CFStringPerformWithCString(CFStringRef inStr, void(^operation)(const char *utf8String)) {
174 CFStringPerformWithCStringAndLength(inStr, ^(const char *utf8String, size_t utf8Length) {
175 operation(utf8String);
176 });
177 }
178
179 void CFStringPerformWithUTF8CFData(CFStringRef inStr, void (^operation)(CFDataRef stringAsData)) {
180 CFIndex neededLen = 0;
181 CFRange range = { 0, CFStringGetLength(inStr) };
182
183 CFStringGetBytes(inStr, range, kCFStringEncodingUTF8,
184 0, FALSE, NULL, 0, &neededLen);
185
186 CFMutableDataRef data = CFDataCreateMutableWithScratch(kCFAllocatorDefault, neededLen);
187
188 CFIndex usedLen;
189 CFStringGetBytes(inStr, range, kCFStringEncodingUTF8,
190 0, FALSE, CFDataGetMutableBytePtr(data), neededLen, &usedLen);
191 assert(usedLen == neededLen);
192
193 operation(data);
194
195 CFReleaseNull(data);
196 }
197
198
199 CFStringRef CFDictionaryCopyCompactDescription(CFDictionaryRef dictionary) {
200 CFStringRef result = NULL;
201 if (dictionary) {
202 CFMutableStringRef compactDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("{"));
203 __block CFStringRef separator = CFSTR("");
204
205 CFDictionaryForEach(dictionary, ^(const void *key, const void *value) {
206 CFMutableStringRef valueDescription = NULL;
207 if (isData(value)) {
208 valueDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("0x"));
209 CFStringAppendHexData(valueDescription, (CFDataRef) value);
210 }
211 CFStringAppendFormat(compactDescription, NULL, CFSTR("%@%@:%@"), separator, key, valueDescription ? valueDescription : value);
212 separator = CFSTR(", ");
213 CFReleaseNull(valueDescription);
214 });
215
216 CFStringAppendFormat(compactDescription, NULL, CFSTR("}"));
217
218 result = compactDescription;
219 } else {
220 result = CFCopyDescription(kCFNull);
221 }
222
223 return result;
224 }
225
226 CFStringRef CFDictionaryCopySuperCompactDescription(CFDictionaryRef dictionary) {
227 CFStringRef result = NULL;
228 if (dictionary) {
229 CFMutableStringRef compactDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("{"));
230 __block CFStringRef separator = CFSTR("");
231
232 CFDictionaryForEach(dictionary, ^(const void *key, const void *value) {
233 CFMutableStringRef valueDescription = NULL;
234
235 if (isData(value)) {
236 valueDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("0x"));
237 CFStringAppendHexData(valueDescription, (CFDataRef) value);
238 CFStringDelete(valueDescription, CFRangeMake(0, 5));
239 }
240 else if(isString(value)){
241 CFStringRef stringValue = NULL;
242 if(CFStringGetLength(value) < 6)
243 stringValue = CFStringCreateCopy(kCFAllocatorDefault, value);
244 else
245 stringValue = CFStringCreateWithSubstring(kCFAllocatorDefault, value, CFRangeMake(0, 6));
246 valueDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, CFStringGetLength(stringValue), stringValue);
247 CFReleaseNull(stringValue);
248 }
249 else if(isNumber(value)){
250 CFStringRef stringValue = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), (CFNumberRef)value);
251 valueDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, CFStringGetLength(stringValue), stringValue);
252 CFReleaseNull(stringValue);
253 }
254
255 UniChar firstCharOfKey = CFStringGetCharacterAtIndex(key, 0);
256 CFStringAppendFormat(compactDescription, NULL, CFSTR("%c:%@ "), firstCharOfKey, valueDescription);
257 separator = CFSTR(", ");
258 CFReleaseNull(valueDescription);
259 });
260
261 CFStringAppendFormat(compactDescription, NULL, CFSTR("}"));
262
263 result = compactDescription;
264 } else {
265 result = CFCopyDescription(kCFNull);
266 }
267
268 return result;
269 }
270
271
272 CFDataRef CFDataCreateWithRandomBytes(size_t len) {
273 __block CFDataRef retval = NULL;
274 PerformWithBufferAndClear(len, ^(size_t size, uint8_t *buffer) {
275 CCRandomGenerateBytes(buffer, size);
276 retval = CFDataCreate(NULL, buffer, size);
277 });
278 return retval;
279 }
280
281 CFDataRef CFDataCreateWithInitializer(CFAllocatorRef allocator, CFIndex size, bool (^operation)(size_t size, uint8_t *buffer)) {
282 __block CFMutableDataRef result = NULL;
283 if(!size) return NULL;
284 if((result = CFDataCreateMutableWithScratch(allocator, size)) == NULL) return NULL;
285 if (!operation(size, CFDataGetMutableBytePtr(result))) CFReleaseNull(result);
286 return result;
287 }
288
289
290
291 CFGiblisGetSingleton(CFDateFormatterRef, GetShortDateFormatter, sDateFormatter, ^{
292 CFLocaleRef locale = CFLocaleCopyCurrent();
293 *sDateFormatter = CFDateFormatterCreate(kCFAllocatorDefault, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle);
294
295 CFDateFormatterSetFormat(*sDateFormatter, CFSTR("yyyy-MM-dd HH:mm"));
296 CFReleaseNull(locale);
297 })
298
299 CFGiblisGetSingleton(dispatch_queue_t, GetShortDateFormatterQueue, sDateFormatQueue, ^{
300 *sDateFormatQueue = dispatch_queue_create("Date Formatting", DISPATCH_QUEUE_SERIAL);
301 })
302
303 //
304 // MARK: time formatters
305 //
306
307 static void withShortDateFormatter(void (^action)(CFDateFormatterRef formatter)) {
308 dispatch_sync(GetShortDateFormatterQueue(), ^{
309 action(GetShortDateFormatter());
310 });
311 }
312
313 void withStringOfAbsoluteTime(CFAbsoluteTime at, void (^action)(CFStringRef decription)) {
314 __block CFStringRef formattedString = NULL;
315
316 withShortDateFormatter(^(CFDateFormatterRef formatter) {
317 formattedString = CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, formatter, at);
318 });
319 action(formattedString);
320
321 CFReleaseNull(formattedString);
322 }