5 // Created by Michael Brouwer on 7/7/12.
6 // Copyright (c) 2012 Apple Inc. All rights reserved.
9 #include "utilities/SecCFRelease.h"
10 #include "utilities/der_date.h"
11 #include "utilities/der_plist.h"
12 #include "utilities/der_plist_internal.h"
14 #include <corecrypto/ccder.h>
15 #include <CoreFoundation/CoreFoundation.h>
21 CFAbsoluteTime
SecCFGregorianDateGetAbsoluteTime(CFGregorianDate g
, CFTimeInterval timeZoneOffset
, CFErrorRef
*error
);
22 CFGregorianDate
SecCFAbsoluteTimeGetGregorianDate(CFAbsoluteTime at
, CFTimeInterval timeZoneOffset
, CFErrorRef
*error
);
24 /* Cumalitive number of days in the year for months up to month i. */
25 static int mdays
[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
27 CFAbsoluteTime
SecCFGregorianDateGetAbsoluteTime(CFGregorianDate g
, CFTimeInterval timeZoneOffset
, CFErrorRef
*error
) {
29 int is_leap_year
= g
.year
% 4 == 0 && (g
.year
% 100 != 0 || g
.year
% 400 == 0) ? 1 : 0;
30 if (g
.month
< 1 || g
.month
> 12 || day
< 1 || day
> 31 || g
.hour
>= 24 || g
.minute
>= 60 || g
.second
>= 60.0
31 || (g
.month
== 2 && day
> mdays
[g
.month
] - mdays
[g
.month
- 1] + is_leap_year
)
32 || (g
.month
!= 2 && day
> mdays
[g
.month
] - mdays
[g
.month
- 1])) {
34 SecCFDERCreateError(-1000, CFSTR("Invalid date."), 0, error
);
38 int dy
= g
.year
- 2001;
44 int leap_days
= dy
/ 4 - dy
/ 100 + dy
/ 400;
45 day
+= ((g
.year
- 2001) * 365 + leap_days
) + mdays
[g
.month
- 1] - 1;
56 time
+= lrint(g
.second
);
57 time
-= lrint(timeZoneOffset
);
60 CFAbsoluteTime absTime
= (CFAbsoluteTime
)((day
* 24 + g
.hour
) * 60 + g
.minute
) * 60 + g
.second
;
61 return absTime
- timeZoneOffset
;
65 CFGregorianDate
SecCFAbsoluteTimeGetGregorianDate(CFAbsoluteTime at
, CFTimeInterval timeZoneOffset
, CFErrorRef
*error
) {
66 CFTimeZoneRef tz
= CFTimeZoneCreateWithTimeIntervalFromGMT(0, timeZoneOffset
);
68 SecCFDERCreateError(-1000, CFSTR("timezone creation failed."), 0, error
);
69 CFGregorianDate g
= {};
72 CFGregorianDate g
= CFAbsoluteTimeGetGregorianDate(at
, tz
);
79 static int der_get_char(const uint8_t **der_p
, const uint8_t *der_end
,
81 const uint8_t *der
= *der_p
;
83 /* Don't create a new error in this case. */
88 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
89 CFSTR("Unexpected end of datetime"), 0, error
);
100 static int der_decode_decimal(const uint8_t **der_p
, const uint8_t *der_end
,
102 char ch
= der_get_char(der_p
, der_end
, error
);
103 if (ch
< '0' || ch
> '9') {
104 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
105 CFSTR("Not a decimal digit"), 0, error
);
112 static int der_decode_decimal_pair(const uint8_t **der_p
, const uint8_t *der_end
,
114 return (10 * der_decode_decimal(der_p
, der_end
, error
))
115 + der_decode_decimal(der_p
, der_end
, error
);
118 static int der_peek_byte(const uint8_t *der
, const uint8_t *der_end
) {
119 if (!der
|| der
>= der_end
)
125 static const uint8_t *der_decode_decimal_fraction(double *fraction
, CFErrorRef
*error
,
126 const uint8_t* der
, const uint8_t *der_end
) {
127 int ch
= der_peek_byte(der
, der_end
);
130 } else if (ch
== '.') {
131 uint64_t divisor
= 1;
134 while (++der
< der_end
) {
137 if (ch
< '0' || ch
> '9') {
140 if (divisor
< UINT64_MAX
/ 10) {
148 else if (last
== '0') {
149 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
150 CFSTR("fraction ends in 0"), 0, error
);
152 } else if (last
== '.') {
153 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
154 CFSTR("fraction without digits"), 0, error
);
157 *fraction
= (double)value
/ divisor
;
166 static const CFTimeInterval
der_decode_timezone_offset(const uint8_t **der_p
,
167 const uint8_t *der_end
,
169 CFTimeInterval timeZoneOffset
;
170 int ch
= der_get_char(der_p
, der_end
, error
);
173 timeZoneOffset
= 0.0;
182 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
183 CFSTR("Invalid datetime character"), 0, error
);
184 timeZoneOffset
= NULL_TIME
;
187 timeZoneOffset
= multiplier
*
188 (der_decode_decimal_pair(der_p
, der_end
, error
)
189 * 60 + der_decode_decimal_pair(der_p
, der_end
, error
));
191 return timeZoneOffset
;
194 static const uint8_t* der_decode_commontime_body(CFAbsoluteTime
*at
, CFErrorRef
*error
, SInt32 year
,
195 const uint8_t* der
, const uint8_t *der_end
)
199 g
.month
= der_decode_decimal_pair(&der
, der_end
, error
);
200 g
.day
= der_decode_decimal_pair(&der
, der_end
, error
);
201 g
.hour
= der_decode_decimal_pair(&der
, der_end
, error
);
202 g
.minute
= der_decode_decimal_pair(&der
, der_end
, error
);
203 g
.second
= der_decode_decimal_pair(&der
, der_end
, error
);
205 der
= der_decode_decimal_fraction(&fraction
, error
, der
, der_end
);
207 CFTimeInterval timeZoneOffset
= der_decode_timezone_offset(&der
, der_end
, error
);
210 secdebug("dateparse",
211 "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g",
212 length
, bytes
, g
.year
, g
.month
,
213 g
.day
, g
.hour
, g
.minute
, g
.second
,
214 timeZoneOffset
/ 60);
218 if (der
!= der_end
) {
219 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
220 CFSTR("trailing garbage at end of datetime"), 0, error
);
224 *at
= SecCFGregorianDateGetAbsoluteTime(g
, timeZoneOffset
, error
) + fraction
;
225 if (*at
== NULL_TIME
)
232 const uint8_t* der_decode_generalizedtime_body(CFAbsoluteTime
*at
, CFErrorRef
*error
,
233 const uint8_t* der
, const uint8_t *der_end
)
235 SInt32 year
= 100 * der_decode_decimal_pair(&der
, der_end
, error
) + der_decode_decimal_pair(&der
, der_end
, error
);
236 return der_decode_commontime_body(at
, error
, year
, der
, der_end
);
239 const uint8_t* der_decode_universaltime_body(CFAbsoluteTime
*at
, CFErrorRef
*error
,
240 const uint8_t* der
, const uint8_t *der_end
)
242 SInt32 year
= der_decode_decimal_pair(&der
, der_end
, error
);
244 /* 0 <= year < 50 : assume century 21 */
246 } else if (year
< 70) {
247 /* 50 <= year < 70 : illegal per PKIX */
248 SecCFDERCreateError(kSecDERErrorUnknownEncoding
,
249 CFSTR("Invalid universal time year between 50 and 70"), 0, error
);
252 /* 70 < year <= 99 : assume century 20 */
256 return der_decode_commontime_body(at
, error
, year
, der
, der_end
);
259 const uint8_t* der_decode_date(CFAllocatorRef allocator
, CFOptionFlags mutability
,
260 CFDateRef
* date
, CFErrorRef
*error
,
261 const uint8_t* der
, const uint8_t *der_end
)
266 der
= ccder_decode_constructed_tl(CCDER_GENERALIZED_TIME
, &der_end
, der
, der_end
);
268 der
= der_decode_generalizedtime_body(&at
, error
, der
, der_end
);
270 *date
= CFDateCreate(allocator
, at
);
272 SecCFDERCreateError(kSecDERErrorUnderlyingError
, CFSTR("Failed to create date"), NULL
, error
);
279 extern char *__dtoa(double _d
, int mode
, int ndigits
, int *decpt
, int *sign
, char **rve
);
280 extern void __freedtoa(char *);
282 static size_t ccder_sizeof_nanoseconds(CFAbsoluteTime at
) {
286 char *str
= __dtoa(at
, 0, 0, &dotoff
, &sign
, &end
);
287 ptrdiff_t len
= end
- str
;
289 return len
< dotoff
? 0 : len
- dotoff
;
290 //return len < dotoff ? 0 : len - dotoff > 9 ? 9 : len - dotoff;
293 size_t der_sizeof_generalizedtime_body(CFAbsoluteTime at
, CFErrorRef
*error
)
295 size_t subsec_digits
= ccder_sizeof_nanoseconds(at
);
297 /* Generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
298 return subsec_digits
? 16 + subsec_digits
: 15;
301 size_t der_sizeof_generalizedtime(CFAbsoluteTime at
, CFErrorRef
*error
)
303 return ccder_sizeof(CCDER_GENERALIZED_TIME
,
304 der_sizeof_generalizedtime_body(at
, error
));
307 size_t der_sizeof_date(CFDateRef date
, CFErrorRef
*error
)
309 return der_sizeof_generalizedtime(CFDateGetAbsoluteTime(date
), error
);
313 static uint8_t *ccder_encode_byte(uint8_t byte
,
314 const uint8_t *der
, uint8_t *der_end
) {
315 if (der
+ 1 > der_end
) {
322 static uint8_t *ccder_encode_decimal_pair(int v
, const uint8_t *der
,
324 if (der
+ 2 > der_end
) {
328 *--der_end
= '0' + v
% 10;
329 *--der_end
= '0' + v
/ 10;
333 static uint8_t *ccder_encode_decimal_quad(int v
, const uint8_t *der
,
335 return ccder_encode_decimal_pair(v
/ 100, der
,
336 ccder_encode_decimal_pair(v
% 100, der
, der_end
));
339 static uint8_t *ccder_encode_nanoseconds(CFAbsoluteTime at
, const uint8_t *der
,
344 char *str
= __dtoa(at
, 0, 0, &dotoff
, &sign
, &end
);
345 char *begin
= str
+ (dotoff
< 0 ? 0 : dotoff
);
346 // Compute 1.0000000 - fraction in ascii space
347 if (at
< 0.0 && begin
< end
) {
349 // Borrow for last digit
350 *p
= ('9' + 1) - (*p
- '0');
351 while (p
-- > begin
) {
352 // Every other digit is a 9 since we borrowed from the last one
353 *p
= '9' - (*p
- '0');
357 ptrdiff_t len
= end
- str
;
360 assert(-1.0 < at
&& at
< 1.0);
361 der_end
= ccder_encode_body(len
, (const uint8_t *)str
, der
, der_end
);
362 der_end
= ccder_encode_body_nocopy(-dotoff
, der
, der_end
);
364 memset(der_end
, at
< 0.0 ? '9' : '0', -dotoff
);
366 der_end
= ccder_encode_body(len
- dotoff
, (const uint8_t *)(str
+ dotoff
), der
, der_end
);
368 der_end
= ccder_encode_byte('.', der
, der_end
);
375 /* Encode generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
376 uint8_t* der_encode_generalizedtime_body(CFAbsoluteTime at
, CFErrorRef
*error
,
377 const uint8_t *der
, uint8_t *der_end
)
379 CFGregorianDate g
= SecCFAbsoluteTimeGetGregorianDate(floor(at
), 0.0, error
);
383 return ccder_encode_decimal_quad(g
.year
, der
,
384 ccder_encode_decimal_pair(g
.month
, der
,
385 ccder_encode_decimal_pair(g
.day
, der
,
386 ccder_encode_decimal_pair(g
.hour
, der
,
387 ccder_encode_decimal_pair(g
.minute
, der
,
388 ccder_encode_decimal_pair(g
.second
, der
,
389 ccder_encode_nanoseconds(at
, der
,
390 ccder_encode_byte('Z', der
, der_end
))))))));
393 uint8_t* der_encode_generalizedtime(CFAbsoluteTime at
, CFErrorRef
*error
,
394 const uint8_t *der
, uint8_t *der_end
)
396 return ccder_encode_constructed_tl(CCDER_GENERALIZED_TIME
, der_end
, der
,
397 der_encode_generalizedtime_body(at
, error
, der
, der_end
));
401 uint8_t* der_encode_date(CFDateRef date
, CFErrorRef
*error
,
402 const uint8_t *der
, uint8_t *der_end
)
404 return der_encode_generalizedtime(CFDateGetAbsoluteTime(date
), error
,