2 * Copyright (c) 2002,2011-2012,2014 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
);
200 /* UTC - 2 year digits - code which parses this assumes that
201 * (2-digit) years between 0 and 49 are in century 21 */
202 if(utc
.tm_year
>= 100) {
205 sprintf(outStr
, "%02d%02d%02d%02d%02d%02dZ",
206 utc
.tm_year
/* + 1900 */, utc
.tm_mon
+ 1,
207 utc
.tm_mday
, utc
.tm_hour
, utc
.tm_min
, utc
.tm_sec
);
210 sprintf(outStr
, "%04d%02d%02d%02d%02d%02dZ",
211 /* note year is relative to 1900, hopefully it'll
212 * have four valid digits! */
213 utc
.tm_year
+ 1900, utc
.tm_mon
+ 1,
214 utc
.tm_mday
, utc
.tm_hour
, utc
.tm_min
, utc
.tm_sec
);
217 sprintf(outStr
, "%04d%02d%02d%02d%02d%02d",
218 /* note year is relative to 1900, hopefully it'll have
219 * four valid digits! */
220 utc
.tm_year
+ 1900, utc
.tm_mon
+ 1,
221 utc
.tm_mday
, utc
.tm_hour
, utc
.tm_min
, utc
.tm_sec
);
228 * Convert a CSSM_X509_TIME, which can be in any of three forms (UTC,
229 * generalized, or CSSM_TIMESTRING) into a CSSM_TIMESTRING. Caller
230 * must free() the result. Returns NULL if x509time is badly formed.
232 char *cuX509TimeToCssmTimestring(
233 const CSSM_X509_TIME
*x509Time
,
234 unsigned *rtnLen
) // for caller's convenience
236 int len
= (int)x509Time
->time
.Length
;
237 const char *inStr
= (char *)x509Time
->time
.Data
;
238 // not NULL terminated!
242 if((len
== 0) || (inStr
== NULL
)) {
245 rtn
= (char *)malloc(CSSM_TIME_STRLEN
+ 1);
248 case UTC_TIME_STRLEN
:
250 /* infer century and prepend to output */
259 * 0 <= year < 50 : assume century 21
260 * 50 <= year < 70 : illegal per PKIX
261 * 70 < year <= 99 : assume century 20
275 memmove(rtn
+ 2, inStr
, len
- 1); // don't copy the Z
278 case CSSM_TIME_STRLEN
:
279 memmove(rtn
, inStr
, len
); // trivial case
281 case GENERALIZED_TIME_STRLEN
:
282 memmove(rtn
, inStr
, len
- 1); // don't copy the Z
289 rtn
[CSSM_TIME_STRLEN
] = '\0';
290 *rtnLen
= CSSM_TIME_STRLEN
;