]> git.saurik.com Git - apple/security.git/blob - Security/utilities/src/der_date.c
Security-57031.40.6.tar.gz
[apple/security.git] / Security / utilities / src / der_date.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/SecCFRelease.h"
26 #include "utilities/SecCFWrappers.h"
27 #include "utilities/der_date.h"
28 #include "utilities/der_plist.h"
29 #include "utilities/der_plist_internal.h"
30
31 #include <corecrypto/ccder.h>
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFCalendar.h>
34 #include <math.h>
35
36 #define NULL_TIME NAN
37 #define IS_NULL_TIME(x) isnan(x)
38
39 /* Cumulative number of days in the year for months up to month i. */
40 static int mdays[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
41
42 static CFAbsoluteTime SecGregorianDateGetAbsoluteTime(int year, int month, int day, int hour, int minute, int second, CFTimeInterval timeZoneOffset, CFErrorRef *error) {
43 int is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) ? 1 : 0;
44 if (month < 1 || month > 12 || day < 1 || day > 31 || hour >= 24 || minute >= 60 || second >= 60.0
45 || (month == 2 && day > mdays[month] - mdays[month - 1] + is_leap_year)
46 || (month != 2 && day > mdays[month] - mdays[month - 1])) {
47 /* Invalid date. */
48 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Invalid date."), 0, error);
49 return NULL_TIME;
50 }
51
52 int dy = year - 2001;
53 if (dy < 0) {
54 dy += 1;
55 day -= 1;
56 }
57
58 int leap_days = dy / 4 - dy / 100 + dy / 400;
59 day += ((year - 2001) * 365 + leap_days) + mdays[month - 1] - 1;
60 if (month > 2)
61 day += is_leap_year;
62
63 CFAbsoluteTime absTime = (CFAbsoluteTime)((day * 24 + hour) * 60 + minute) * 60 + second;
64 return absTime - timeZoneOffset;
65 }
66
67 static bool SecAbsoluteTimeGetGregorianDate(CFTimeInterval at, int *year, int *month, int *day, int *hour, int *minute, int *second, CFErrorRef *error) {
68 // TODO: Remove CFCalendarDecomposeAbsoluteTime dependancy because
69 // CFTimeZoneCreateWithTimeIntervalFromGMT is expensive and requires
70 // filesystem access to timezone files when we are only doing zulu time anyway
71 __block bool result;
72 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
73 result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, at, "yMdHms", year, month, day, hour, minute, second);
74 });
75 if (!result)
76 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Failed to encode date."), 0, error);
77 return result;
78 }
79
80 static int der_get_char(const uint8_t **der_p, const uint8_t *der_end,
81 CFErrorRef *error) {
82 const uint8_t *der = *der_p;
83 if (!der) {
84 /* Don't create a new error in this case. */
85 return -1;
86 }
87
88 if (der >= der_end) {
89 SecCFDERCreateError(kSecDERErrorUnknownEncoding,
90 CFSTR("Unexpected end of datetime"), 0, error);
91 *der_p = NULL;
92 return -1;
93 }
94
95 int ch = *der++;
96 *der_p = der;
97 return ch;
98 }
99
100
101 static int der_decode_decimal(const uint8_t **der_p, const uint8_t *der_end,
102 CFErrorRef *error) {
103 char ch = der_get_char(der_p, der_end, error);
104 if (ch < '0' || ch > '9') {
105 SecCFDERCreateError(kSecDERErrorUnknownEncoding,
106 CFSTR("Not a decimal digit"), 0, error);
107 *der_p = NULL;
108 return -1;
109 }
110 return ch - '0';
111 }
112
113 static int der_decode_decimal_pair(const uint8_t **der_p, const uint8_t *der_end,
114 CFErrorRef *error) {
115 return (10 * der_decode_decimal(der_p, der_end, error))
116 + der_decode_decimal(der_p, der_end, error);
117 }
118
119 static int der_peek_byte(const uint8_t *der, const uint8_t *der_end) {
120 if (!der || der >= der_end)
121 return -1;
122
123 return *der;
124 }
125
126 static const uint8_t *der_decode_decimal_fraction(double *fraction, CFErrorRef *error,
127 const uint8_t* der, const uint8_t *der_end) {
128 int ch = der_peek_byte(der, der_end);
129 if (ch == -1) {
130 der = NULL;
131 } else if (ch == '.') {
132 uint64_t divisor = 1;
133 uint64_t value = 0;
134 int last = -1;
135 while (++der < der_end) {
136 last = ch;
137 ch = *der;
138 if (ch < '0' || ch > '9') {
139 break;
140 }
141 if (divisor < UINT64_MAX / 10) {
142 divisor *= 10;
143 value *= 10;
144 value += (ch - '0');
145 }
146 }
147 if (der >= der_end)
148 der = NULL;
149 else if (last == '0') {
150 SecCFDERCreateError(kSecDERErrorUnknownEncoding,
151 CFSTR("fraction ends in 0"), 0, error);
152 der = NULL;
153 } else if (last == '.') {
154 SecCFDERCreateError(kSecDERErrorUnknownEncoding,
155 CFSTR("fraction without digits"), 0, error);
156 der = NULL;
157 } else {
158 *fraction = (double)value / divisor;
159 }
160 } else {
161 *fraction = 0.0;
162 }
163
164 return der;
165 }
166
167 static const CFTimeInterval der_decode_timezone_offset(const uint8_t **der_p,
168 const uint8_t *der_end,
169 CFErrorRef *error) {
170 CFTimeInterval timeZoneOffset;
171 int ch = der_get_char(der_p, der_end, error);
172 if (ch == 'Z') {
173 /* Zulu time. */
174 timeZoneOffset = 0.0;
175 } else {
176 /* ZONE INDICATOR */
177 int multiplier;
178 if (ch == '-')
179 multiplier = -60;
180 else if (ch == '+')
181 multiplier = +60;
182 else {
183 SecCFDERCreateError(kSecDERErrorUnknownEncoding,
184 CFSTR("Invalid datetime character"), 0, error);
185 return NULL_TIME;
186 }
187
188 timeZoneOffset = multiplier *
189 (der_decode_decimal_pair(der_p, der_end, error)
190 * 60 + der_decode_decimal_pair(der_p, der_end, error));
191 }
192 return timeZoneOffset;
193 }
194
195 static const uint8_t* der_decode_commontime_body(CFAbsoluteTime *at, CFErrorRef *error, int year,
196 const uint8_t* der, const uint8_t *der_end)
197 {
198 int month = der_decode_decimal_pair(&der, der_end, error);
199 int day = der_decode_decimal_pair(&der, der_end, error);
200 int hour = der_decode_decimal_pair(&der, der_end, error);
201 int minute = der_decode_decimal_pair(&der, der_end, error);
202 int second = der_decode_decimal_pair(&der, der_end, error);
203 double fraction;
204 der = der_decode_decimal_fraction(&fraction, error, der, der_end);
205
206 CFTimeInterval timeZoneOffset = der_decode_timezone_offset(&der, der_end, error);
207
208 #if 0
209 secdebug("dateparse",
210 "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g",
211 length, bytes, g.year, g.month,
212 g.day, g.hour, g.minute, g.second,
213 timeZoneOffset / 60);
214 #endif
215
216 if (der) {
217 if (der != der_end) {
218 SecCFDERCreateError(kSecDERErrorUnknownEncoding,
219 CFSTR("trailing garbage at end of datetime"), 0, error);
220 return NULL;
221 }
222
223 *at = SecGregorianDateGetAbsoluteTime(year, month, day, hour, minute, second, timeZoneOffset, error);
224 if (IS_NULL_TIME(*at))
225 return NULL;
226
227 *at += fraction;
228 }
229
230 return der;
231 }
232
233 const uint8_t* der_decode_generalizedtime_body(CFAbsoluteTime *at, CFErrorRef *error,
234 const uint8_t* der, const uint8_t *der_end)
235 {
236 int year = 100 * der_decode_decimal_pair(&der, der_end, error) + der_decode_decimal_pair(&der, der_end, error);
237 return der_decode_commontime_body(at, error, year, der, der_end);
238 }
239
240 const uint8_t* der_decode_universaltime_body(CFAbsoluteTime *at, CFErrorRef *error,
241 const uint8_t* der, const uint8_t *der_end)
242 {
243 SInt32 year = der_decode_decimal_pair(&der, der_end, error);
244 if (year < 50) {
245 /* 0 <= year < 50 : assume century 21 */
246 year += 2000;
247 } else if (year < 70) {
248 /* 50 <= year < 70 : illegal per PKIX */
249 SecCFDERCreateError(kSecDERErrorUnknownEncoding,
250 CFSTR("Invalid universal time year between 50 and 70"), 0, error);
251 der = NULL;
252 } else {
253 /* 70 < year <= 99 : assume century 20 */
254 year += 1900;
255 }
256
257 return der_decode_commontime_body(at, error, year, der, der_end);
258 }
259
260 const uint8_t* der_decode_date(CFAllocatorRef allocator, CFOptionFlags mutability,
261 CFDateRef* date, CFErrorRef *error,
262 const uint8_t* der, const uint8_t *der_end)
263 {
264 if (NULL == der)
265 return NULL;
266
267 der = ccder_decode_constructed_tl(CCDER_GENERALIZED_TIME, &der_end, der, der_end);
268 CFAbsoluteTime at = 0;
269 der = der_decode_generalizedtime_body(&at, error, der, der_end);
270 if (der) {
271 *date = CFDateCreate(allocator, at);
272 if (NULL == *date) {
273 SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create date"), NULL, error);
274 return NULL;
275 }
276 }
277 return der;
278 }
279
280 extern char *__dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve);
281 extern void __freedtoa(char *);
282
283 static size_t ccder_sizeof_nanoseconds(CFAbsoluteTime at) {
284 int dotoff;
285 int sign;
286 char *end;
287 char *str = __dtoa(at, 0, 0, &dotoff, &sign, &end);
288 ptrdiff_t len = end - str;
289 __freedtoa(str);
290 return len < dotoff ? 0 : len - dotoff;
291 //return len < dotoff ? 0 : len - dotoff > 9 ? 9 : len - dotoff;
292 }
293
294 size_t der_sizeof_generalizedtime_body(CFAbsoluteTime at, CFErrorRef *error)
295 {
296 size_t subsec_digits = ccder_sizeof_nanoseconds(at);
297
298 /* Generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
299 return subsec_digits ? 16 + subsec_digits : 15;
300 }
301
302 size_t der_sizeof_generalizedtime(CFAbsoluteTime at, CFErrorRef *error)
303 {
304 return ccder_sizeof(CCDER_GENERALIZED_TIME,
305 der_sizeof_generalizedtime_body(at, error));
306 }
307
308 size_t der_sizeof_date(CFDateRef date, CFErrorRef *error)
309 {
310 return der_sizeof_generalizedtime(CFDateGetAbsoluteTime(date), error);
311 }
312
313
314 static uint8_t *ccder_encode_byte(uint8_t byte,
315 const uint8_t *der, uint8_t *der_end) {
316 if (der + 1 > der_end) {
317 return NULL;
318 }
319 *--der_end = byte;
320 return der_end;
321 }
322
323 static uint8_t *ccder_encode_decimal_pair(int v, const uint8_t *der,
324 uint8_t *der_end) {
325 if (der_end == NULL || der + 2 > der_end) {
326 return NULL;
327 }
328 assert(v < 100);
329 *--der_end = '0' + v % 10;
330 *--der_end = '0' + v / 10;
331 return der_end;
332 }
333
334 static uint8_t *ccder_encode_decimal_quad(int v, const uint8_t *der,
335 uint8_t *der_end) {
336 return ccder_encode_decimal_pair(v / 100, der,
337 ccder_encode_decimal_pair(v % 100, der, der_end));
338 }
339
340 static uint8_t *ccder_encode_nanoseconds(CFAbsoluteTime at, const uint8_t *der,
341 uint8_t *der_end) {
342 int dotoff;
343 int sign;
344 char *end;
345 char *str = __dtoa(at, 0, 0, &dotoff, &sign, &end);
346 char *begin = str + (dotoff < 0 ? 0 : dotoff);
347 // Compute 1.0000000 - fraction in ascii space
348 if (at < 0.0 && begin < end) {
349 char *p = end - 1;
350 // Borrow for last digit
351 *p = ('9' + 1) - (*p - '0');
352 while (p-- > begin) {
353 // Every other digit is a 9 since we borrowed from the last one
354 *p = '9' - (*p - '0');
355 }
356 }
357
358 ptrdiff_t len = end - str;
359 if (len > dotoff) {
360 if (dotoff < 0) {
361 assert(-1.0 < at && at < 1.0);
362 der_end = ccder_encode_body(len, (const uint8_t *)str, der, der_end);
363 der_end = ccder_encode_body_nocopy(-dotoff, der, der_end);
364 if (der_end)
365 memset(der_end, at < 0.0 ? '9' : '0', -dotoff);
366 } else {
367 der_end = ccder_encode_body(len - dotoff, (const uint8_t *)(str + dotoff), der, der_end);
368 }
369 der_end = ccder_encode_byte('.', der, der_end);
370 }
371 __freedtoa(str);
372
373 return der_end;
374 }
375
376 /* Encode generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
377 uint8_t* der_encode_generalizedtime_body(CFAbsoluteTime at, CFErrorRef *error,
378 const uint8_t *der, uint8_t *der_end)
379 {
380 int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
381 if (!SecAbsoluteTimeGetGregorianDate(at, &year, &month, &day, &hour, &minute, &second, error))
382 return NULL;
383
384 uint8_t * result = ccder_encode_decimal_quad(year, der,
385 ccder_encode_decimal_pair(month, der,
386 ccder_encode_decimal_pair(day, der,
387 ccder_encode_decimal_pair(hour, der,
388 ccder_encode_decimal_pair(minute, der,
389 ccder_encode_decimal_pair(second, der,
390 ccder_encode_nanoseconds(at, der,
391 ccder_encode_byte('Z', der, der_end))))))));
392
393 return result;
394 }
395
396 uint8_t* der_encode_generalizedtime(CFAbsoluteTime at, CFErrorRef *error,
397 const uint8_t *der, uint8_t *der_end)
398 {
399 return ccder_encode_constructed_tl(CCDER_GENERALIZED_TIME, der_end, der,
400 der_encode_generalizedtime_body(at, error, der, der_end));
401 }
402
403
404 uint8_t* der_encode_date(CFDateRef date, CFErrorRef *error,
405 const uint8_t *der, uint8_t *der_end)
406 {
407 return der_encode_generalizedtime(CFDateGetAbsoluteTime(date), error,
408 der, der_end);
409 }