]> git.saurik.com Git - apple/security.git/blob - AppleX509TP/tpTime.c
Security-179.tar.gz
[apple/security.git] / AppleX509TP / tpTime.c
1 /*
2 * Copyright (c) 2000-2001 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 /*
20 * tpTime.c - cert related time functions
21 *
22 * Written 10/10/2000 by Doug Mitchell.
23 */
24
25 #include "tpTime.h"
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <ctype.h>
30 #include <stdbool.h>
31
32 /*
33 * Given a string containing either a UTC-style or "generalized time"
34 * time string, convert to a struct tm (in GMT/UTC). Returns nonzero on
35 * error.
36 */
37 int timeStringToTm(
38 const char *str,
39 unsigned len,
40 struct tm *tmp)
41 {
42 char szTemp[5];
43 bool isUtc = false; // 2-digit year
44 bool isCssmTime = false; // no trailing 'Z'
45 unsigned x;
46 unsigned i;
47 char *cp;
48
49 if((str == NULL) || (len == 0) || (tmp == NULL)) {
50 return 1;
51 }
52
53 /* tolerate NULL terminated or not */
54 if(str[len - 1] == '\0') {
55 len--;
56 }
57 switch(len) {
58 case UTC_TIME_STRLEN: // 2-digit year, not Y2K compliant
59 isUtc = true;
60 break;
61 case CSSM_TIME_STRLEN:
62 isCssmTime = true;
63 break;
64 case GENERALIZED_TIME_STRLEN: // 4-digit year
65 break;
66 default: // unknown format
67 return 1;
68 }
69
70 cp = (char *)str;
71
72 /* check that all characters except last are digits */
73 for(i=0; i<(len - 1); i++) {
74 if ( !(isdigit(cp[i])) ) {
75 return 1;
76 }
77 }
78
79 /* check last character is a 'Z' or digit as appropriate */
80 if(isCssmTime) {
81 if(!isdigit(cp[len - 1])) {
82 return 1;
83 }
84 }
85 else {
86 if(cp[len - 1] != 'Z' ) {
87 return 1;
88 }
89 }
90
91 /* YEAR */
92 szTemp[0] = *cp++;
93 szTemp[1] = *cp++;
94 if(!isUtc) {
95 /* two more digits */
96 szTemp[2] = *cp++;
97 szTemp[3] = *cp++;
98 szTemp[4] = '\0';
99 }
100 else {
101 szTemp[2] = '\0';
102 }
103 x = atoi( szTemp );
104 if(isUtc) {
105 /*
106 * 2-digit year.
107 * 0 <= year < 50 : assume century 21
108 * 50 <= year < 70 : illegal per PKIX
109 * ...though we allow this as of 10/10/02...dmitch
110 * 70 < year <= 99 : assume century 20
111 */
112 if(x < 50) {
113 x += 2000;
114 }
115 /*
116 else if(x < 70) {
117 return 1;
118 }
119 */
120 else {
121 /* century 20 */
122 x += 1900;
123 }
124 }
125 /* by definition - tm_year is year - 1900 */
126 tmp->tm_year = x - 1900;
127
128 /* MONTH */
129 szTemp[0] = *cp++;
130 szTemp[1] = *cp++;
131 szTemp[2] = '\0';
132 x = atoi( szTemp );
133 /* in the string, months are from 1 to 12 */
134 if((x > 12) || (x <= 0)) {
135 return 1;
136 }
137 /* in a tm, 0 to 11 */
138 tmp->tm_mon = x - 1;
139
140 /* DAY */
141 szTemp[0] = *cp++;
142 szTemp[1] = *cp++;
143 szTemp[2] = '\0';
144 x = atoi( szTemp );
145 /* 1..31 in both formats */
146 if((x > 31) || (x <= 0)) {
147 return 1;
148 }
149 tmp->tm_mday = x;
150
151 /* HOUR */
152 szTemp[0] = *cp++;
153 szTemp[1] = *cp++;
154 szTemp[2] = '\0';
155 x = atoi( szTemp );
156 if((x > 23) || (x < 0)) {
157 return 1;
158 }
159 tmp->tm_hour = x;
160
161 /* MINUTE */
162 szTemp[0] = *cp++;
163 szTemp[1] = *cp++;
164 szTemp[2] = '\0';
165 x = atoi( szTemp );
166 if((x > 59) || (x < 0)) {
167 return 1;
168 }
169 tmp->tm_min = x;
170
171 /* SECOND */
172 szTemp[0] = *cp++;
173 szTemp[1] = *cp++;
174 szTemp[2] = '\0';
175 x = atoi( szTemp );
176 if((x > 59) || (x < 0)) {
177 return 1;
178 }
179 tmp->tm_sec = x;
180 return 0;
181 }
182
183 /*
184 * Return current GMT time as a struct tm.
185 * Caller must hold tpTimeLock.
186 */
187 void nowTime(
188 struct tm *now)
189 {
190 time_t nowTime = time(NULL);
191 *now = *gmtime(&nowTime);
192 }
193
194 /*
195 * Compare two times. Assumes they're both in GMT. Returns:
196 * -1 if t1 < t2
197 * 0 if t1 == t2
198 * 1 if t1 > t2
199 */
200 int compareTimes(
201 const struct tm *t1,
202 const struct tm *t2)
203 {
204 if(t1->tm_year > t2->tm_year) {
205 return 1;
206 }
207 else if(t1->tm_year < t2->tm_year) {
208 return -1;
209 }
210 /* year equal */
211 else if(t1->tm_mon > t2->tm_mon) {
212 return 1;
213 }
214 else if(t1->tm_mon < t2->tm_mon) {
215 return -1;
216 }
217 /* month equal */
218 else if(t1->tm_mday > t2->tm_mday) {
219 return 1;
220 }
221 else if(t1->tm_mday < t2->tm_mday) {
222 return -1;
223 }
224 /* day of month equal */
225 else if(t1->tm_hour > t2->tm_hour) {
226 return 1;
227 }
228 else if(t1->tm_hour < t2->tm_hour) {
229 return -1;
230 }
231 /* hour equal */
232 else if(t1->tm_min > t2->tm_min) {
233 return 1;
234 }
235 else if(t1->tm_min < t2->tm_min) {
236 return -1;
237 }
238 /* minute equal */
239 else if(t1->tm_sec > t2->tm_sec) {
240 return 1;
241 }
242 else if(t1->tm_sec < t2->tm_sec) {
243 return -1;
244 }
245 /* equal */
246 return 0;
247 }
248
249 /*
250 * Create a time string, in either UTC (2-digit) or or Generalized (4-digit)
251 * year format. Caller mallocs the output string whose length is at least
252 * (UTC_TIME_STRLEN+1), (GENERALIZED_TIME_STRLEN+1), or (CSSM_TIME_STRLEN+1)
253 * respectively. Caller must hold tpTimeLock.
254 */
255 void timeAtNowPlus(unsigned secFromNow,
256 TpTimeSpec timeSpec,
257 char *outStr)
258 {
259 struct tm utc;
260 time_t baseTime;
261
262 baseTime = time(NULL);
263 baseTime += (time_t)secFromNow;
264 utc = *gmtime(&baseTime);
265
266 switch(timeSpec) {
267 case TIME_UTC:
268 /* UTC - 2 year digits - code which parses this assumes that
269 * (2-digit) years between 0 and 49 are in century 21 */
270 if(utc.tm_year >= 100) {
271 utc.tm_year -= 100;
272 }
273 sprintf(outStr, "%02d%02d%02d%02d%02d%02dZ",
274 utc.tm_year /* + 1900 */, utc.tm_mon + 1,
275 utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec);
276 break;
277 case TIME_GEN:
278 sprintf(outStr, "%04d%02d%02d%02d%02d%02dZ",
279 /* note year is relative to 1900, hopefully it'll have
280 * four valid digits! */
281 utc.tm_year + 1900, utc.tm_mon + 1,
282 utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec);
283 break;
284 case TIME_CSSM:
285 sprintf(outStr, "%04d%02d%02d%02d%02d%02d",
286 /* note year is relative to 1900, hopefully it'll have
287 * four valid digits! */
288 utc.tm_year + 1900, utc.tm_mon + 1,
289 utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec);
290 break;
291 }
292 }
293
294 /*
295 * Convert a time string, which can be in any of three forms (UTC,
296 * generalized, or CSSM_TIMESTRING) into a CSSM_TIMESTRING. Caller
297 * mallocs the result, which must be at least (CSSM_TIME_STRLEN+1) bytes.
298 * Returns nonzero if incoming time string is badly formed.
299 */
300 int tpTimeToCssmTimestring(
301 const char *inStr, // not necessarily NULL terminated
302 unsigned inStrLen, // not including possible NULL
303 char *outTime)
304 {
305 if((inStrLen == 0) || (inStr == NULL)) {
306 return 1;
307 }
308 outTime[0] = '\0';
309 switch(inStrLen) {
310 case UTC_TIME_STRLEN:
311 {
312 /* infer century and prepend to output */
313 char tmp[3];
314 int year;
315 tmp[0] = inStr[0];
316 tmp[1] = inStr[1];
317 tmp[2] = '\0';
318 year = atoi(tmp);
319
320 /*
321 * 0 <= year < 50 : assume century 21
322 * 50 <= year < 70 : illegal per PKIX
323 * 70 < year <= 99 : assume century 20
324 */
325 if(year < 50) {
326 /* century 21 */
327 strcpy(outTime, "20");
328 }
329 else if(year < 70) {
330 return 1;
331 }
332 else {
333 /* century 20 */
334 strcpy(outTime, "19");
335 }
336 memmove(outTime + 2, inStr, inStrLen - 1); // don't copy the Z
337 break;
338 }
339 case CSSM_TIME_STRLEN:
340 memmove(outTime, inStr, inStrLen); // trivial case
341 break;
342 case GENERALIZED_TIME_STRLEN:
343 memmove(outTime, inStr, inStrLen - 1); // don't copy the Z
344 break;
345
346 default:
347 return 1;
348 }
349 outTime[CSSM_TIME_STRLEN] = '\0';
350 return 0;
351 }
352