]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/Regressions/su-16-cfdate-der.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / utilities / Regressions / su-16-cfdate-der.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/der_plist.h"
26 #include "utilities/der_plist_internal.h"
27 #include "utilities/der_date.h"
28
29 #include "utilities/SecCFRelease.h"
30 #include "utilities/array_size.h"
31 #include <utilities/SecCFWrappers.h>
32
33 #include <CoreFoundation/CoreFoundation.h>
34 #include <corecrypto/ccder.h>
35 #include <dispatch/dispatch.h>
36
37 #include "utilities_regressions.h"
38
39 #define kMaxResultSize 100
40
41 struct test_case {
42 CFAbsoluteTime value;
43 char *expected;
44 };
45
46 static struct test_case test_cases[] =
47 {
48 { .value = 0.0, .expected = "20010101000000Z", },
49 { .value = 1.0, .expected = "20010101000001Z", },
50 { .value = 0.1, .expected = "20010101000000.1Z", },
51 { .value = 0.0001, .expected = "20010101000000.0001Z", },
52 { .value = 128.0, .expected = "20010101000208Z", },
53 { .value = -1.0, .expected = "20001231235959Z", },
54 { .value = -0.9, .expected = "20001231235959.1Z", },
55 { .value = -129.0, .expected = "20001231235751Z", },
56 { .value = 1000.0, .expected = "20010101001640Z", },
57 { .value = 65280.0, .expected = "20010101180800Z", },
58 { .value = 41234576.0, .expected = "20020423060256Z", },
59 { .value = -412343576.0, .expected = "19871208120704Z", },
60 { .value = 381778873.238063, .expected = "20130205174113.238063Z", },
61 { .value = 381778873.638063, .expected = "20130205174113.638063Z", },
62 { .value = 1400603.141, .expected = "20010117050323.141Z", },
63 { .value = -412343576.238063, .expected = "19871208120703.761937Z", },
64 { .value = -412343576.638063, .expected = "19871208120703.361937Z", },
65 { .value = 5.000539014, .expected = "20010101000005.000539014Z", },
66 { .value = -5.00053901, .expected = "20001231235954.99946099Z", },
67 { .value = 0.000539014, .expected = "20010101000000.000539014Z", },
68 { .value = -0.00053901, .expected = "20001231235959.99946099Z", },
69 { .value = 11031400603.141, .expected = "23500729055643.141Z", }, // Michael's 400th birthday
70 // Pedantic tests within 1 second of the epoch.
71 { .value = 0.000100120234, .expected = "20010101000000.000100120234Z", },
72 { .value = 0.00000000000000000000000000000000000000000010012654182354326,
73 .expected = "20010101000000.00000000000000000000000000000000000000000010012654182354326Z", },
74 { .value = -0.00000000000000000000000000000000000000000010012654182354326,
75 .expected = "20001231235959.99999999999999999999999999999999999999999989987345817645674Z", },
76 { .value = 0.0001234522366234637, .expected = "20010101000000.0001234522366234637Z", },
77 };
78
79 static CFStringRef string_create_with_hex(const uint8_t* start, const uint8_t* end) {
80 CFMutableStringRef s = CFStringCreateMutable(NULL, 0);
81 CFStringAppendFormat(s, 0, CFSTR(".size = %" PRIdPTR ", .res = { "), (intptr_t)(end - start));
82 if (start)
83 while (start < end)
84 CFStringAppendFormat(s, 0, CFSTR("0x%02X, "), *start++);
85 CFStringAppend(s, CFSTR("},\n"));
86 return s;
87 }
88
89 static bool ok_der_date_is(int testnumber, const char *expected, const uint8_t *der, const uint8_t *der_end) {
90 size_t elen = strlen(expected);
91 size_t dlen;
92 const uint8_t *body = ccder_decode_tl(CCDER_GENERALIZED_TIME, &dlen, der, der_end);
93 if (!body) {
94 return fail("[%d] encoded date %@ expected %s not a generalized time", testnumber, string_create_with_hex(der, der_end), expected);
95 } else if (body + dlen != der_end) {
96 return fail("[%d] Trailing garbage in encoded string after generalized time got: %@ expected: %s", testnumber, string_create_with_hex(der, der_end), expected);
97 } else if (dlen != elen) {
98 return fail("[%d] encoded date len %zu != %zu got: %.*s expected: %s", testnumber, dlen , elen, (int)dlen, (char *)body, expected);
99 } else if (memcmp(body, expected, elen)) {
100 return fail("[%d] encoded got: %.*s expected: %s", testnumber, (int)dlen, (char *)body, expected);
101 } else {
102 return pass("[%d] properly encoded %s", testnumber, expected);
103 }
104 }
105
106 static bool ok_date_equals(int testnumber, CFDateRef decoded, CFDateRef expected) {
107 CFAbsoluteTime t1 = CFDateGetAbsoluteTime(decoded);
108 CFAbsoluteTime t2 = CFDateGetAbsoluteTime(expected);
109 if (-1.0 < t1 && t1 < 1.0) {
110 // Dates near the epoch can't be off by more than 1 nanosecond. Other dates should be exactly right.
111 return ok((decoded != NULL) && fabs(t1 - t2) < 7e-18, "[%d] Delta too big %g %a != %a (%g != %g).", testnumber, fabs(t1 - t2), t1, t2, t1, t2);
112 } else {
113 return ok((decoded != NULL) && CFEqual(decoded, expected), "[%d] Didn't make equal value %a != %a (%g != %g).", testnumber, t1, t2, t1, t2);
114 }
115 }
116
117 #if 0
118 static CFCalendarRef sZuluCalendar = NULL;
119
120 static CFCalendarRef SecCFCalendarGetZulu() {
121 static dispatch_once_t onceToken;
122 dispatch_once(&onceToken, ^{
123 sZuluCalendar = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar);
124 CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0);
125 CFCalendarSetTimeZone(sZuluCalendar, tz);
126 CFReleaseSafe(tz);
127 });
128 return sZuluCalendar;
129 }
130
131 static bool SecAbsoluteTimeGetGregorianDate(CFTimeInterval at, int *year, int *month, int *day, int *hour, int *minute, int *second, CFErrorRef *error) {
132 // TODO: Remove CFCalendarDecomposeAbsoluteTime dependancy because CFTimeZoneCreateWithTimeIntervalFromGMT is expensive and requires filesystem access to timezone files when we are only doing zulu time anyway
133 if (!CFCalendarDecomposeAbsoluteTime(SecCFCalendarGetZulu(), at, "yMdHms", year, month, day, hour, minute, second)) {
134 SecCFDERCreateError(-1000, CFSTR("Failed to encode date."), 0, error);
135 return false;
136 }
137 return true;
138 }
139
140 // &year, &month, &day, &hour, &minute, &second
141 CFTimeInterval referenceTimeDate = 416957062.807688; // 2014 3 19 21 24 22
142 #define expectedYear 2014
143 #define expectedMonth 3
144 #define expectedDay 19
145 #define expectedHour 21
146 #define expectedMinute 24
147 #define expectedSecond 22
148
149 static bool parallelizeZulu(bool useSharedZuluCalendar, void(^action)(CFCalendarRef zuluCalendar, bool *STOP)) {
150 // If useSharedZuluCalendar is false, NULL will be passed to zuluCalendar parameter of action
151 int ix;
152 static int kThreadLimit = 75000; // on a J86, this took 49963 threads to fail
153 static const int64_t kFailureTimeLimit = (NSEC_PER_SEC * 10); // Assume failure after 10s
154 dispatch_time_t failTime = dispatch_time(DISPATCH_TIME_NOW, kFailureTimeLimit);
155
156 // This is a __block variable since it can get modified (due the the <rdar://problem/16372688>)
157 __block CFCalendarRef zuluCalendar = useSharedZuluCalendar ? SecCFCalendarGetZulu() : NULL;
158 __block bool stop = false;
159
160 dispatch_group_t dgroup = dispatch_group_create();
161 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
162
163 for (ix=0;ix<kThreadLimit && !stop;ix++) {
164 dispatch_group_enter(dgroup);
165 dispatch_async(queue, ^{
166 action(zuluCalendar, &stop);
167 dispatch_group_leave(dgroup);
168 });
169 }
170 dispatch_group_wait(dgroup, failTime);
171 dispatch_release(dgroup);
172 return !stop;
173 }
174 #endif
175
176 // We expect this to fail until this is fixed:
177 // <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
178 //
179 #if 0
180 static void testWithUnguardedZuluCalendar() {
181 const bool useSharedZuluCalendar = true;
182 __block bool success = true;
183 __block int successCount = 0;
184
185 success &= parallelizeZulu(useSharedZuluCalendar, ^(CFCalendarRef zuluCalendar, bool *STOP) {
186 int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
187 bool matches = false;
188 if (!SecAbsoluteTimeGetGregorianDate(referenceTimeDate, &year, &month, &day, &hour, &minute, &second, NULL))
189 success = false;
190 matches = year==expectedYear && month==expectedMonth && day==expectedDay &&
191 hour==expectedHour && minute==expectedMinute && second==expectedSecond;
192 // assert(matches); // enable to catch crash
193 if (matches)
194 successCount++;
195 else
196 *STOP = true;
197 });
198
199 todo("<rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe, not yet fixed");
200
201 TODO: {
202 ok(success,"unexpected result from SecAbsoluteTimeGetGregorianDate, failed, successes: %d", successCount);
203 }
204 }
205
206 static void testDoWithZulu() {
207 const bool useSharedZuluCalendar = false;
208 int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
209 __block bool success = true;
210
211 success &= parallelizeZulu(useSharedZuluCalendar, ^(CFCalendarRef zuluCalendar, bool *STOP) {
212 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
213 bool matches = false;
214 success &= CFCalendarDecomposeAbsoluteTime(zuluCalendar, referenceTimeDate, "yMdHms", &year, &month, &day, &hour, &minute, &second);
215 matches = year==expectedYear && month==expectedMonth && day==expectedDay &&
216 hour==expectedHour && minute==expectedMinute && second==expectedSecond;
217 *STOP = !matches;
218 });
219 });
220
221 ok(success,"unexpected result from CFCalendarDecomposeAbsoluteTime");
222 }
223 #endif
224
225 #define kTestsPerTestCase 12
226 static void one_test(const struct test_case * thisCase, int testnumber)
227 {
228 uint8_t buffer[kMaxResultSize];
229 uint8_t* buffer_end = buffer + sizeof(buffer);
230
231 CFDateRef initialValue = CFDateCreate(NULL, thisCase->value);
232 CFErrorRef error = NULL;
233
234 uint8_t* encoded = der_encode_plist(initialValue, &error, buffer, buffer_end);
235 SKIP:
236 {
237 skip("der_encode_plist failed", 1,
238 ok(encoded != NULL, "[%d] der_encode_plist failed: %@", testnumber, error));
239 ok_der_date_is(testnumber, thisCase->expected, encoded, buffer_end);
240 }
241 CFReleaseNull(error);
242
243 encoded = der_encode_date(initialValue, &error, buffer, buffer_end);
244 SKIP:
245 {
246 skip("der_encode_date failed", 1,
247 ok(encoded != NULL, "[%d] der_encode_date failed: %@", testnumber, error));
248 ok_der_date_is(testnumber, thisCase->expected, encoded, buffer_end);
249 }
250 CFReleaseNull(error);
251
252 CFDateRef decoded = NULL;
253 const uint8_t* decode_end = der_decode_date(NULL,
254 &decoded, &error, encoded, buffer_end);
255 ok(error == NULL, "[%d] der_decode_date failed: %@", testnumber, error);
256 CFReleaseNull(error);
257
258 ok(decode_end == buffer_end, "[%d] didn't decode whole buffer", testnumber);
259 ok_date_equals(testnumber, decoded, initialValue);
260
261 CFPropertyListRef decoded_type = NULL;
262
263 decode_end = der_decode_plist(NULL,
264 &decoded_type, &error, encoded, buffer_end);
265 ok(error == NULL, "[%d] der_decode_plist failed: %@", testnumber, error);
266 CFReleaseNull(error);
267
268 ok(decode_end == buffer_end, "[%d] didn't decode whole buffer", testnumber);
269 ok_date_equals(testnumber, decoded, initialValue);
270
271 is(der_sizeof_date(initialValue, NULL), ccder_sizeof(CCDER_GENERALIZED_TIME, strlen(thisCase->expected)), "[%d] der_sizeof_date mismatch", testnumber);
272 is(der_sizeof_plist(initialValue, NULL), ccder_sizeof(CCDER_GENERALIZED_TIME, strlen(thisCase->expected)), "[%d] der_sizeof_plist mismatch", testnumber);
273
274 CFReleaseSafe(initialValue);
275 CFReleaseNull(decoded);
276 CFReleaseNull(decoded_type);
277 }
278
279 #define kTestCount (array_size(test_cases) * kTestsPerTestCase)
280 static void tests(void)
281 {
282 for (int testnumber = 0; testnumber < array_size(test_cases); ++testnumber)
283 one_test(test_cases + testnumber, testnumber);
284
285 // testWithUnguardedZuluCalendar();
286 // testDoWithZulu();
287 }
288
289 int su_16_cfdate_der(int argc, char *const *argv)
290 {
291 plan_tests(kTestCount);
292 tests();
293
294 return 0;
295 }