2 * Copyright (c) 2012,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <utilities/SecCFWrappers.h>
26 #include <utilities/SecBuffer.h>
27 #include <CommonCrypto/CommonCryptor.h>
28 #include <CommonCrypto/CommonRandom.h>
30 CFStringRef kSecDebugFormatOption
= CFSTR("debug");
33 // Global singleton CopyDebugDescription format dictionary getter.
35 CFGiblisGetSingleton(CFDictionaryRef
, SecGetDebugDescriptionFormatOptions
, formatOption
, ^{
36 const void *k
[] = { kSecDebugFormatOption
};
37 const void *v
[] = { kCFBooleanTrue
};
38 *formatOption
= CFDictionaryCreate(kCFAllocatorDefault
, k
, v
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
43 // Global sigleton Zulu time. Must be serialized since it is really a CFMutableCalendarRef
44 // <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
46 static dispatch_queue_t fqueue_cf
;
47 static CFCalendarRef sZuluCalendar
= NULL
;
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
);
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
);
69 void SecCFCalendarDoWithZuluCalendar(void(^action
)(CFCalendarRef zuluCalendar
)) {
70 dispatch_sync(SecCFCalendarGetZuluQueue(), ^{
71 action(SecCFCalendarGetZulu());
75 void CFStringPerformWithCStringAndLength(CFStringRef inStr
, void(^operation
)(const char *utf8String
, size_t utf8Length
)) {
76 const char *cstr
= CFStringGetCStringPtr(inStr
, kCFStringEncodingUTF8
);
78 operation(cstr
, strlen(cstr
));
80 CFIndex neededLen
= 0;
81 CFRange range
= { 0, CFStringGetLength(inStr
) };
83 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
84 0, FALSE
, NULL
, 0, &neededLen
);
86 // + 1 bytes for the '\0' we're adding.
87 PerformWithBuffer(neededLen
+ 1, ^(size_t size
, uint8_t *buf
) {
90 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
91 0, FALSE
, (UInt8
*)buf
, neededLen
, &usedLen
);
92 assert(usedLen
== neededLen
);
94 operation((const char *) buf
, (size_t)usedLen
);
100 void CFStringPerformWithCString(CFStringRef inStr
, void(^operation
)(const char *utf8String
)) {
101 CFStringPerformWithCStringAndLength(inStr
, ^(const char *utf8String
, size_t utf8Length
) {
102 operation(utf8String
);
106 void CFStringPerformWithUTF8CFData(CFStringRef inStr
, void (^operation
)(CFDataRef stringAsData
)) {
107 CFIndex neededLen
= 0;
108 CFRange range
= { 0, CFStringGetLength(inStr
) };
110 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
111 0, FALSE
, NULL
, 0, &neededLen
);
113 CFMutableDataRef data
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, neededLen
);
116 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
117 0, FALSE
, CFDataGetMutableBytePtr(data
), neededLen
, &usedLen
);
118 assert(usedLen
== neededLen
);
126 CFStringRef
CFDictionaryCopyCompactDescription(CFDictionaryRef dictionary
) {
127 CFStringRef result
= NULL
;
129 CFMutableStringRef compactDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("{"));
130 __block CFStringRef separator
= CFSTR("");
132 CFDictionaryForEach(dictionary
, ^(const void *key
, const void *value
) {
133 CFMutableStringRef valueDescription
= NULL
;
135 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("0x"));
136 CFStringAppendHexData(valueDescription
, (CFDataRef
) value
);
138 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("%@%@:%@"), separator
, key
, valueDescription
? valueDescription
: value
);
139 separator
= CFSTR(", ");
140 CFReleaseNull(valueDescription
);
143 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("}"));
145 result
= compactDescription
;
147 result
= CFCopyDescription(kCFNull
);
153 CFStringRef
CFDictionaryCopySuperCompactDescription(CFDictionaryRef dictionary
) {
154 CFStringRef result
= NULL
;
156 CFMutableStringRef compactDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("{"));
157 __block CFStringRef separator
= CFSTR("");
159 CFDictionaryForEach(dictionary
, ^(const void *key
, const void *value
) {
160 CFMutableStringRef valueDescription
= NULL
;
163 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("0x"));
164 CFStringAppendHexData(valueDescription
, (CFDataRef
) value
);
165 CFStringDelete(valueDescription
, CFRangeMake(0, 5));
167 else if(isString(value
)){
168 CFStringRef stringValue
= NULL
;
169 if(CFStringGetLength(value
) < 6)
170 stringValue
= CFStringCreateCopy(kCFAllocatorDefault
, value
);
172 stringValue
= CFStringCreateWithSubstring(kCFAllocatorDefault
, value
, CFRangeMake(0, 6));
173 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(stringValue
), stringValue
);
174 CFReleaseNull(stringValue
);
176 else if(isNumber(value
)){
177 CFStringRef stringValue
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@"), (CFNumberRef
)value
);
178 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(stringValue
), stringValue
);
179 CFReleaseNull(stringValue
);
182 UniChar firstCharOfKey
= CFStringGetCharacterAtIndex(key
, 0);
183 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("%c:%@ "), firstCharOfKey
, valueDescription
);
184 separator
= CFSTR(", ");
185 CFReleaseNull(valueDescription
);
188 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("}"));
190 result
= compactDescription
;
192 result
= CFCopyDescription(kCFNull
);
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
);
209 CFGiblisGetSingleton(CFDateFormatterRef
, GetShortDateFormatter
, sDateFormatter
, ^{
210 CFLocaleRef locale
= CFLocaleCopyCurrent();
211 *sDateFormatter
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
);
213 CFDateFormatterSetFormat(*sDateFormatter
, CFSTR("yyyy-MM-dd HH:mm"));
214 CFReleaseNull(locale
);
217 CFGiblisGetSingleton(dispatch_queue_t
, GetShortDateFormatterQueue
, sDateFormatQueue
, ^{
218 *sDateFormatQueue
= dispatch_queue_create("Date Formatting", DISPATCH_QUEUE_SERIAL
);
222 // MARK: time formatters
225 static void withShortDateFormatter(void (^action
)(CFDateFormatterRef formatter
)) {
226 dispatch_sync(GetShortDateFormatterQueue(), ^{
227 action(GetShortDateFormatter());
231 void withStringOfAbsoluteTime(CFAbsoluteTime at
, void (^action
)(CFStringRef decription
)) {
232 __block CFStringRef formattedString
= NULL
;
234 withShortDateFormatter(^(CFDateFormatterRef formatter
) {
235 formattedString
= CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault
, formatter
, at
);
237 action(formattedString
);
239 CFReleaseNull(formattedString
);
244 // MARK: Custom Sensitive Data Allocator
246 #include <malloc/malloc.h>
247 static CFStringRef
SecCFAllocatorCopyDescription(const void *info
) {
248 return CFSTR("Custom CFAllocator for sensitive data");
251 // primary goal of this allocator is to clear memory when it is deallocated
252 static void SecCFAllocatorDeallocate(void *ptr
, void *info
) {
254 size_t sz
= malloc_size(ptr
);
255 if(sz
) cc_clear(sz
, ptr
);
257 CFAllocatorDeallocate(NULL
, ptr
);
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
);
267 CFAllocatorContext ctx
= {0,
271 SecCFAllocatorCopyDescription
,
273 defaultCtx
.reallocate
,
274 SecCFAllocatorDeallocate
,
275 defaultCtx
.preferredSize
};
277 sAllocator
= CFAllocatorCreate(NULL
, &ctx
);