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/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"
31 #include <corecrypto/ccder.h>
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFCalendar.h>
38 /* Cumulative number of days in the year for months up to month i. */
39 static int mdays
[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
41 static CFAbsoluteTime
SecGregorianDateGetAbsoluteTime(int year
, int month
, int day
, int hour
, int minute
, int second
, CFTimeInterval timeZoneOffset
, CFErrorRef
*error
) {
42 int is_leap_year
= year
% 4 == 0 && (year
% 100 != 0 || year
% 400 == 0) ? 1 : 0;
43 if (month
< 1 || month
> 12 || day
< 1 || day
> 31 || hour
>= 24 || minute
>= 60 || second
>= 60.0
44 || (month
== 2 && day
> mdays
[month
] - mdays
[month
- 1] + is_leap_year
)
45 || (month
!= 2 && day
> mdays
[month
] - mdays
[month
- 1])) {
47 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Invalid date."), 0, error
);
57 int leap_days
= dy
/ 4 - dy
/ 100 + dy
/ 400;
58 day
+= ((year
- 2001) * 365 + leap_days
) + mdays
[month
- 1] - 1;
62 CFAbsoluteTime absTime
= (CFAbsoluteTime
)((day
* 24 + hour
) * 60 + minute
) * 60 + second
;
63 return absTime
- timeZoneOffset
;
66 static bool SecAbsoluteTimeGetGregorianDate(CFTimeInterval at
, int *year
, int *month
, int *day
, int *hour
, int *minute
, int *second
, CFErrorRef
*error
) {
67 // TODO: Remove CFCalendarDecomposeAbsoluteTime dependancy because CFTimeZoneCreateWithTimeIntervalFromGMT is expensive and requires filesystem access to timezone files when we are only doing zulu time anyway
68 if (!CFCalendarDecomposeAbsoluteTime(SecCFCalendarGetZulu(), at
, "yMdHms", year
, month
, day
, hour
, minute
, second
)) {
69 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Failed to encode date."), 0, error
);
75 static int der_get_char(const uint8_t **der_p
, const uint8_t *der_end
,
77 const uint8_t *der
= *der_p
;
79 /* Don't create a new error in this case. */
84 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
85 CFSTR("Unexpected end of datetime"), 0, error
);
96 static int der_decode_decimal(const uint8_t **der_p
, const uint8_t *der_end
,
98 char ch
= der_get_char(der_p
, der_end
, error
);
99 if (ch
< '0' || ch
> '9') {
100 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
101 CFSTR("Not a decimal digit"), 0, error
);
108 static int der_decode_decimal_pair(const uint8_t **der_p
, const uint8_t *der_end
,
110 return (10 * der_decode_decimal(der_p
, der_end
, error
))
111 + der_decode_decimal(der_p
, der_end
, error
);
114 static int der_peek_byte(const uint8_t *der
, const uint8_t *der_end
) {
115 if (!der
|| der
>= der_end
)
121 static const uint8_t *der_decode_decimal_fraction(double *fraction
, CFErrorRef
*error
,
122 const uint8_t* der
, const uint8_t *der_end
) {
123 int ch
= der_peek_byte(der
, der_end
);
126 } else if (ch
== '.') {
127 uint64_t divisor
= 1;
130 while (++der
< der_end
) {
133 if (ch
< '0' || ch
> '9') {
136 if (divisor
< UINT64_MAX
/ 10) {
144 else if (last
== '0') {
145 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
146 CFSTR("fraction ends in 0"), 0, error
);
148 } else if (last
== '.') {
149 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
150 CFSTR("fraction without digits"), 0, error
);
153 *fraction
= (double)value
/ divisor
;
162 static const CFTimeInterval
der_decode_timezone_offset(const uint8_t **der_p
,
163 const uint8_t *der_end
,
165 CFTimeInterval timeZoneOffset
;
166 int ch
= der_get_char(der_p
, der_end
, error
);
169 timeZoneOffset
= 0.0;
178 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
179 CFSTR("Invalid datetime character"), 0, error
);
183 timeZoneOffset
= multiplier
*
184 (der_decode_decimal_pair(der_p
, der_end
, error
)
185 * 60 + der_decode_decimal_pair(der_p
, der_end
, error
));
187 return timeZoneOffset
;
190 static const uint8_t* der_decode_commontime_body(CFAbsoluteTime
*at
, CFErrorRef
*error
, int year
,
191 const uint8_t* der
, const uint8_t *der_end
)
193 int month
= der_decode_decimal_pair(&der
, der_end
, error
);
194 int day
= der_decode_decimal_pair(&der
, der_end
, error
);
195 int hour
= der_decode_decimal_pair(&der
, der_end
, error
);
196 int minute
= der_decode_decimal_pair(&der
, der_end
, error
);
197 int second
= der_decode_decimal_pair(&der
, der_end
, error
);
199 der
= der_decode_decimal_fraction(&fraction
, error
, der
, der_end
);
201 CFTimeInterval timeZoneOffset
= der_decode_timezone_offset(&der
, der_end
, error
);
204 secdebug("dateparse",
205 "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g",
206 length
, bytes
, g
.year
, g
.month
,
207 g
.day
, g
.hour
, g
.minute
, g
.second
,
208 timeZoneOffset
/ 60);
212 if (der
!= der_end
) {
213 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
214 CFSTR("trailing garbage at end of datetime"), 0, error
);
218 *at
= SecGregorianDateGetAbsoluteTime(year
, month
, day
, hour
, minute
, second
, timeZoneOffset
, error
) + fraction
;
219 if (*at
== NULL_TIME
)
226 const uint8_t* der_decode_generalizedtime_body(CFAbsoluteTime
*at
, CFErrorRef
*error
,
227 const uint8_t* der
, const uint8_t *der_end
)
229 int year
= 100 * der_decode_decimal_pair(&der
, der_end
, error
) + der_decode_decimal_pair(&der
, der_end
, error
);
230 return der_decode_commontime_body(at
, error
, year
, der
, der_end
);
233 const uint8_t* der_decode_universaltime_body(CFAbsoluteTime
*at
, CFErrorRef
*error
,
234 const uint8_t* der
, const uint8_t *der_end
)
236 SInt32 year
= der_decode_decimal_pair(&der
, der_end
, error
);
238 /* 0 <= year < 50 : assume century 21 */
240 } else if (year
< 70) {
241 /* 50 <= year < 70 : illegal per PKIX */
242 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
243 CFSTR("Invalid universal time year between 50 and 70"), 0, error
);
246 /* 70 < year <= 99 : assume century 20 */
250 return der_decode_commontime_body(at
, error
, year
, der
, der_end
);
253 const uint8_t* der_decode_date(CFAllocatorRef allocator
, CFOptionFlags mutability
,
254 CFDateRef
* date
, CFErrorRef
*error
,
255 const uint8_t* der
, const uint8_t *der_end
)
260 der
= ccder_decode_constructed_tl(CCDER_GENERALIZED_TIME
, &der_end
, der
, der_end
);
261 CFAbsoluteTime at
= 0;
262 der
= der_decode_generalizedtime_body(&at
, error
, der
, der_end
);
264 *date
= CFDateCreate(allocator
, at
);
266 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create date"), NULL
, error
);
273 extern char *__dtoa(double _d
, int mode
, int ndigits
, int *decpt
, int *sign
, char **rve
);
274 extern void __freedtoa(char *);
276 static size_t ccder_sizeof_nanoseconds(CFAbsoluteTime at
) {
280 char *str
= __dtoa(at
, 0, 0, &dotoff
, &sign
, &end
);
281 ptrdiff_t len
= end
- str
;
283 return len
< dotoff
? 0 : len
- dotoff
;
284 //return len < dotoff ? 0 : len - dotoff > 9 ? 9 : len - dotoff;
287 size_t der_sizeof_generalizedtime_body(CFAbsoluteTime at
, CFErrorRef
*error
)
289 size_t subsec_digits
= ccder_sizeof_nanoseconds(at
);
291 /* Generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
292 return subsec_digits
? 16 + subsec_digits
: 15;
295 size_t der_sizeof_generalizedtime(CFAbsoluteTime at
, CFErrorRef
*error
)
297 return ccder_sizeof(CCDER_GENERALIZED_TIME
,
298 der_sizeof_generalizedtime_body(at
, error
));
301 size_t der_sizeof_date(CFDateRef date
, CFErrorRef
*error
)
303 return der_sizeof_generalizedtime(CFDateGetAbsoluteTime(date
), error
);
307 static uint8_t *ccder_encode_byte(uint8_t byte
,
308 const uint8_t *der
, uint8_t *der_end
) {
309 if (der
+ 1 > der_end
) {
316 static uint8_t *ccder_encode_decimal_pair(int v
, const uint8_t *der
,
318 if (der_end
== NULL
|| der
+ 2 > der_end
) {
322 *--der_end
= '0' + v
% 10;
323 *--der_end
= '0' + v
/ 10;
327 static uint8_t *ccder_encode_decimal_quad(int v
, const uint8_t *der
,
329 return ccder_encode_decimal_pair(v
/ 100, der
,
330 ccder_encode_decimal_pair(v
% 100, der
, der_end
));
333 static uint8_t *ccder_encode_nanoseconds(CFAbsoluteTime at
, const uint8_t *der
,
338 char *str
= __dtoa(at
, 0, 0, &dotoff
, &sign
, &end
);
339 char *begin
= str
+ (dotoff
< 0 ? 0 : dotoff
);
340 // Compute 1.0000000 - fraction in ascii space
341 if (at
< 0.0 && begin
< end
) {
343 // Borrow for last digit
344 *p
= ('9' + 1) - (*p
- '0');
345 while (p
-- > begin
) {
346 // Every other digit is a 9 since we borrowed from the last one
347 *p
= '9' - (*p
- '0');
351 ptrdiff_t len
= end
- str
;
354 assert(-1.0 < at
&& at
< 1.0);
355 der_end
= ccder_encode_body(len
, (const uint8_t *)str
, der
, der_end
);
356 der_end
= ccder_encode_body_nocopy(-dotoff
, der
, der_end
);
358 memset(der_end
, at
< 0.0 ? '9' : '0', -dotoff
);
360 der_end
= ccder_encode_body(len
- dotoff
, (const uint8_t *)(str
+ dotoff
), der
, der_end
);
362 der_end
= ccder_encode_byte('.', der
, der_end
);
369 /* Encode generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
370 uint8_t* der_encode_generalizedtime_body(CFAbsoluteTime at
, CFErrorRef
*error
,
371 const uint8_t *der
, uint8_t *der_end
)
373 int year
= 0, month
= 0, day
= 0, hour
= 0, minute
= 0, second
= 0;
374 if (!SecAbsoluteTimeGetGregorianDate(at
, &year
, &month
, &day
, &hour
, &minute
, &second
, error
))
377 return ccder_encode_decimal_quad(year
, der
,
378 ccder_encode_decimal_pair(month
, der
,
379 ccder_encode_decimal_pair(day
, der
,
380 ccder_encode_decimal_pair(hour
, der
,
381 ccder_encode_decimal_pair(minute
, der
,
382 ccder_encode_decimal_pair(second
, der
,
383 ccder_encode_nanoseconds(at
, der
,
384 ccder_encode_byte('Z', der
, der_end
))))))));
387 uint8_t* der_encode_generalizedtime(CFAbsoluteTime at
, CFErrorRef
*error
,
388 const uint8_t *der
, uint8_t *der_end
)
390 return ccder_encode_constructed_tl(CCDER_GENERALIZED_TIME
, der_end
, der
,
391 der_encode_generalizedtime_body(at
, error
, der
, der_end
));
395 uint8_t* der_encode_date(CFDateRef date
, CFErrorRef
*error
,
396 const uint8_t *der
, uint8_t *der_end
)
398 return der_encode_generalizedtime(CFDateGetAbsoluteTime(date
), error
,