]> git.saurik.com Git - apple/security.git/blob - CdsaUtils/cuTimeStr.cpp
Security-176.tar.gz
[apple/security.git] / CdsaUtils / cuTimeStr.cpp
1 /*
2 * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18 /*
19 * cuTimeStr.cpp - time string routines
20 */
21 #include "cuTimeStr.h"
22 #include "cuCdsaUtils.h"
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <Security/threading.h>
28
29 /*
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
32 * error.
33 */
34 int cuTimeStringToTm(
35 const char *str,
36 unsigned len,
37 struct tm *tmp)
38 {
39 char szTemp[5];
40 unsigned isUtc;
41 unsigned x;
42 unsigned i;
43 char *cp;
44
45 if((str == NULL) || (len == 0) || (tmp == NULL)) {
46 return 1;
47 }
48
49 /* tolerate NULL terminated or not */
50 if(str[len - 1] == '\0') {
51 len--;
52 }
53 switch(len) {
54 case UTC_TIME_STRLEN: // 2-digit year, not Y2K compliant
55 isUtc = 1;
56 break;
57 case GENERALIZED_TIME_STRLEN: // 4-digit year
58 isUtc = 0;
59 break;
60 default: // unknown format
61 return 1;
62 }
63
64 cp = (char *)str;
65
66 /* check that all characters except last are digits */
67 for(i=0; i<(len - 1); i++) {
68 if ( !(isdigit(cp[i])) ) {
69 return 1;
70 }
71 }
72
73 /* check last character is a 'Z' */
74 if(cp[len - 1] != 'Z' ) {
75 return 1;
76 }
77
78 /* YEAR */
79 szTemp[0] = *cp++;
80 szTemp[1] = *cp++;
81 if(!isUtc) {
82 /* two more digits */
83 szTemp[2] = *cp++;
84 szTemp[3] = *cp++;
85 szTemp[4] = '\0';
86 }
87 else {
88 szTemp[2] = '\0';
89 }
90 x = atoi( szTemp );
91 if(isUtc) {
92 /*
93 * 2-digit year.
94 * 0 <= year < 50 : assume century 21
95 * 50 <= year < 70 : illegal per PKIX, though we tolerate
96 * 70 < year <= 99 : assume century 20
97 */
98 if(x < 50) {
99 x += 2000;
100 }
101 /*
102 else if(x < 70) {
103 return 1;
104 }
105 */
106 else {
107 /* century 20 */
108 x += 1900;
109 }
110 }
111 /* by definition - tm_year is year - 1900 */
112 tmp->tm_year = x - 1900;
113
114 /* MONTH */
115 szTemp[0] = *cp++;
116 szTemp[1] = *cp++;
117 szTemp[2] = '\0';
118 x = atoi( szTemp );
119 /* in the string, months are from 1 to 12 */
120 if((x > 12) || (x <= 0)) {
121 return 1;
122 }
123 /* in a tm, 0 to 11 */
124 tmp->tm_mon = x - 1;
125
126 /* DAY */
127 szTemp[0] = *cp++;
128 szTemp[1] = *cp++;
129 szTemp[2] = '\0';
130 x = atoi( szTemp );
131 /* 1..31 in both formats */
132 if((x > 31) || (x <= 0)) {
133 return 1;
134 }
135 tmp->tm_mday = x;
136
137 /* HOUR */
138 szTemp[0] = *cp++;
139 szTemp[1] = *cp++;
140 szTemp[2] = '\0';
141 x = atoi( szTemp );
142 if((x > 23) || (x < 0)) {
143 return 1;
144 }
145 tmp->tm_hour = x;
146
147 /* MINUTE */
148 szTemp[0] = *cp++;
149 szTemp[1] = *cp++;
150 szTemp[2] = '\0';
151 x = atoi( szTemp );
152 if((x > 59) || (x < 0)) {
153 return 1;
154 }
155 tmp->tm_min = x;
156
157 /* SECOND */
158 szTemp[0] = *cp++;
159 szTemp[1] = *cp++;
160 szTemp[2] = '\0';
161 x = atoi( szTemp );
162 if((x > 59) || (x < 0)) {
163 return 1;
164 }
165 tmp->tm_sec = x;
166 return 0;
167 }
168
169 #define MAX_TIME_STR_LEN 30
170
171 static Mutex timeMutex; // protects time(), gmtime()
172
173 char *cuTimeAtNowPlus(int secFromNow,
174 timeSpec spec)
175 {
176 struct tm utc;
177 char *outStr;
178 time_t baseTime;
179
180 timeMutex.lock();
181 baseTime = time(NULL);
182 baseTime += (time_t)secFromNow;
183 utc = *gmtime(&baseTime);
184 timeMutex.unlock();
185
186 outStr = (char *)APP_MALLOC(MAX_TIME_STR_LEN);
187
188 switch(spec) {
189 case TIME_UTC:
190 /* UTC - 2 year digits - code which parses this assumes that
191 * (2-digit) years between 0 and 49 are in century 21 */
192 if(utc.tm_year >= 100) {
193 utc.tm_year -= 100;
194 }
195 sprintf(outStr, "%02d%02d%02d%02d%02d%02dZ",
196 utc.tm_year /* + 1900 */, utc.tm_mon + 1,
197 utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec);
198 break;
199 case TIME_GEN:
200 sprintf(outStr, "%04d%02d%02d%02d%02d%02dZ",
201 /* note year is relative to 1900, hopefully it'll
202 * have four valid digits! */
203 utc.tm_year + 1900, utc.tm_mon + 1,
204 utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec);
205 break;
206 case TIME_CSSM:
207 sprintf(outStr, "%04d%02d%02d%02d%02d%02d",
208 /* note year is relative to 1900, hopefully it'll have
209 * four valid digits! */
210 utc.tm_year + 1900, utc.tm_mon + 1,
211 utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec);
212 break;
213 }
214 return outStr;
215 }
216
217 /*
218 * Convert a CSSM_X509_TIME, which can be in any of three forms (UTC,
219 * generalized, or CSSM_TIMESTRING) into a CSSM_TIMESTRING. Caller
220 * must free() the result. Returns NULL if x509time is badly formed.
221 */
222 char *cuX509TimeToCssmTimestring(
223 const CSSM_X509_TIME *x509Time,
224 unsigned *rtnLen) // for caller's convenience
225 {
226 int len = x509Time->time.Length;
227 const char *inStr = (char *)x509Time->time.Data;
228 // not NULL terminated!
229 char *rtn;
230
231 *rtnLen = 0;
232 if((len == 0) || (inStr == NULL)) {
233 return NULL;
234 }
235 rtn = (char *)malloc(CSSM_TIME_STRLEN + 1);
236 rtn[0] = '\0';
237 switch(len) {
238 case UTC_TIME_STRLEN:
239 {
240 /* infer century and prepend to output */
241 char tmp[3];
242 int year;
243 tmp[0] = inStr[0];
244 tmp[1] = inStr[1];
245 tmp[2] = '\0';
246 year = atoi(tmp);
247
248 /*
249 * 0 <= year < 50 : assume century 21
250 * 50 <= year < 70 : illegal per PKIX
251 * 70 < year <= 99 : assume century 20
252 */
253 if(year < 50) {
254 /* century 21 */
255 strcpy(rtn, "20");
256 }
257 else if(year < 70) {
258 free(rtn);
259 return NULL;
260 }
261 else {
262 /* century 20 */
263 strcpy(rtn, "19");
264 }
265 memmove(rtn + 2, inStr, len - 1); // don't copy the Z
266 break;
267 }
268 case CSSM_TIME_STRLEN:
269 memmove(rtn, inStr, len); // trivial case
270 break;
271 case GENERALIZED_TIME_STRLEN:
272 memmove(rtn, inStr, len - 1); // don't copy the Z
273 break;
274
275 default:
276 free(rtn);
277 return NULL;
278 }
279 rtn[CSSM_TIME_STRLEN] = '\0';
280 *rtnLen = CSSM_TIME_STRLEN;
281 return rtn;
282 }
283