]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/src/SecCFWrappers.c
Security-57337.50.23.tar.gz
[apple/security.git] / OSX / utilities / src / 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 //
43 // Global sigleton Zulu time. Must be serialized since it is really a CFMutableCalendarRef
44 // <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
45 //
46 static dispatch_queue_t fqueue_cf;
47 static CFCalendarRef sZuluCalendar = NULL;
48
49 static dispatch_queue_t SecCFCalendarGetZuluQueue() {
50 static dispatch_once_t onceToken;
51 dispatch_once(&onceToken, ^{
52 fqueue_cf = dispatch_queue_create("ZuluCalendar", DISPATCH_QUEUE_SERIAL);
53 });
54 return fqueue_cf;
55 }
56
57 static CFCalendarRef SecCFCalendarGetZulu() {
58 static dispatch_once_t onceToken;
59 dispatch_once(&onceToken, ^{
60 sZuluCalendar = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar);
61 CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0);
62 CFCalendarSetTimeZone(sZuluCalendar, tz);
63 if (tz)
64 CFRelease(tz);
65 });
66 return sZuluCalendar;
67 }
68
69 void SecCFCalendarDoWithZuluCalendar(void(^action)(CFCalendarRef zuluCalendar)) {
70 dispatch_sync(SecCFCalendarGetZuluQueue(), ^{
71 action(SecCFCalendarGetZulu());
72 });
73 }
74
75 void CFStringPerformWithCStringAndLength(CFStringRef inStr, void(^operation)(const char *utf8String, size_t utf8Length)) {
76 const char *cstr = CFStringGetCStringPtr(inStr, kCFStringEncodingUTF8);
77 if (cstr) {
78 operation(cstr, strlen(cstr));
79 } else {
80 CFIndex neededLen = 0;
81 CFRange range = { 0, CFStringGetLength(inStr) };
82
83 CFStringGetBytes(inStr, range, kCFStringEncodingUTF8,
84 0, FALSE, NULL, 0, &neededLen);
85
86 // + 1 bytes for the '\0' we're adding.
87 PerformWithBuffer(neededLen + 1, ^(size_t size, uint8_t *buf) {
88 if (buf) {
89 CFIndex usedLen;
90 CFStringGetBytes(inStr, range, kCFStringEncodingUTF8,
91 0, FALSE, (UInt8 *)buf, neededLen, &usedLen);
92 assert(usedLen == neededLen);
93 buf[usedLen] = 0;
94 operation((const char *) buf, (size_t)usedLen);
95 }
96 });
97 }
98 }
99
100 void CFStringPerformWithCString(CFStringRef inStr, void(^operation)(const char *utf8String)) {
101 CFStringPerformWithCStringAndLength(inStr, ^(const char *utf8String, size_t utf8Length) {
102 operation(utf8String);
103 });
104 }
105
106 void CFStringPerformWithUTF8CFData(CFStringRef inStr, void (^operation)(CFDataRef stringAsData)) {
107 CFIndex neededLen = 0;
108 CFRange range = { 0, CFStringGetLength(inStr) };
109
110 CFStringGetBytes(inStr, range, kCFStringEncodingUTF8,
111 0, FALSE, NULL, 0, &neededLen);
112
113 CFMutableDataRef data = CFDataCreateMutableWithScratch(kCFAllocatorDefault, neededLen);
114
115 CFIndex usedLen;
116 CFStringGetBytes(inStr, range, kCFStringEncodingUTF8,
117 0, FALSE, CFDataGetMutableBytePtr(data), neededLen, &usedLen);
118 assert(usedLen == neededLen);
119
120 operation(data);
121
122 CFReleaseNull(data);
123 }
124
125
126 CFStringRef CFDictionaryCopyCompactDescription(CFDictionaryRef dictionary) {
127 CFStringRef result = NULL;
128 if (dictionary) {
129 CFMutableStringRef compactDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("{"));
130 __block CFStringRef separator = CFSTR("");
131
132 CFDictionaryForEach(dictionary, ^(const void *key, const void *value) {
133 CFMutableStringRef valueDescription = NULL;
134 if (isData(value)) {
135 valueDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("0x"));
136 CFStringAppendHexData(valueDescription, (CFDataRef) value);
137 }
138 CFStringAppendFormat(compactDescription, NULL, CFSTR("%@%@:%@"), separator, key, valueDescription ? valueDescription : value);
139 separator = CFSTR(", ");
140 CFReleaseNull(valueDescription);
141 });
142
143 CFStringAppendFormat(compactDescription, NULL, CFSTR("}"));
144
145 result = compactDescription;
146 } else {
147 result = CFCopyDescription(kCFNull);
148 }
149
150 return result;
151 }
152
153 CFStringRef CFDictionaryCopySuperCompactDescription(CFDictionaryRef dictionary) {
154 CFStringRef result = NULL;
155 if (dictionary) {
156 CFMutableStringRef compactDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("{"));
157 __block CFStringRef separator = CFSTR("");
158
159 CFDictionaryForEach(dictionary, ^(const void *key, const void *value) {
160 CFMutableStringRef valueDescription = NULL;
161
162 if (isData(value)) {
163 valueDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("0x"));
164 CFStringAppendHexData(valueDescription, (CFDataRef) value);
165 CFStringDelete(valueDescription, CFRangeMake(0, 5));
166 }
167 else if(isString(value)){
168 CFStringRef stringValue = NULL;
169 if(CFStringGetLength(value) < 6)
170 stringValue = CFStringCreateCopy(kCFAllocatorDefault, value);
171 else
172 stringValue = CFStringCreateWithSubstring(kCFAllocatorDefault, value, CFRangeMake(0, 6));
173 valueDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, CFStringGetLength(stringValue), stringValue);
174 CFReleaseNull(stringValue);
175 }
176 else if(isNumber(value)){
177 CFStringRef stringValue = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), (CFNumberRef)value);
178 valueDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, CFStringGetLength(stringValue), stringValue);
179 CFReleaseNull(stringValue);
180 }
181
182 UniChar firstCharOfKey = CFStringGetCharacterAtIndex(key, 0);
183 CFStringAppendFormat(compactDescription, NULL, CFSTR("%c:%@ "), firstCharOfKey, valueDescription);
184 separator = CFSTR(", ");
185 CFReleaseNull(valueDescription);
186 });
187
188 CFStringAppendFormat(compactDescription, NULL, CFSTR("}"));
189
190 result = compactDescription;
191 } else {
192 result = CFCopyDescription(kCFNull);
193 }
194
195 return result;
196 }
197
198
199 CFDataRef CFDataCreateWithRandomBytes(size_t len) {
200 __block CFDataRef retval = NULL;
201 PerformWithBufferAndClear(len, ^(size_t size, uint8_t *buffer) {
202 CCRandomGenerateBytes(buffer, size);
203 retval = CFDataCreate(NULL, buffer, size);
204 });
205 return retval;
206 }
207
208
209 CFGiblisGetSingleton(CFDateFormatterRef, GetShortDateFormatter, sDateFormatter, ^{
210 CFLocaleRef locale = CFLocaleCopyCurrent();
211 *sDateFormatter = CFDateFormatterCreate(kCFAllocatorDefault, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle);
212
213 CFDateFormatterSetFormat(*sDateFormatter, CFSTR("yyyy-MM-dd HH:mm"));
214 CFReleaseNull(locale);
215 })
216
217 CFGiblisGetSingleton(dispatch_queue_t, GetShortDateFormatterQueue, sDateFormatQueue, ^{
218 *sDateFormatQueue = dispatch_queue_create("Date Formatting", DISPATCH_QUEUE_SERIAL);
219 })
220
221 //
222 // MARK: time formatters
223 //
224
225 static void withShortDateFormatter(void (^action)(CFDateFormatterRef formatter)) {
226 dispatch_sync(GetShortDateFormatterQueue(), ^{
227 action(GetShortDateFormatter());
228 });
229 }
230
231 void withStringOfAbsoluteTime(CFAbsoluteTime at, void (^action)(CFStringRef decription)) {
232 __block CFStringRef formattedString = NULL;
233
234 withShortDateFormatter(^(CFDateFormatterRef formatter) {
235 formattedString = CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, formatter, at);
236 });
237 action(formattedString);
238
239 CFReleaseNull(formattedString);
240 }
241
242
243 //
244 // MARK: Custom Sensitive Data Allocator
245 //
246 #include <malloc/malloc.h>
247 static CFStringRef SecCFAllocatorCopyDescription(const void *info) {
248 return CFSTR("Custom CFAllocator for sensitive data");
249 }
250
251 // primary goal of this allocator is to clear memory when it is deallocated
252 static void SecCFAllocatorDeallocate(void *ptr, void *info) {
253 if (!ptr) return;
254 size_t sz = malloc_size(ptr);
255 if(sz) cc_clear(sz, ptr);
256
257 CFAllocatorDeallocate(NULL, ptr);
258 }
259
260 CFAllocatorRef CFAllocatorSensitive(void) {
261 static dispatch_once_t sOnce = 0;
262 static CFAllocatorRef sAllocator = NULL;
263 dispatch_once(&sOnce, ^{
264 CFAllocatorContext defaultCtx;
265 CFAllocatorGetContext(NULL, &defaultCtx);
266
267 CFAllocatorContext ctx = {0,
268 defaultCtx.info,
269 defaultCtx.retain,
270 defaultCtx.release,
271 SecCFAllocatorCopyDescription,
272 defaultCtx.allocate,
273 defaultCtx.reallocate,
274 SecCFAllocatorDeallocate,
275 defaultCtx.preferredSize};
276
277 sAllocator = CFAllocatorCreate(NULL, &ctx);
278 });
279
280 return sAllocator;
281 }