]> git.saurik.com Git - apple/security.git/blob - Keychain/cssmdatetime.cpp
22d5c1cdd0bff64e18e19b44e1118be91d2f0a57
[apple/security.git] / Keychain / cssmdatetime.cpp
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 File: cssmdatetime.cpp
21
22 Contains: CSSM date and time utilities for the Mac
23
24 Written by: The Hindsight team
25
26 Copyright: © 1997-2000 by Apple Computer, Inc., all rights reserved.
27
28 Change History (most recent first):
29
30 To Do:
31 */
32
33 #ifdef __MWERKS__
34 #define _CPP_CSSM_DATE_TIME_UTILS
35 #endif
36
37 #include "cssmdatetime.h"
38
39 #include <string.h>
40 #include <stdio.h>
41 #include <Security/utilities.h>
42 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
43 #include <CoreFoundation/CFDate.h>
44 #include <CoreFoundation/CFTimeZone.h>
45 #include <ctype.h>
46
47 namespace Security
48 {
49
50 namespace CSSMDateTimeUtils
51 {
52
53 #define MAX_TIME_STR_LEN 30
54 #define UTC_TIME_STRLEN 13
55 #define GENERALIZED_TIME_STRLEN 15
56
57
58 void
59 GetCurrentMacLongDateTime(SInt64 &outMacDate)
60 {
61 CFTimeZoneRef timeZone = CFTimeZoneCopyDefault();
62 CFAbsoluteTime absTime = CFAbsoluteTimeGetCurrent();
63 absTime += CFTimeZoneGetSecondsFromGMT(timeZone, absTime);
64 CFRelease(timeZone);
65 outMacDate = SInt64(double(absTime + kCFAbsoluteTimeIntervalSince1904));
66 }
67
68 void
69 TimeStringToMacSeconds (const CSSM_DATA &inUTCTime, UInt32 &ioMacDate)
70 {
71 SInt64 ldt;
72 TimeStringToMacLongDateTime(inUTCTime, ldt);
73 ioMacDate = UInt32(ldt);
74 }
75
76 /*
77 * Given a CSSM_DATA containing either a UTC-style or "generalized time"
78 * time string, convert to 32-bit Mac time in seconds.
79 * Returns nonzero on error.
80 */
81 void
82 TimeStringToMacLongDateTime (const CSSM_DATA &inUTCTime, SInt64 &outMacDate)
83 {
84 char szTemp[5];
85 unsigned len;
86 int isUtc;
87 sint32 x;
88 sint32 i;
89 char *cp;
90
91 CFGregorianDate date;
92 ::memset( &date, 0, sizeof(date) );
93
94 if ((inUTCTime.Data == NULL) || (inUTCTime.Length == 0))
95 {
96 MacOSError::throwMe(paramErr);
97 }
98
99 /* tolerate NULL terminated or not */
100 len = inUTCTime.Length;
101 if (inUTCTime.Data[len - 1] == '\0')
102 len--;
103
104 switch(len)
105 {
106 case UTC_TIME_STRLEN: // 2-digit year, not Y2K compliant
107 isUtc = 1;
108 break;
109 case GENERALIZED_TIME_STRLEN: // 4-digit year
110 isUtc = 0;
111 break;
112 default: // unknown format
113 MacOSError::throwMe(paramErr);
114 }
115
116 cp = (char *)inUTCTime.Data;
117
118 /* check that all characters except last are digits */
119 for(i=0; i<(sint32)(len - 1); i++) {
120 if ( !(isdigit(cp[i])) ) {
121 MacOSError::throwMe(paramErr);
122 }
123 }
124
125 /* check last character is a 'Z' */
126 if(cp[len - 1] != 'Z' ) {
127 MacOSError::throwMe(paramErr);
128 }
129
130 /* YEAR */
131 szTemp[0] = *cp++;
132 szTemp[1] = *cp++;
133 if(!isUtc) {
134 /* two more digits */
135 szTemp[2] = *cp++;
136 szTemp[3] = *cp++;
137 szTemp[4] = '\0';
138 }
139 else {
140 szTemp[2] = '\0';
141 }
142 x = atoi( szTemp );
143 if(isUtc) {
144 /*
145 * 2-digit year.
146 * 0 <= year <= 50 : assume century 21
147 * 50 < year < 70 : illegal per PKIX
148 * 70 < year <= 99 : assume century 20
149 */
150 if(x <= 50) {
151 x += 100;
152 }
153 else if(x < 70) {
154 MacOSError::throwMe(paramErr);
155 }
156 /* else century 20, OK */
157
158 /* bug fix... we need to end up with a 4-digit year! */
159 x += 1900;
160 }
161 /* by definition - tm_year is year - 1900 */
162 //tmp->tm_year = x - 1900;
163 date.year = x;
164
165 /* MONTH */
166 szTemp[0] = *cp++;
167 szTemp[1] = *cp++;
168 szTemp[2] = '\0';
169 x = atoi( szTemp );
170 /* in the string, months are from 1 to 12 */
171 if((x > 12) || (x <= 0)) {
172 MacOSError::throwMe(paramErr);
173 }
174 /* in a tm, 0 to 11 */
175 //tmp->tm_mon = x - 1;
176 date.month = x;
177
178 /* DAY */
179 szTemp[0] = *cp++;
180 szTemp[1] = *cp++;
181 szTemp[2] = '\0';
182 x = atoi( szTemp );
183 /* 1..31 in both formats */
184 if((x > 31) || (x <= 0)) {
185 MacOSError::throwMe(paramErr);
186 }
187 //tmp->tm_mday = x;
188 date.day = x;
189
190 /* HOUR */
191 szTemp[0] = *cp++;
192 szTemp[1] = *cp++;
193 szTemp[2] = '\0';
194 x = atoi( szTemp );
195 if((x > 23) || (x < 0)) {
196 MacOSError::throwMe(paramErr);
197 }
198 //tmp->tm_hour = x;
199 date.hour = x;
200
201 /* MINUTE */
202 szTemp[0] = *cp++;
203 szTemp[1] = *cp++;
204 szTemp[2] = '\0';
205 x = atoi( szTemp );
206 if((x > 59) || (x < 0)) {
207 MacOSError::throwMe(paramErr);
208 }
209 //tmp->tm_min = x;
210 date.minute = x;
211
212 /* SECOND */
213 szTemp[0] = *cp++;
214 szTemp[1] = *cp++;
215 szTemp[2] = '\0';
216 x = atoi( szTemp );
217 if((x > 59) || (x < 0)) {
218 MacOSError::throwMe(paramErr);
219 }
220 //tmp->tm_sec = x;
221 date.second = x;
222
223 CFTimeZoneRef timeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0);
224 CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime(date, timeZone);
225 CFRelease(timeZone);
226
227 // Adjust abstime to local timezone
228 timeZone = CFTimeZoneCopyDefault();
229 absTime += CFTimeZoneGetSecondsFromGMT(timeZone, absTime);
230 CFRelease(timeZone);
231
232 outMacDate = SInt64(double(absTime + kCFAbsoluteTimeIntervalSince1904));
233 }
234
235 void MacSecondsToTimeString(UInt32 inMacDate, UInt32 inLength, void *outData)
236 {
237 SInt64 ldt = SInt64(UInt64(inMacDate));
238 MacLongDateTimeToTimeString(ldt, inLength, outData);
239 }
240
241 void MacLongDateTimeToTimeString(const SInt64 &inMacDate,
242 UInt32 inLength, void *outData)
243 {
244 // @@@ this code is close, but on the fringe case of a daylight savings time it will be off for a little while
245 CFAbsoluteTime absTime = inMacDate - kCFAbsoluteTimeIntervalSince1904;
246
247 // Remove local timezone component from absTime
248 CFTimeZoneRef timeZone = CFTimeZoneCopyDefault();
249 absTime -= CFTimeZoneGetSecondsFromGMT(timeZone, absTime);
250 CFRelease(timeZone);
251
252 timeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0);
253 CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(absTime, timeZone);
254 CFRelease(timeZone);
255
256 if (inLength == 16)
257 {
258 sprintf((char *)(outData), "%04d%02d%02d%02d%02d%02dZ",
259 int(date.year % 10000), date.month, date.day,
260 date.hour, date.minute, int(date.second));
261 }
262 else if (inLength == 14)
263 {
264 /* UTC - 2 year digits - code which parses this assumes that
265 * (2-digit) years between 0 and 49 are in century 21 */
266 sprintf((char *)(outData), "%02d%02d%02d%02d%02d%02dZ",
267 int(date.year % 100), date.month, date.day,
268 date.hour, date.minute, int(date.second));
269 }
270 else
271 MacOSError::throwMe(paramErr);
272 }
273
274 }; // end namespace CSSMDateTimeUtils
275
276 } // end namespace Security