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