2 * Copyright (c) 2002,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.
19 * cuTimeStr.cpp - time string routines
21 #include "cuTimeStr.h"
22 #include "cuCdsaUtils.h"
30 * Given a string containing either a UTC-style or "generalized time"
31 * time string, convert to a struct tm (in GMT/UTC). Returns nonzero on
41 unsigned noSeconds
= 0;
46 if((str
== NULL
) || (len
== 0) || (tmp
== NULL
)) {
50 /* tolerate NULL terminated or not */
51 if(str
[len
- 1] == '\0') {
55 case UTC_TIME_NOSEC_LEN
: // 2-digit year, no seconds, not y2K compliant
59 case UTC_TIME_STRLEN
: // 2-digit year, not Y2K compliant
62 case GENERALIZED_TIME_STRLEN
: // 4-digit year
64 default: // unknown format
70 /* check that all characters except last are digits */
71 for(i
=0; i
<(len
- 1); i
++) {
72 if ( !(isdigit(cp
[i
])) ) {
77 /* check last character is a 'Z' */
78 if(cp
[len
- 1] != 'Z' ) {
98 * 0 <= year < 50 : assume century 21
99 * 50 <= year < 70 : illegal per PKIX, though we tolerate
100 * 70 < year <= 99 : assume century 20
115 /* by definition - tm_year is year - 1900 */
116 tmp
->tm_year
= x
- 1900;
123 /* in the string, months are from 1 to 12 */
124 if((x
> 12) || (x
<= 0)) {
127 /* in a tm, 0 to 11 */
135 /* 1..31 in both formats */
136 if((x
> 31) || (x
<= 0)) {
146 if((x
> 23) || (x
< 0)) {
156 if((x
> 59) || (x
< 0)) {
170 if((x
> 59) || (x
< 0)) {
178 #define MAX_TIME_STR_LEN 30
180 /* protects time(), gmtime() */
181 static pthread_mutex_t timeMutex
= PTHREAD_MUTEX_INITIALIZER
;
183 char *cuTimeAtNowPlus(int secFromNow
,
190 pthread_mutex_lock(&timeMutex
);
191 baseTime
= time(NULL
);
192 baseTime
+= (time_t)secFromNow
;
193 utc
= *gmtime(&baseTime
);
194 pthread_mutex_unlock(&timeMutex
);
196 outStr
= (char *)APP_MALLOC(MAX_TIME_STR_LEN
);
198 /* Check for legacy value of 1 */
199 if (spec
== CU_TIME_LEGACY
) {
201 /* time.h has defined TIME_UTC=1, so legacy caller
202 actually wants TIME_UTC, not TIME_CSSM. */
212 /* UTC - 2 year digits - code which parses this assumes that
213 * (2-digit) years between 0 and 49 are in century 21 */
214 if(utc
.tm_year
>= 100) {
217 sprintf(outStr
, "%02d%02d%02d%02d%02d%02dZ",
218 utc
.tm_year
/* + 1900 */, utc
.tm_mon
+ 1,
219 utc
.tm_mday
, utc
.tm_hour
, utc
.tm_min
, utc
.tm_sec
);
222 sprintf(outStr
, "%04d%02d%02d%02d%02d%02dZ",
223 /* note year is relative to 1900, hopefully it'll
224 * have four valid digits! */
225 utc
.tm_year
+ 1900, utc
.tm_mon
+ 1,
226 utc
.tm_mday
, utc
.tm_hour
, utc
.tm_min
, utc
.tm_sec
);
229 sprintf(outStr
, "%04d%02d%02d%02d%02d%02d",
230 /* note year is relative to 1900, hopefully it'll have
231 * four valid digits! */
232 utc
.tm_year
+ 1900, utc
.tm_mon
+ 1,
233 utc
.tm_mday
, utc
.tm_hour
, utc
.tm_min
, utc
.tm_sec
);
240 * Convert a CSSM_X509_TIME, which can be in any of three forms (UTC,
241 * generalized, or CSSM_TIMESTRING) into a CSSM_TIMESTRING. Caller
242 * must free() the result. Returns NULL if x509time is badly formed.
244 char *cuX509TimeToCssmTimestring(
245 const CSSM_X509_TIME
*x509Time
,
246 unsigned *rtnLen
) // for caller's convenience
248 int len
= (int)x509Time
->time
.Length
;
249 const char *inStr
= (char *)x509Time
->time
.Data
;
250 // not NULL terminated!
254 if((len
== 0) || (inStr
== NULL
)) {
257 rtn
= (char *)malloc(CSSM_TIME_STRLEN
+ 1);
260 case UTC_TIME_STRLEN
:
262 /* infer century and prepend to output */
271 * 0 <= year < 50 : assume century 21
272 * 50 <= year < 70 : illegal per PKIX
273 * 70 < year <= 99 : assume century 20
287 memmove(rtn
+ 2, inStr
, len
- 1); // don't copy the Z
290 case CSSM_TIME_STRLEN
:
291 memmove(rtn
, inStr
, len
); // trivial case
293 case GENERALIZED_TIME_STRLEN
:
294 memmove(rtn
, inStr
, len
- 1); // don't copy the Z
301 rtn
[CSSM_TIME_STRLEN
] = '\0';
302 *rtnLen
= CSSM_TIME_STRLEN
;