/src/openssl/crypto/o_time.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* crypto/o_time.c */ |
2 | | /* |
3 | | * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project |
4 | | * 2001. |
5 | | */ |
6 | | /* |
7 | | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project |
8 | | * 2008. |
9 | | */ |
10 | | /* ==================================================================== |
11 | | * Copyright (c) 2001 The OpenSSL Project. All rights reserved. |
12 | | * |
13 | | * Redistribution and use in source and binary forms, with or without |
14 | | * modification, are permitted provided that the following conditions |
15 | | * are met: |
16 | | * |
17 | | * 1. Redistributions of source code must retain the above copyright |
18 | | * notice, this list of conditions and the following disclaimer. |
19 | | * |
20 | | * 2. Redistributions in binary form must reproduce the above copyright |
21 | | * notice, this list of conditions and the following disclaimer in |
22 | | * the documentation and/or other materials provided with the |
23 | | * distribution. |
24 | | * |
25 | | * 3. All advertising materials mentioning features or use of this |
26 | | * software must display the following acknowledgment: |
27 | | * "This product includes software developed by the OpenSSL Project |
28 | | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" |
29 | | * |
30 | | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
31 | | * endorse or promote products derived from this software without |
32 | | * prior written permission. For written permission, please contact |
33 | | * licensing@OpenSSL.org. |
34 | | * |
35 | | * 5. Products derived from this software may not be called "OpenSSL" |
36 | | * nor may "OpenSSL" appear in their names without prior written |
37 | | * permission of the OpenSSL Project. |
38 | | * |
39 | | * 6. Redistributions of any form whatsoever must retain the following |
40 | | * acknowledgment: |
41 | | * "This product includes software developed by the OpenSSL Project |
42 | | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" |
43 | | * |
44 | | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
45 | | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
46 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
47 | | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
48 | | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
49 | | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
50 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
51 | | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
52 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
53 | | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
54 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
55 | | * OF THE POSSIBILITY OF SUCH DAMAGE. |
56 | | * ==================================================================== |
57 | | * |
58 | | * This product includes cryptographic software written by Eric Young |
59 | | * (eay@cryptsoft.com). This product includes software written by Tim |
60 | | * Hudson (tjh@cryptsoft.com). |
61 | | * |
62 | | */ |
63 | | |
64 | | #include <openssl/e_os2.h> |
65 | | #include <string.h> |
66 | | #include "o_time.h" |
67 | | |
68 | | #ifdef OPENSSL_SYS_VMS |
69 | | # if __CRTL_VER >= 70000000 && \ |
70 | | (defined _POSIX_C_SOURCE || !defined _ANSI_C_SOURCE) |
71 | | # define VMS_GMTIME_OK |
72 | | # endif |
73 | | # ifndef VMS_GMTIME_OK |
74 | | # include <libdtdef.h> |
75 | | # include <lib$routines.h> |
76 | | # include <lnmdef.h> |
77 | | # include <starlet.h> |
78 | | # include <descrip.h> |
79 | | # include <stdlib.h> |
80 | | # endif /* ndef VMS_GMTIME_OK */ |
81 | | |
82 | | |
83 | | /* |
84 | | * Needed to pick up the correct definitions and declarations in some of the |
85 | | * DEC C Header Files (*.H). |
86 | | */ |
87 | | # define __NEW_STARLET 1 |
88 | | |
89 | | # if (defined(__alpha) || defined(__ia64)) |
90 | | # include <iledef.h> |
91 | | # else |
92 | | |
93 | | /* VAX */ |
94 | | typedef struct _ile3 { /* Copied from ILEDEF.H for Alpha */ |
95 | | # pragma __nomember_alignment |
96 | | unsigned short int ile3$w_length; /* Length of buffer in bytes */ |
97 | | unsigned short int ile3$w_code; /* Item code value */ |
98 | | void *ile3$ps_bufaddr; /* Buffer address */ |
99 | | unsigned short int *ile3$ps_retlen_addr; /* Address of word for returned length */ |
100 | | } ILE3; |
101 | | # endif /* alpha || ia64 */ |
102 | | #endif /* OPENSSL_SYS_VMS */ |
103 | | |
104 | | struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result) |
105 | 0 | { |
106 | 0 | struct tm *ts = NULL; |
107 | |
|
108 | 0 | #if defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_SYS_OS2) && (!defined(OPENSSL_SYS_VMS) || defined(gmtime_r)) && !defined(OPENSSL_SYS_MACOSX) && !defined(OPENSSL_SYS_SUNOS) |
109 | 0 | if (gmtime_r(timer, result) == NULL) |
110 | 0 | return NULL; |
111 | 0 | ts = result; |
112 | | #elif !defined(OPENSSL_SYS_VMS) || defined(VMS_GMTIME_OK) |
113 | | ts = gmtime(timer); |
114 | | if (ts == NULL) |
115 | | return NULL; |
116 | | |
117 | | memcpy(result, ts, sizeof(struct tm)); |
118 | | ts = result; |
119 | | #endif |
120 | | #if defined( OPENSSL_SYS_VMS) && !defined( VMS_GMTIME_OK) |
121 | | if (ts == NULL) { |
122 | | static $DESCRIPTOR(tabnam, "LNM$DCL_LOGICAL"); |
123 | | static $DESCRIPTOR(lognam, "SYS$TIMEZONE_DIFFERENTIAL"); |
124 | | char logvalue[256]; |
125 | | unsigned int reslen = 0; |
126 | | # if __INITIAL_POINTER_SIZE == 64 |
127 | | ILEB_64 itemlist[2], *pitem; |
128 | | # else |
129 | | ILE3 itemlist[2], *pitem; |
130 | | # endif |
131 | | int status; |
132 | | time_t t; |
133 | | |
134 | | |
135 | | /* |
136 | | * Setup an itemlist for the call to $TRNLNM - Translate Logical Name. |
137 | | */ |
138 | | pitem = itemlist; |
139 | | |
140 | | # if __INITIAL_POINTER_SIZE == 64 |
141 | | pitem->ileb_64$w_mbo = 1; |
142 | | pitem->ileb_64$w_code = LNM$_STRING; |
143 | | pitem->ileb_64$l_mbmo = -1; |
144 | | pitem->ileb_64$q_length = sizeof (logvalue); |
145 | | pitem->ileb_64$pq_bufaddr = logvalue; |
146 | | pitem->ileb_64$pq_retlen_addr = (unsigned __int64 *) &reslen; |
147 | | pitem++; |
148 | | /* Last item of the item list is null terminated */ |
149 | | pitem->ileb_64$q_length = pitem->ileb_64$w_code = 0; |
150 | | # else |
151 | | pitem->ile3$w_length = sizeof (logvalue); |
152 | | pitem->ile3$w_code = LNM$_STRING; |
153 | | pitem->ile3$ps_bufaddr = logvalue; |
154 | | pitem->ile3$ps_retlen_addr = (unsigned short int *) &reslen; |
155 | | pitem++; |
156 | | /* Last item of the item list is null terminated */ |
157 | | pitem->ile3$w_length = pitem->ile3$w_code = 0; |
158 | | # endif |
159 | | |
160 | | |
161 | | /* Get the value for SYS$TIMEZONE_DIFFERENTIAL */ |
162 | | status = sys$trnlnm(0, &tabnam, &lognam, 0, itemlist); |
163 | | if (!(status & 1)) |
164 | | return NULL; |
165 | | logvalue[reslen] = '\0'; |
166 | | |
167 | | t = *timer; |
168 | | |
169 | | /* The following is extracted from the DEC C header time.h */ |
170 | | /* |
171 | | ** Beginning in OpenVMS Version 7.0 mktime, time, ctime, strftime |
172 | | ** have two implementations. One implementation is provided |
173 | | ** for compatibility and deals with time in terms of local time, |
174 | | ** the other __utc_* deals with time in terms of UTC. |
175 | | */ |
176 | | /* |
177 | | * We use the same conditions as in said time.h to check if we should |
178 | | * assume that t contains local time (and should therefore be |
179 | | * adjusted) or UTC (and should therefore be left untouched). |
180 | | */ |
181 | | # if __CRTL_VER < 70000000 || defined _VMS_V6_SOURCE |
182 | | /* Get the numerical value of the equivalence string */ |
183 | | status = atoi(logvalue); |
184 | | |
185 | | /* and use it to move time to GMT */ |
186 | | t -= status; |
187 | | # endif |
188 | | |
189 | | /* then convert the result to the time structure */ |
190 | | |
191 | | /* |
192 | | * Since there was no gmtime_r() to do this stuff for us, we have to |
193 | | * do it the hard way. |
194 | | */ |
195 | | { |
196 | | /*- |
197 | | * The VMS epoch is the astronomical Smithsonian date, |
198 | | if I remember correctly, which is November 17, 1858. |
199 | | Furthermore, time is measure in thenths of microseconds |
200 | | and stored in quadwords (64 bit integers). unix_epoch |
201 | | below is January 1st 1970 expressed as a VMS time. The |
202 | | following code was used to get this number: |
203 | | |
204 | | #include <stdio.h> |
205 | | #include <stdlib.h> |
206 | | #include <lib$routines.h> |
207 | | #include <starlet.h> |
208 | | |
209 | | main() |
210 | | { |
211 | | unsigned long systime[2]; |
212 | | unsigned short epoch_values[7] = |
213 | | { 1970, 1, 1, 0, 0, 0, 0 }; |
214 | | |
215 | | lib$cvt_vectim(epoch_values, systime); |
216 | | |
217 | | printf("%u %u", systime[0], systime[1]); |
218 | | } |
219 | | */ |
220 | | unsigned long unix_epoch[2] = { 1273708544, 8164711 }; |
221 | | unsigned long deltatime[2]; |
222 | | unsigned long systime[2]; |
223 | | struct vms_vectime { |
224 | | short year, month, day, hour, minute, second, centi_second; |
225 | | } time_values; |
226 | | long operation; |
227 | | |
228 | | /* |
229 | | * Turn the number of seconds since January 1st 1970 to an |
230 | | * internal delta time. Note that lib$cvt_to_internal_time() will |
231 | | * assume that t is signed, and will therefore break on 32-bit |
232 | | * systems some time in 2038. |
233 | | */ |
234 | | operation = LIB$K_DELTA_SECONDS; |
235 | | status = lib$cvt_to_internal_time(&operation, &t, deltatime); |
236 | | |
237 | | /* |
238 | | * Add the delta time with the Unix epoch and we have the current |
239 | | * UTC time in internal format |
240 | | */ |
241 | | status = lib$add_times(unix_epoch, deltatime, systime); |
242 | | |
243 | | /* Turn the internal time into a time vector */ |
244 | | status = sys$numtim(&time_values, systime); |
245 | | |
246 | | /* Fill in the struct tm with the result */ |
247 | | result->tm_sec = time_values.second; |
248 | | result->tm_min = time_values.minute; |
249 | | result->tm_hour = time_values.hour; |
250 | | result->tm_mday = time_values.day; |
251 | | result->tm_mon = time_values.month - 1; |
252 | | result->tm_year = time_values.year - 1900; |
253 | | |
254 | | operation = LIB$K_DAY_OF_WEEK; |
255 | | status = lib$cvt_from_internal_time(&operation, |
256 | | &result->tm_wday, systime); |
257 | | result->tm_wday %= 7; |
258 | | |
259 | | operation = LIB$K_DAY_OF_YEAR; |
260 | | status = lib$cvt_from_internal_time(&operation, |
261 | | &result->tm_yday, systime); |
262 | | result->tm_yday--; |
263 | | |
264 | | result->tm_isdst = 0; /* There's no way to know... */ |
265 | | |
266 | | ts = result; |
267 | | } |
268 | | } |
269 | | #endif |
270 | 0 | return ts; |
271 | 0 | } |
272 | | |
273 | | /* |
274 | | * Take a tm structure and add an offset to it. This avoids any OS issues |
275 | | * with restricted date types and overflows which cause the year 2038 |
276 | | * problem. |
277 | | */ |
278 | | |
279 | 0 | #define SECS_PER_DAY (24 * 60 * 60) |
280 | | |
281 | | static long date_to_julian(int y, int m, int d); |
282 | | static void julian_to_date(long jd, int *y, int *m, int *d); |
283 | | static int julian_adj(const struct tm *tm, int off_day, long offset_sec, |
284 | | long *pday, int *psec); |
285 | | |
286 | | int OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec) |
287 | 0 | { |
288 | 0 | int time_sec, time_year, time_month, time_day; |
289 | 0 | long time_jd; |
290 | | |
291 | | /* Convert time and offset into julian day and seconds */ |
292 | 0 | if (!julian_adj(tm, off_day, offset_sec, &time_jd, &time_sec)) |
293 | 0 | return 0; |
294 | | |
295 | | /* Convert Julian day back to date */ |
296 | | |
297 | 0 | julian_to_date(time_jd, &time_year, &time_month, &time_day); |
298 | |
|
299 | 0 | if (time_year < 1900 || time_year > 9999) |
300 | 0 | return 0; |
301 | | |
302 | | /* Update tm structure */ |
303 | | |
304 | 0 | tm->tm_year = time_year - 1900; |
305 | 0 | tm->tm_mon = time_month - 1; |
306 | 0 | tm->tm_mday = time_day; |
307 | |
|
308 | 0 | tm->tm_hour = time_sec / 3600; |
309 | 0 | tm->tm_min = (time_sec / 60) % 60; |
310 | 0 | tm->tm_sec = time_sec % 60; |
311 | |
|
312 | 0 | return 1; |
313 | |
|
314 | 0 | } |
315 | | |
316 | | int OPENSSL_gmtime_diff(int *pday, int *psec, |
317 | | const struct tm *from, const struct tm *to) |
318 | 0 | { |
319 | 0 | int from_sec, to_sec, diff_sec; |
320 | 0 | long from_jd, to_jd, diff_day; |
321 | 0 | if (!julian_adj(from, 0, 0, &from_jd, &from_sec)) |
322 | 0 | return 0; |
323 | 0 | if (!julian_adj(to, 0, 0, &to_jd, &to_sec)) |
324 | 0 | return 0; |
325 | 0 | diff_day = to_jd - from_jd; |
326 | 0 | diff_sec = to_sec - from_sec; |
327 | | /* Adjust differences so both positive or both negative */ |
328 | 0 | if (diff_day > 0 && diff_sec < 0) { |
329 | 0 | diff_day--; |
330 | 0 | diff_sec += SECS_PER_DAY; |
331 | 0 | } |
332 | 0 | if (diff_day < 0 && diff_sec > 0) { |
333 | 0 | diff_day++; |
334 | 0 | diff_sec -= SECS_PER_DAY; |
335 | 0 | } |
336 | |
|
337 | 0 | if (pday) |
338 | 0 | *pday = (int)diff_day; |
339 | 0 | if (psec) |
340 | 0 | *psec = diff_sec; |
341 | |
|
342 | 0 | return 1; |
343 | |
|
344 | 0 | } |
345 | | |
346 | | /* Convert tm structure and offset into julian day and seconds */ |
347 | | static int julian_adj(const struct tm *tm, int off_day, long offset_sec, |
348 | | long *pday, int *psec) |
349 | 0 | { |
350 | 0 | int offset_hms, offset_day; |
351 | 0 | long time_jd; |
352 | 0 | int time_year, time_month, time_day; |
353 | | /* split offset into days and day seconds */ |
354 | 0 | offset_day = offset_sec / SECS_PER_DAY; |
355 | | /* Avoid sign issues with % operator */ |
356 | 0 | offset_hms = offset_sec - (offset_day * SECS_PER_DAY); |
357 | 0 | offset_day += off_day; |
358 | | /* Add current time seconds to offset */ |
359 | 0 | offset_hms += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec; |
360 | | /* Adjust day seconds if overflow */ |
361 | 0 | if (offset_hms >= SECS_PER_DAY) { |
362 | 0 | offset_day++; |
363 | 0 | offset_hms -= SECS_PER_DAY; |
364 | 0 | } else if (offset_hms < 0) { |
365 | 0 | offset_day--; |
366 | 0 | offset_hms += SECS_PER_DAY; |
367 | 0 | } |
368 | | |
369 | | /* |
370 | | * Convert date of time structure into a Julian day number. |
371 | | */ |
372 | |
|
373 | 0 | time_year = tm->tm_year + 1900; |
374 | 0 | time_month = tm->tm_mon + 1; |
375 | 0 | time_day = tm->tm_mday; |
376 | |
|
377 | 0 | time_jd = date_to_julian(time_year, time_month, time_day); |
378 | | |
379 | | /* Work out Julian day of new date */ |
380 | 0 | time_jd += offset_day; |
381 | |
|
382 | 0 | if (time_jd < 0) |
383 | 0 | return 0; |
384 | | |
385 | 0 | *pday = time_jd; |
386 | 0 | *psec = offset_hms; |
387 | 0 | return 1; |
388 | 0 | } |
389 | | |
390 | | /* |
391 | | * Convert date to and from julian day Uses Fliegel & Van Flandern algorithm |
392 | | */ |
393 | | static long date_to_julian(int y, int m, int d) |
394 | 0 | { |
395 | 0 | return (1461 * (y + 4800 + (m - 14) / 12)) / 4 + |
396 | 0 | (367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 - |
397 | 0 | (3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075; |
398 | 0 | } |
399 | | |
400 | | static void julian_to_date(long jd, int *y, int *m, int *d) |
401 | 0 | { |
402 | 0 | long L = jd + 68569; |
403 | 0 | long n = (4 * L) / 146097; |
404 | 0 | long i, j; |
405 | |
|
406 | 0 | L = L - (146097 * n + 3) / 4; |
407 | 0 | i = (4000 * (L + 1)) / 1461001; |
408 | 0 | L = L - (1461 * i) / 4 + 31; |
409 | 0 | j = (80 * L) / 2447; |
410 | 0 | *d = L - (2447 * j) / 80; |
411 | 0 | L = j / 11; |
412 | 0 | *m = j + 2 - (12 * L); |
413 | 0 | *y = 100 * (n - 49) + i + L; |
414 | 0 | } |
415 | | |
416 | | #ifdef OPENSSL_TIME_TEST |
417 | | |
418 | | # include <stdio.h> |
419 | | |
420 | | /* |
421 | | * Time checking test code. Check times are identical for a wide range of |
422 | | * offsets. This should be run on a machine with 64 bit time_t or it will |
423 | | * trigger the very errors the routines fix. |
424 | | */ |
425 | | |
426 | | int main(int argc, char **argv) |
427 | | { |
428 | | long offset; |
429 | | for (offset = 0; offset < 1000000; offset++) { |
430 | | check_time(offset); |
431 | | check_time(-offset); |
432 | | check_time(offset * 1000); |
433 | | check_time(-offset * 1000); |
434 | | } |
435 | | } |
436 | | |
437 | | int check_time(long offset) |
438 | | { |
439 | | struct tm tm1, tm2, o1; |
440 | | int off_day, off_sec; |
441 | | long toffset; |
442 | | time_t t1, t2; |
443 | | time(&t1); |
444 | | t2 = t1 + offset; |
445 | | OPENSSL_gmtime(&t2, &tm2); |
446 | | OPENSSL_gmtime(&t1, &tm1); |
447 | | o1 = tm1; |
448 | | OPENSSL_gmtime_adj(&tm1, 0, offset); |
449 | | if ((tm1.tm_year != tm2.tm_year) || |
450 | | (tm1.tm_mon != tm2.tm_mon) || |
451 | | (tm1.tm_mday != tm2.tm_mday) || |
452 | | (tm1.tm_hour != tm2.tm_hour) || |
453 | | (tm1.tm_min != tm2.tm_min) || (tm1.tm_sec != tm2.tm_sec)) { |
454 | | fprintf(stderr, "TIME ERROR!!\n"); |
455 | | fprintf(stderr, "Time1: %d/%d/%d, %d:%02d:%02d\n", |
456 | | tm2.tm_mday, tm2.tm_mon + 1, tm2.tm_year + 1900, |
457 | | tm2.tm_hour, tm2.tm_min, tm2.tm_sec); |
458 | | fprintf(stderr, "Time2: %d/%d/%d, %d:%02d:%02d\n", |
459 | | tm1.tm_mday, tm1.tm_mon + 1, tm1.tm_year + 1900, |
460 | | tm1.tm_hour, tm1.tm_min, tm1.tm_sec); |
461 | | return 0; |
462 | | } |
463 | | OPENSSL_gmtime_diff(&o1, &tm1, &off_day, &off_sec); |
464 | | toffset = (long)off_day *SECS_PER_DAY + off_sec; |
465 | | if (offset != toffset) { |
466 | | fprintf(stderr, "TIME OFFSET ERROR!!\n"); |
467 | | fprintf(stderr, "Expected %ld, Got %ld (%d:%d)\n", |
468 | | offset, toffset, off_day, off_sec); |
469 | | return 0; |
470 | | } |
471 | | return 1; |
472 | | } |
473 | | |
474 | | #endif |