2 * Copyright (c) 2000-2001,2011-2012,2014-2019 Apple Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 * tpTime.c - cert related time functions
31 #include <security_utilities/simulatecrash_assert.h>
34 * Given a string containing either a UTC-style or "generalized time"
35 * time string, convert to a CFDateRef. Returns nonzero on
38 int timeStringToCfDate(
44 bool isUtc
= false; // 2-digit year
45 bool isLocal
= false; // trailing timezone offset
46 bool isCssmTime
= false; // no trailing 'Z'
47 bool noSeconds
= false;
52 CFTimeZoneRef timeZone
;
53 CFTimeInterval gmtOff
= 0;
55 if((str
== NULL
) || (len
== 0) || (cfDate
== NULL
)) {
59 /* tolerate NULL terminated or not */
60 if(str
[len
- 1] == '\0') {
64 case UTC_TIME_NOSEC_LEN
: // 2-digit year, no seconds, not y2K compliant
68 case UTC_TIME_STRLEN
: // 2-digit year, not Y2K compliant
71 case CSSM_TIME_STRLEN
:
74 case GENERALIZED_TIME_STRLEN
: // 4-digit year
76 case LOCALIZED_UTC_TIME_STRLEN
: // "YYMMDDhhmmssThhmm" (where T=[+,-])
78 // deliberate fallthrough
79 case LOCALIZED_TIME_STRLEN
: // "YYYYMMDDhhmmssThhmm" (where T=[+,-])
82 default: // unknown format
88 /* check that all characters except last (or timezone indicator, if localized) are digits */
89 for(i
=0; i
<(len
- 1); i
++) {
90 if ( !(isdigit(cp
[i
])) )
91 if ( !isLocal
|| !(cp
[i
]=='+' || cp
[i
]=='-') )
95 /* check last character is a 'Z' or digit as appropriate */
96 if(isCssmTime
|| isLocal
) {
97 if(!isdigit(cp
[len
- 1])) {
102 if(cp
[len
- 1] != 'Z' ) {
111 /* two more digits */
123 * 0 <= year < 50 : assume century 21
124 * 50 <= year < 70 : illegal per PKIX
125 * ...though we allow this as of 10/10/02...dmitch
126 * 70 < year <= 99 : assume century 20
148 /* in the string, months are from 1 to 12 */
149 if((x
> 12) || (x
<= 0)) {
159 /* 1..31 in both formats */
160 if((x
> 31) || (x
<= 0)) {
170 if((x
> 23) || (x
< 0)) {
180 if((x
> 59) || (x
< 0)) {
194 if((x
> 59) || (x
< 0)) {
216 x
= atoi( szTemp
) * 60 * 60;
222 x
= atoi( szTemp
) * 60;
230 timeZone
= CFTimeZoneCreateWithTimeIntervalFromGMT(NULL
, gmtOff
);
234 *cfDate
= CFDateCreate(NULL
, CFGregorianDateGetAbsoluteTime(gd
, timeZone
));
240 * Compare two times. Assumes they're both in GMT. Returns:
249 switch(CFDateCompare(t1
, t2
, NULL
)) {
250 case kCFCompareLessThan
:
252 case kCFCompareEqualTo
:
254 case kCFCompareGreaterThan
:
263 * Create a time string, in either UTC (2-digit) or or Generalized (4-digit)
264 * year format. Caller mallocs the output string whose length is at least
265 * (UTC_TIME_STRLEN+1), (GENERALIZED_TIME_STRLEN+1), or (CSSM_TIME_STRLEN+1)
266 * respectively. Caller must hold tpTimeLock.
268 void timeAtNowPlus(unsigned secFromNow
,
275 baseTime
= time(NULL
);
276 baseTime
+= (time_t)secFromNow
;
277 utc
= *gmtime(&baseTime
);
281 /* UTC - 2 year digits - code which parses this assumes that
282 * (2-digit) years between 0 and 49 are in century 21 */
283 if(utc
.tm_year
>= 100) {
286 sprintf(outStr
, "%02d%02d%02d%02d%02d%02dZ",
287 utc
.tm_year
/* + 1900 */, utc
.tm_mon
+ 1,
288 utc
.tm_mday
, utc
.tm_hour
, utc
.tm_min
, utc
.tm_sec
);
291 sprintf(outStr
, "%04d%02d%02d%02d%02d%02dZ",
292 /* note year is relative to 1900, hopefully it'll have
293 * four valid digits! */
294 utc
.tm_year
+ 1900, utc
.tm_mon
+ 1,
295 utc
.tm_mday
, utc
.tm_hour
, utc
.tm_min
, utc
.tm_sec
);
298 sprintf(outStr
, "%04d%02d%02d%02d%02d%02d",
299 /* note year is relative to 1900, hopefully it'll have
300 * four valid digits! */
301 utc
.tm_year
+ 1900, utc
.tm_mon
+ 1,
302 utc
.tm_mday
, utc
.tm_hour
, utc
.tm_min
, utc
.tm_sec
);
308 * Convert a time string, which can be in any of three forms (UTC,
309 * generalized, or CSSM_TIMESTRING) into a CSSM_TIMESTRING. Caller
310 * mallocs the result, which must be at least (CSSM_TIME_STRLEN+1) bytes.
311 * Returns nonzero if incoming time string is badly formed.
313 int tpTimeToCssmTimestring(
314 const char *inStr
, // not necessarily NULL terminated
315 unsigned inStrLen
, // not including possible NULL
318 if((inStrLen
== 0) || (inStr
== NULL
)) {
323 case UTC_TIME_STRLEN
:
325 /* infer century and prepend to output */
334 * 0 <= year < 50 : assume century 21
335 * 50 <= year < 70 : illegal per PKIX
336 * 70 < year <= 99 : assume century 20
340 strcpy(outTime
, "20");
347 strcpy(outTime
, "19");
349 memmove(outTime
+ 2, inStr
, inStrLen
- 1); // don't copy the Z
352 case CSSM_TIME_STRLEN
:
353 memmove(outTime
, inStr
, inStrLen
); // trivial case
355 case GENERALIZED_TIME_STRLEN
:
356 memmove(outTime
, inStr
, inStrLen
- 1); // don't copy the Z
362 outTime
[CSSM_TIME_STRLEN
] = '\0';