]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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 <pthread.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 = 0; | |
41 | unsigned noSeconds = 0; | |
427c49bc | 42 | int x; |
b1ab9ed8 A |
43 | unsigned i; |
44 | char *cp; | |
45 | ||
46 | if((str == NULL) || (len == 0) || (tmp == NULL)) { | |
47 | return 1; | |
48 | } | |
49 | ||
50 | /* tolerate NULL terminated or not */ | |
51 | if(str[len - 1] == '\0') { | |
52 | len--; | |
53 | } | |
54 | switch(len) { | |
55 | case UTC_TIME_NOSEC_LEN: // 2-digit year, no seconds, not y2K compliant | |
56 | isUtc = 1; | |
57 | noSeconds = 1; | |
58 | break; | |
59 | case UTC_TIME_STRLEN: // 2-digit year, not Y2K compliant | |
60 | isUtc = 1; | |
61 | break; | |
62 | case GENERALIZED_TIME_STRLEN: // 4-digit year | |
63 | break; | |
64 | default: // unknown format | |
65 | return 1; | |
66 | } | |
67 | ||
68 | cp = (char *)str; | |
69 | ||
70 | /* check that all characters except last are digits */ | |
71 | for(i=0; i<(len - 1); i++) { | |
72 | if ( !(isdigit(cp[i])) ) { | |
73 | return 1; | |
74 | } | |
75 | } | |
76 | ||
77 | /* check last character is a 'Z' */ | |
78 | if(cp[len - 1] != 'Z' ) { | |
79 | return 1; | |
80 | } | |
81 | ||
82 | /* YEAR */ | |
83 | szTemp[0] = *cp++; | |
84 | szTemp[1] = *cp++; | |
85 | if(!isUtc) { | |
86 | /* two more digits */ | |
87 | szTemp[2] = *cp++; | |
88 | szTemp[3] = *cp++; | |
89 | szTemp[4] = '\0'; | |
90 | } | |
91 | else { | |
92 | szTemp[2] = '\0'; | |
93 | } | |
94 | x = atoi( szTemp ); | |
95 | if(isUtc) { | |
96 | /* | |
97 | * 2-digit year. | |
98 | * 0 <= year < 50 : assume century 21 | |
99 | * 50 <= year < 70 : illegal per PKIX, though we tolerate | |
100 | * 70 < year <= 99 : assume century 20 | |
101 | */ | |
102 | if(x < 50) { | |
103 | x += 2000; | |
104 | } | |
105 | /* | |
106 | else if(x < 70) { | |
107 | return 1; | |
108 | } | |
109 | */ | |
110 | else { | |
111 | /* century 20 */ | |
112 | x += 1900; | |
113 | } | |
114 | } | |
115 | /* by definition - tm_year is year - 1900 */ | |
116 | tmp->tm_year = x - 1900; | |
117 | ||
118 | /* MONTH */ | |
119 | szTemp[0] = *cp++; | |
120 | szTemp[1] = *cp++; | |
121 | szTemp[2] = '\0'; | |
122 | x = atoi( szTemp ); | |
123 | /* in the string, months are from 1 to 12 */ | |
124 | if((x > 12) || (x <= 0)) { | |
125 | return 1; | |
126 | } | |
127 | /* in a tm, 0 to 11 */ | |
128 | tmp->tm_mon = x - 1; | |
129 | ||
130 | /* DAY */ | |
131 | szTemp[0] = *cp++; | |
132 | szTemp[1] = *cp++; | |
133 | szTemp[2] = '\0'; | |
134 | x = atoi( szTemp ); | |
135 | /* 1..31 in both formats */ | |
136 | if((x > 31) || (x <= 0)) { | |
137 | return 1; | |
138 | } | |
139 | tmp->tm_mday = x; | |
140 | ||
141 | /* HOUR */ | |
142 | szTemp[0] = *cp++; | |
143 | szTemp[1] = *cp++; | |
144 | szTemp[2] = '\0'; | |
145 | x = atoi( szTemp ); | |
146 | if((x > 23) || (x < 0)) { | |
147 | return 1; | |
148 | } | |
149 | tmp->tm_hour = x; | |
150 | ||
151 | /* MINUTE */ | |
152 | szTemp[0] = *cp++; | |
153 | szTemp[1] = *cp++; | |
154 | szTemp[2] = '\0'; | |
155 | x = atoi( szTemp ); | |
156 | if((x > 59) || (x < 0)) { | |
157 | return 1; | |
158 | } | |
159 | tmp->tm_min = x; | |
160 | ||
161 | /* SECOND */ | |
162 | if(noSeconds) { | |
163 | tmp->tm_sec = 0; | |
164 | } | |
165 | else { | |
166 | szTemp[0] = *cp++; | |
167 | szTemp[1] = *cp++; | |
168 | szTemp[2] = '\0'; | |
169 | x = atoi( szTemp ); | |
170 | if((x > 59) || (x < 0)) { | |
171 | return 1; | |
172 | } | |
173 | tmp->tm_sec = x; | |
174 | } | |
175 | return 0; | |
176 | } | |
177 | ||
178 | #define MAX_TIME_STR_LEN 30 | |
179 | ||
180 | /* protects time(), gmtime() */ | |
181 | static pthread_mutex_t timeMutex = PTHREAD_MUTEX_INITIALIZER; | |
182 | ||
183 | char *cuTimeAtNowPlus(int secFromNow, | |
184 | timeSpec spec) | |
185 | { | |
186 | struct tm utc; | |
187 | char *outStr; | |
188 | time_t baseTime; | |
189 | ||
190 | pthread_mutex_lock(&timeMutex); | |
191 | baseTime = time(NULL); | |
192 | baseTime += (time_t)secFromNow; | |
193 | utc = *gmtime(&baseTime); | |
194 | pthread_mutex_unlock(&timeMutex); | |
195 | ||
196 | outStr = (char *)APP_MALLOC(MAX_TIME_STR_LEN); | |
197 | ||
198 | switch(spec) { | |
199 | case TIME_UTC: | |
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) { | |
203 | utc.tm_year -= 100; | |
204 | } | |
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); | |
208 | break; | |
209 | case TIME_GEN: | |
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); | |
215 | break; | |
216 | case TIME_CSSM: | |
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); | |
222 | break; | |
223 | } | |
224 | return outStr; | |
225 | } | |
226 | ||
227 | /* | |
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. | |
231 | */ | |
232 | char *cuX509TimeToCssmTimestring( | |
233 | const CSSM_X509_TIME *x509Time, | |
234 | unsigned *rtnLen) // for caller's convenience | |
235 | { | |
427c49bc | 236 | int len = (int)x509Time->time.Length; |
b1ab9ed8 A |
237 | const char *inStr = (char *)x509Time->time.Data; |
238 | // not NULL terminated! | |
239 | char *rtn; | |
240 | ||
241 | *rtnLen = 0; | |
242 | if((len == 0) || (inStr == NULL)) { | |
243 | return NULL; | |
244 | } | |
245 | rtn = (char *)malloc(CSSM_TIME_STRLEN + 1); | |
246 | rtn[0] = '\0'; | |
247 | switch(len) { | |
248 | case UTC_TIME_STRLEN: | |
249 | { | |
250 | /* infer century and prepend to output */ | |
251 | char tmp[3]; | |
252 | int year; | |
253 | tmp[0] = inStr[0]; | |
254 | tmp[1] = inStr[1]; | |
255 | tmp[2] = '\0'; | |
256 | year = atoi(tmp); | |
257 | ||
258 | /* | |
259 | * 0 <= year < 50 : assume century 21 | |
260 | * 50 <= year < 70 : illegal per PKIX | |
261 | * 70 < year <= 99 : assume century 20 | |
262 | */ | |
263 | if(year < 50) { | |
264 | /* century 21 */ | |
265 | strcpy(rtn, "20"); | |
266 | } | |
267 | else if(year < 70) { | |
268 | free(rtn); | |
269 | return NULL; | |
270 | } | |
271 | else { | |
272 | /* century 20 */ | |
273 | strcpy(rtn, "19"); | |
274 | } | |
275 | memmove(rtn + 2, inStr, len - 1); // don't copy the Z | |
276 | break; | |
277 | } | |
278 | case CSSM_TIME_STRLEN: | |
279 | memmove(rtn, inStr, len); // trivial case | |
280 | break; | |
281 | case GENERALIZED_TIME_STRLEN: | |
282 | memmove(rtn, inStr, len - 1); // don't copy the Z | |
283 | break; | |
284 | ||
285 | default: | |
286 | free(rtn); | |
287 | return NULL; | |
288 | } | |
289 | rtn[CSSM_TIME_STRLEN] = '\0'; | |
290 | *rtnLen = CSSM_TIME_STRLEN; | |
291 | return rtn; | |
292 | } | |
293 |