1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <openssl/e_os2.h> 11e1051a39Sopenharmony_ci#include <string.h> 12e1051a39Sopenharmony_ci#include <openssl/crypto.h> 13e1051a39Sopenharmony_ci 14e1051a39Sopenharmony_cistruct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result) 15e1051a39Sopenharmony_ci{ 16e1051a39Sopenharmony_ci struct tm *ts = NULL; 17e1051a39Sopenharmony_ci 18e1051a39Sopenharmony_ci#if defined(OPENSSL_THREADS) && defined(OPENSSL_SYS_VMS) 19e1051a39Sopenharmony_ci { 20e1051a39Sopenharmony_ci /* 21e1051a39Sopenharmony_ci * On VMS, gmtime_r() takes a 32-bit pointer as second argument. 22e1051a39Sopenharmony_ci * Since we can't know that |result| is in a space that can easily 23e1051a39Sopenharmony_ci * translate to a 32-bit pointer, we must store temporarily on stack 24e1051a39Sopenharmony_ci * and copy the result. The stack is always reachable with 32-bit 25e1051a39Sopenharmony_ci * pointers. 26e1051a39Sopenharmony_ci */ 27e1051a39Sopenharmony_ci#if defined(OPENSSL_SYS_VMS) && __INITIAL_POINTER_SIZE 28e1051a39Sopenharmony_ci# pragma pointer_size save 29e1051a39Sopenharmony_ci# pragma pointer_size 32 30e1051a39Sopenharmony_ci#endif 31e1051a39Sopenharmony_ci struct tm data, *ts2 = &data; 32e1051a39Sopenharmony_ci#if defined OPENSSL_SYS_VMS && __INITIAL_POINTER_SIZE 33e1051a39Sopenharmony_ci# pragma pointer_size restore 34e1051a39Sopenharmony_ci#endif 35e1051a39Sopenharmony_ci if (gmtime_r(timer, ts2) == NULL) 36e1051a39Sopenharmony_ci return NULL; 37e1051a39Sopenharmony_ci memcpy(result, ts2, sizeof(struct tm)); 38e1051a39Sopenharmony_ci ts = result; 39e1051a39Sopenharmony_ci } 40e1051a39Sopenharmony_ci#elif defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_SYS_MACOSX) 41e1051a39Sopenharmony_ci if (gmtime_r(timer, result) == NULL) 42e1051a39Sopenharmony_ci return NULL; 43e1051a39Sopenharmony_ci ts = result; 44e1051a39Sopenharmony_ci#elif defined (OPENSSL_SYS_WINDOWS) && defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(_WIN32_WCE) 45e1051a39Sopenharmony_ci if (gmtime_s(result, timer)) 46e1051a39Sopenharmony_ci return NULL; 47e1051a39Sopenharmony_ci ts = result; 48e1051a39Sopenharmony_ci#else 49e1051a39Sopenharmony_ci ts = gmtime(timer); 50e1051a39Sopenharmony_ci if (ts == NULL) 51e1051a39Sopenharmony_ci return NULL; 52e1051a39Sopenharmony_ci 53e1051a39Sopenharmony_ci memcpy(result, ts, sizeof(struct tm)); 54e1051a39Sopenharmony_ci ts = result; 55e1051a39Sopenharmony_ci#endif 56e1051a39Sopenharmony_ci return ts; 57e1051a39Sopenharmony_ci} 58e1051a39Sopenharmony_ci 59e1051a39Sopenharmony_ci/* 60e1051a39Sopenharmony_ci * Take a tm structure and add an offset to it. This avoids any OS issues 61e1051a39Sopenharmony_ci * with restricted date types and overflows which cause the year 2038 62e1051a39Sopenharmony_ci * problem. 63e1051a39Sopenharmony_ci */ 64e1051a39Sopenharmony_ci 65e1051a39Sopenharmony_ci#define SECS_PER_DAY (24 * 60 * 60) 66e1051a39Sopenharmony_ci 67e1051a39Sopenharmony_cistatic long date_to_julian(int y, int m, int d); 68e1051a39Sopenharmony_cistatic void julian_to_date(long jd, int *y, int *m, int *d); 69e1051a39Sopenharmony_cistatic int julian_adj(const struct tm *tm, int off_day, long offset_sec, 70e1051a39Sopenharmony_ci long *pday, int *psec); 71e1051a39Sopenharmony_ci 72e1051a39Sopenharmony_ciint OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec) 73e1051a39Sopenharmony_ci{ 74e1051a39Sopenharmony_ci int time_sec, time_year, time_month, time_day; 75e1051a39Sopenharmony_ci long time_jd; 76e1051a39Sopenharmony_ci 77e1051a39Sopenharmony_ci /* Convert time and offset into Julian day and seconds */ 78e1051a39Sopenharmony_ci if (!julian_adj(tm, off_day, offset_sec, &time_jd, &time_sec)) 79e1051a39Sopenharmony_ci return 0; 80e1051a39Sopenharmony_ci 81e1051a39Sopenharmony_ci /* Convert Julian day back to date */ 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci julian_to_date(time_jd, &time_year, &time_month, &time_day); 84e1051a39Sopenharmony_ci 85e1051a39Sopenharmony_ci if (time_year < 1900 || time_year > 9999) 86e1051a39Sopenharmony_ci return 0; 87e1051a39Sopenharmony_ci 88e1051a39Sopenharmony_ci /* Update tm structure */ 89e1051a39Sopenharmony_ci 90e1051a39Sopenharmony_ci tm->tm_year = time_year - 1900; 91e1051a39Sopenharmony_ci tm->tm_mon = time_month - 1; 92e1051a39Sopenharmony_ci tm->tm_mday = time_day; 93e1051a39Sopenharmony_ci 94e1051a39Sopenharmony_ci tm->tm_hour = time_sec / 3600; 95e1051a39Sopenharmony_ci tm->tm_min = (time_sec / 60) % 60; 96e1051a39Sopenharmony_ci tm->tm_sec = time_sec % 60; 97e1051a39Sopenharmony_ci 98e1051a39Sopenharmony_ci return 1; 99e1051a39Sopenharmony_ci 100e1051a39Sopenharmony_ci} 101e1051a39Sopenharmony_ci 102e1051a39Sopenharmony_ciint OPENSSL_gmtime_diff(int *pday, int *psec, 103e1051a39Sopenharmony_ci const struct tm *from, const struct tm *to) 104e1051a39Sopenharmony_ci{ 105e1051a39Sopenharmony_ci int from_sec, to_sec, diff_sec; 106e1051a39Sopenharmony_ci long from_jd, to_jd, diff_day; 107e1051a39Sopenharmony_ci if (!julian_adj(from, 0, 0, &from_jd, &from_sec)) 108e1051a39Sopenharmony_ci return 0; 109e1051a39Sopenharmony_ci if (!julian_adj(to, 0, 0, &to_jd, &to_sec)) 110e1051a39Sopenharmony_ci return 0; 111e1051a39Sopenharmony_ci diff_day = to_jd - from_jd; 112e1051a39Sopenharmony_ci diff_sec = to_sec - from_sec; 113e1051a39Sopenharmony_ci /* Adjust differences so both positive or both negative */ 114e1051a39Sopenharmony_ci if (diff_day > 0 && diff_sec < 0) { 115e1051a39Sopenharmony_ci diff_day--; 116e1051a39Sopenharmony_ci diff_sec += SECS_PER_DAY; 117e1051a39Sopenharmony_ci } 118e1051a39Sopenharmony_ci if (diff_day < 0 && diff_sec > 0) { 119e1051a39Sopenharmony_ci diff_day++; 120e1051a39Sopenharmony_ci diff_sec -= SECS_PER_DAY; 121e1051a39Sopenharmony_ci } 122e1051a39Sopenharmony_ci 123e1051a39Sopenharmony_ci if (pday) 124e1051a39Sopenharmony_ci *pday = (int)diff_day; 125e1051a39Sopenharmony_ci if (psec) 126e1051a39Sopenharmony_ci *psec = diff_sec; 127e1051a39Sopenharmony_ci 128e1051a39Sopenharmony_ci return 1; 129e1051a39Sopenharmony_ci 130e1051a39Sopenharmony_ci} 131e1051a39Sopenharmony_ci 132e1051a39Sopenharmony_ci/* Convert tm structure and offset into julian day and seconds */ 133e1051a39Sopenharmony_cistatic int julian_adj(const struct tm *tm, int off_day, long offset_sec, 134e1051a39Sopenharmony_ci long *pday, int *psec) 135e1051a39Sopenharmony_ci{ 136e1051a39Sopenharmony_ci int offset_hms; 137e1051a39Sopenharmony_ci long offset_day, time_jd; 138e1051a39Sopenharmony_ci int time_year, time_month, time_day; 139e1051a39Sopenharmony_ci /* split offset into days and day seconds */ 140e1051a39Sopenharmony_ci offset_day = offset_sec / SECS_PER_DAY; 141e1051a39Sopenharmony_ci /* Avoid sign issues with % operator */ 142e1051a39Sopenharmony_ci offset_hms = offset_sec - (offset_day * SECS_PER_DAY); 143e1051a39Sopenharmony_ci offset_day += off_day; 144e1051a39Sopenharmony_ci /* Add current time seconds to offset */ 145e1051a39Sopenharmony_ci offset_hms += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec; 146e1051a39Sopenharmony_ci /* Adjust day seconds if overflow */ 147e1051a39Sopenharmony_ci if (offset_hms >= SECS_PER_DAY) { 148e1051a39Sopenharmony_ci offset_day++; 149e1051a39Sopenharmony_ci offset_hms -= SECS_PER_DAY; 150e1051a39Sopenharmony_ci } else if (offset_hms < 0) { 151e1051a39Sopenharmony_ci offset_day--; 152e1051a39Sopenharmony_ci offset_hms += SECS_PER_DAY; 153e1051a39Sopenharmony_ci } 154e1051a39Sopenharmony_ci 155e1051a39Sopenharmony_ci /* 156e1051a39Sopenharmony_ci * Convert date of time structure into a Julian day number. 157e1051a39Sopenharmony_ci */ 158e1051a39Sopenharmony_ci 159e1051a39Sopenharmony_ci time_year = tm->tm_year + 1900; 160e1051a39Sopenharmony_ci time_month = tm->tm_mon + 1; 161e1051a39Sopenharmony_ci time_day = tm->tm_mday; 162e1051a39Sopenharmony_ci 163e1051a39Sopenharmony_ci time_jd = date_to_julian(time_year, time_month, time_day); 164e1051a39Sopenharmony_ci 165e1051a39Sopenharmony_ci /* Work out Julian day of new date */ 166e1051a39Sopenharmony_ci time_jd += offset_day; 167e1051a39Sopenharmony_ci 168e1051a39Sopenharmony_ci if (time_jd < 0) 169e1051a39Sopenharmony_ci return 0; 170e1051a39Sopenharmony_ci 171e1051a39Sopenharmony_ci *pday = time_jd; 172e1051a39Sopenharmony_ci *psec = offset_hms; 173e1051a39Sopenharmony_ci return 1; 174e1051a39Sopenharmony_ci} 175e1051a39Sopenharmony_ci 176e1051a39Sopenharmony_ci/* 177e1051a39Sopenharmony_ci * Convert date to and from julian day Uses Fliegel & Van Flandern algorithm 178e1051a39Sopenharmony_ci */ 179e1051a39Sopenharmony_cistatic long date_to_julian(int y, int m, int d) 180e1051a39Sopenharmony_ci{ 181e1051a39Sopenharmony_ci return (1461 * (y + 4800 + (m - 14) / 12)) / 4 + 182e1051a39Sopenharmony_ci (367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 - 183e1051a39Sopenharmony_ci (3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075; 184e1051a39Sopenharmony_ci} 185e1051a39Sopenharmony_ci 186e1051a39Sopenharmony_cistatic void julian_to_date(long jd, int *y, int *m, int *d) 187e1051a39Sopenharmony_ci{ 188e1051a39Sopenharmony_ci long L = jd + 68569; 189e1051a39Sopenharmony_ci long n = (4 * L) / 146097; 190e1051a39Sopenharmony_ci long i, j; 191e1051a39Sopenharmony_ci 192e1051a39Sopenharmony_ci L = L - (146097 * n + 3) / 4; 193e1051a39Sopenharmony_ci i = (4000 * (L + 1)) / 1461001; 194e1051a39Sopenharmony_ci L = L - (1461 * i) / 4 + 31; 195e1051a39Sopenharmony_ci j = (80 * L) / 2447; 196e1051a39Sopenharmony_ci *d = L - (2447 * j) / 80; 197e1051a39Sopenharmony_ci L = j / 11; 198e1051a39Sopenharmony_ci *m = j + 2 - (12 * L); 199e1051a39Sopenharmony_ci *y = 100 * (n - 49) + i + L; 200e1051a39Sopenharmony_ci} 201