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>
37 #define IS_NULL_TIME(x) isnan(x)
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 };
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])) {
48 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Invalid date."), 0, error
);
58 int leap_days
= dy
/ 4 - dy
/ 100 + dy
/ 400;
59 day
+= ((year
- 2001) * 365 + leap_days
) + mdays
[month
- 1] - 1;
63 CFAbsoluteTime absTime
= (CFAbsoluteTime
)((day
* 24 + hour
) * 60 + minute
) * 60 + second
;
64 return absTime
- timeZoneOffset
;
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
72 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) {
73 result
= CFCalendarDecomposeAbsoluteTime(zuluCalendar
, at
, "yMdHms", year
, month
, day
, hour
, minute
, second
);
76 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Failed to encode date."), 0, error
);
80 static int der_get_char(const uint8_t **der_p
, const uint8_t *der_end
,
82 const uint8_t *der
= *der_p
;
84 /* Don't create a new error in this case. */
89 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
90 CFSTR("Unexpected end of datetime"), 0, error
);
101 static int der_decode_decimal(const uint8_t **der_p
, const uint8_t *der_end
,
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
);
113 static int der_decode_decimal_pair(const uint8_t **der_p
, const uint8_t *der_end
,
115 return (10 * der_decode_decimal(der_p
, der_end
, error
))
116 + der_decode_decimal(der_p
, der_end
, error
);
119 static int der_peek_byte(const uint8_t *der
, const uint8_t *der_end
) {
120 if (!der
|| der
>= der_end
)
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
);
131 } else if (ch
== '.') {
132 uint64_t divisor
= 1;
135 while (++der
< der_end
) {
138 if (ch
< '0' || ch
> '9') {
141 if (divisor
< UINT64_MAX
/ 10) {
149 else if (last
== '0') {
150 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
151 CFSTR("fraction ends in 0"), 0, error
);
153 } else if (last
== '.') {
154 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
155 CFSTR("fraction without digits"), 0, error
);
158 *fraction
= (double)value
/ divisor
;
167 static const CFTimeInterval
der_decode_timezone_offset(const uint8_t **der_p
,
168 const uint8_t *der_end
,
170 CFTimeInterval timeZoneOffset
;
171 int ch
= der_get_char(der_p
, der_end
, error
);
174 timeZoneOffset
= 0.0;
183 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
184 CFSTR("Invalid datetime character"), 0, error
);
188 timeZoneOffset
= multiplier
*
189 (der_decode_decimal_pair(der_p
, der_end
, error
)
190 * 60 + der_decode_decimal_pair(der_p
, der_end
, error
));
192 return timeZoneOffset
;
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
)
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
);
204 der
= der_decode_decimal_fraction(&fraction
, error
, der
, der_end
);
206 CFTimeInterval timeZoneOffset
= der_decode_timezone_offset(&der
, der_end
, error
);
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);
217 if (der
!= der_end
) {
218 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
219 CFSTR("trailing garbage at end of datetime"), 0, error
);
223 *at
= SecGregorianDateGetAbsoluteTime(year
, month
, day
, hour
, minute
, second
, timeZoneOffset
, error
);
224 if (IS_NULL_TIME(*at
))
233 const uint8_t* der_decode_generalizedtime_body(CFAbsoluteTime
*at
, CFErrorRef
*error
,
234 const uint8_t* der
, const uint8_t *der_end
)
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
);
240 const uint8_t* der_decode_universaltime_body(CFAbsoluteTime
*at
, CFErrorRef
*error
,
241 const uint8_t* der
, const uint8_t *der_end
)
243 SInt32 year
= der_decode_decimal_pair(&der
, der_end
, error
);
245 /* 0 <= year < 50 : assume century 21 */
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
);
253 /* 70 < year <= 99 : assume century 20 */
257 return der_decode_commontime_body(at
, error
, year
, der
, der_end
);
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
)
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
);
271 *date
= CFDateCreate(allocator
, at
);
273 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create date"), NULL
, error
);
280 extern char *__dtoa(double _d
, int mode
, int ndigits
, int *decpt
, int *sign
, char **rve
);
281 extern void __freedtoa(char *);
283 static size_t ccder_sizeof_nanoseconds(CFAbsoluteTime at
) {
287 char *str
= __dtoa(at
, 0, 0, &dotoff
, &sign
, &end
);
288 ptrdiff_t len
= end
- str
;
290 return len
< dotoff
? 0 : len
- dotoff
;
291 //return len < dotoff ? 0 : len - dotoff > 9 ? 9 : len - dotoff;
294 size_t der_sizeof_generalizedtime_body(CFAbsoluteTime at
, CFErrorRef
*error
)
296 size_t subsec_digits
= ccder_sizeof_nanoseconds(at
);
298 /* Generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
299 return subsec_digits
? 16 + subsec_digits
: 15;
302 size_t der_sizeof_generalizedtime(CFAbsoluteTime at
, CFErrorRef
*error
)
304 return ccder_sizeof(CCDER_GENERALIZED_TIME
,
305 der_sizeof_generalizedtime_body(at
, error
));
308 size_t der_sizeof_date(CFDateRef date
, CFErrorRef
*error
)
310 return der_sizeof_generalizedtime(CFDateGetAbsoluteTime(date
), error
);
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
) {
323 static uint8_t *ccder_encode_decimal_pair(int v
, const uint8_t *der
,
325 if (der_end
== NULL
|| der
+ 2 > der_end
) {
329 *--der_end
= '0' + v
% 10;
330 *--der_end
= '0' + v
/ 10;
334 static uint8_t *ccder_encode_decimal_quad(int v
, const uint8_t *der
,
336 return ccder_encode_decimal_pair(v
/ 100, der
,
337 ccder_encode_decimal_pair(v
% 100, der
, der_end
));
340 static uint8_t *ccder_encode_nanoseconds(CFAbsoluteTime at
, const uint8_t *der
,
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
) {
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');
358 ptrdiff_t len
= end
- str
;
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
);
365 memset(der_end
, at
< 0.0 ? '9' : '0', -dotoff
);
367 der_end
= ccder_encode_body(len
- dotoff
, (const uint8_t *)(str
+ dotoff
), der
, der_end
);
369 der_end
= ccder_encode_byte('.', der
, der_end
);
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
)
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
))
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
))))))));
396 uint8_t* der_encode_generalizedtime(CFAbsoluteTime at
, CFErrorRef
*error
,
397 const uint8_t *der
, uint8_t *der_end
)
399 return ccder_encode_constructed_tl(CCDER_GENERALIZED_TIME
, der_end
, der
,
400 der_encode_generalizedtime_body(at
, error
, der
, der_end
));
404 uint8_t* der_encode_date(CFDateRef date
, CFErrorRef
*error
,
405 const uint8_t *der
, uint8_t *der_end
)
407 return der_encode_generalizedtime(CFDateGetAbsoluteTime(date
), error
,