mirror of
https://github.com/openssl/openssl.git
synced 2026-01-18 17:11:31 +01:00
Bring in posix time conversion functions, originally from BoringSSL
This is effectively a Julien date computation, but done as seconds since the POSIX epoch, all checked for overflow and limited to dates from year 0000 to 9999. This is advantageous as it removed the need to use the operating system provided timegm() and gmtime() functions which are only semi-standardized in any case and when they aren't there or don't work other nastiness needs to be tried to do the same thing. Even when they are there, you need to worry about the size of time_t and if the bad idea bears of unsigned time_t have visited this platform. By simply doing the conversion ourselves, to and from and int64, this can be done the same everywhere, and bounds checked when being put into a time_t. This adds public API that is already added in libre and boring in <openssl/posix_time.h>: These are added in the forks due to noticing a fair bit of software needing to perform similar error-prone conversions themselves when dealing with ASN1 times (such as what we have to do in the tests). While I intend to use some of this API for further simplification in a follow on changes in several places (such as ocsp and X509) For now we only use it to simplify the test helpers and clean that up a bunch Reviewed-by: Neil Horman <nhorman@openssl.org> Reviewed-by: Saša Nedvědický <sashan@openssl.org> (Merged from https://github.com/openssl/openssl/pull/28748)
This commit is contained in:
279
crypto/asn1/a_time_posix.c
Normal file
279
crypto/asn1/a_time_posix.c
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* Time conversion to/from POSIX time_t and struct tm, with no support
|
||||
* for time zones other than UTC
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/posix_time.h>
|
||||
|
||||
#include "asn1_local.h"
|
||||
|
||||
#define SECS_PER_HOUR (int64_t)(60 * 60)
|
||||
#define SECS_PER_DAY (int64_t)(24 * SECS_PER_HOUR)
|
||||
|
||||
/*
|
||||
* Is a year/month/day combination valid, in the range from year 0000
|
||||
* to 9999?
|
||||
*/
|
||||
static int is_valid_date(int64_t year, int64_t month, int64_t day)
|
||||
{
|
||||
int days_in_month;
|
||||
|
||||
if (day < 1 || year < 0 || year > 9999)
|
||||
return 0;
|
||||
switch (month) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
days_in_month = 31;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
case 9:
|
||||
case 11:
|
||||
days_in_month = 30;
|
||||
break;
|
||||
case 2:
|
||||
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
|
||||
days_in_month = 29;
|
||||
else
|
||||
days_in_month = 28;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return day <= days_in_month;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is a time valid? Leap seconds of 60 are not considered valid, as
|
||||
* the POSIX time in seconds does not include them.
|
||||
*/
|
||||
static int is_valid_time(int64_t hours, int64_t minutes, int64_t seconds)
|
||||
{
|
||||
return hours >= 0 && minutes >= 0 && seconds >= 0 && hours <= 23 &&
|
||||
minutes <= 59 && seconds <= 59;
|
||||
}
|
||||
|
||||
/* 0000-01-01 00:00:00 UTC */
|
||||
#define MIN_POSIX_TIME INT64_C(-62167219200)
|
||||
/* 9999-12-31 23:59:59 UTC */
|
||||
#define MAX_POSIX_TIME INT64_C(253402300799)
|
||||
|
||||
/* Is a int64 time representing a time within our expected range? */
|
||||
static int is_valid_posix_time(int64_t time)
|
||||
{
|
||||
return MIN_POSIX_TIME <= time && time <= MAX_POSIX_TIME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inspired by algorithms presented in
|
||||
* https://howardhinnant.github.io/date_algorithms.html
|
||||
* (Public Domain)
|
||||
*/
|
||||
static int posix_time_from_utc(int64_t year, int64_t month, int64_t day,
|
||||
int64_t hours, int64_t minutes, int64_t seconds,
|
||||
int64_t *out_time)
|
||||
{
|
||||
int64_t era, year_of_era, day_of_year, day_of_era, posix_days;
|
||||
|
||||
if (!is_valid_date(year, month, day) ||
|
||||
!is_valid_time(hours, minutes, seconds))
|
||||
return 0;
|
||||
if (month <= 2)
|
||||
year--; /* Start years on Mar 1, so leap days end a year. */
|
||||
|
||||
/* At this point year will be in the range -1 and 9999. */
|
||||
era = (year >= 0 ? year : year - 399) / 400;
|
||||
year_of_era = year - era * 400;
|
||||
day_of_year = (153 * (month > 2 ? month - 3 : month + 9) + 2) /
|
||||
5 + day - 1;
|
||||
day_of_era = year_of_era * 365 + year_of_era / 4 - year_of_era /
|
||||
100 + day_of_year;
|
||||
posix_days = era * 146097 + day_of_era - 719468;
|
||||
*out_time = posix_days * SECS_PER_DAY + hours * SECS_PER_HOUR +
|
||||
minutes * 60 + seconds;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inspired by algorithms presented in
|
||||
* https://howardhinnant.github.io/date_algorithms.html
|
||||
* (Public Domain)
|
||||
*/
|
||||
static int utc_from_posix_time(int64_t time, int *out_year, int *out_month,
|
||||
int *out_day, int *out_hours, int *out_minutes,
|
||||
int *out_seconds)
|
||||
{
|
||||
int64_t days, leftover_seconds, era, day_of_era, year_of_era, day_of_year;
|
||||
int64_t month_of_year;
|
||||
|
||||
if (!is_valid_posix_time(time))
|
||||
return 0;
|
||||
|
||||
days = time / SECS_PER_DAY;
|
||||
leftover_seconds = time % SECS_PER_DAY;
|
||||
if (leftover_seconds < 0) {
|
||||
days--;
|
||||
leftover_seconds += SECS_PER_DAY;
|
||||
}
|
||||
days += 719468; /* Shift to starting epoch of Mar 1 0000. */
|
||||
|
||||
/* At this point, days will be in the range -61 and 3652364. */
|
||||
era = (days > 0 ? days : days - 146096) / 146097;
|
||||
day_of_era = days - era * 146097;
|
||||
year_of_era = (day_of_era - day_of_era / 1460 + day_of_era / 36524 -
|
||||
day_of_era / 146096) / 365;
|
||||
*out_year = (int)(year_of_era + era * 400); /* Year starts on Mar 1 */
|
||||
day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 -
|
||||
year_of_era / 100);
|
||||
month_of_year = (5 * day_of_year + 2) / 153;
|
||||
*out_month = (int) (month_of_year < 10 ? month_of_year + 3 :
|
||||
month_of_year - 9);
|
||||
if (*out_month <= 2)
|
||||
(*out_year)++; /* Adjust year back to Jan 1 start of year. */
|
||||
|
||||
*out_day = (int)(day_of_year - (153 * month_of_year + 2) / 5 + 1);
|
||||
*out_hours = (int) leftover_seconds / SECS_PER_HOUR;
|
||||
leftover_seconds %= SECS_PER_HOUR;
|
||||
*out_minutes = (int) leftover_seconds / 60;
|
||||
*out_seconds = (int) leftover_seconds % 60;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OPENSSL_tm_to_posix(const struct tm *tm, int64_t *out)
|
||||
{
|
||||
return posix_time_from_utc(tm->tm_year + (int64_t)1900,
|
||||
tm->tm_mon + (int64_t)1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec, out);
|
||||
}
|
||||
|
||||
int OPENSSL_posix_to_tm(int64_t time, struct tm *out_tm)
|
||||
{
|
||||
struct tm tmp_tm = {0};
|
||||
|
||||
memset(out_tm, 0, sizeof(*out_tm));
|
||||
|
||||
if (!utc_from_posix_time(time, &tmp_tm.tm_year, &tmp_tm.tm_mon,
|
||||
&tmp_tm.tm_mday, &tmp_tm.tm_hour,
|
||||
&tmp_tm.tm_min, &tmp_tm.tm_sec))
|
||||
return 0;
|
||||
|
||||
tmp_tm.tm_year -= 1900;
|
||||
tmp_tm.tm_mon -= 1;
|
||||
|
||||
*out_tm = tmp_tm;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_asn1_time_tm_to_time_t(const struct tm *tm, time_t *out)
|
||||
{
|
||||
int64_t posix_time;
|
||||
time_t test_t = -1;
|
||||
int bad_idea_bears = (test_t > 0); /* time_t is unsigned */
|
||||
|
||||
if (!OPENSSL_tm_to_posix(tm, &posix_time))
|
||||
return 0;
|
||||
|
||||
if (sizeof(time_t) == sizeof(int32_t)
|
||||
&& ((!bad_idea_bears && (posix_time > INT32_MAX
|
||||
|| posix_time < INT32_MIN))
|
||||
|| (bad_idea_bears && (posix_time > UINT32_MAX
|
||||
|| posix_time < 0))))
|
||||
return 0;
|
||||
|
||||
*out = posix_time;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_asn1_time_time_t_to_tm(const time_t *time, struct tm *out_tm)
|
||||
{
|
||||
int64_t posix_time = *time;
|
||||
|
||||
return OPENSSL_posix_to_tm(posix_time, out_tm);
|
||||
}
|
||||
|
||||
int OPENSSL_timegm(const struct tm *tm, time_t *out)
|
||||
{
|
||||
return ossl_asn1_time_tm_to_time_t(tm, out);
|
||||
}
|
||||
|
||||
struct tm * OPENSSL_gmtime(const time_t *time, struct tm *out_tm)
|
||||
{
|
||||
if (!ossl_asn1_time_time_t_to_tm(time, out_tm))
|
||||
return NULL;
|
||||
return out_tm;
|
||||
}
|
||||
|
||||
/* LibreSSL and BoringSSL use int64_t instead of long. */
|
||||
int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec)
|
||||
{
|
||||
int64_t posix_time;
|
||||
|
||||
if (!OPENSSL_tm_to_posix(tm, &posix_time))
|
||||
return 0;
|
||||
|
||||
OPENSSL_assert(INT_MAX <= INT64_MAX / SECS_PER_DAY);
|
||||
OPENSSL_assert(MAX_POSIX_TIME <= INT64_MAX - INT_MAX * SECS_PER_DAY);
|
||||
OPENSSL_assert(MIN_POSIX_TIME >= INT64_MIN - INT_MIN * SECS_PER_DAY);
|
||||
|
||||
posix_time += offset_day * SECS_PER_DAY;
|
||||
|
||||
if (posix_time > 0 && offset_sec > INT64_MAX - posix_time)
|
||||
return 0;
|
||||
if (posix_time < 0 && offset_sec < INT64_MIN - posix_time)
|
||||
return 0;
|
||||
posix_time += offset_sec;
|
||||
|
||||
if (!OPENSSL_posix_to_tm(posix_time, tm))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
|
||||
const struct tm *to)
|
||||
{
|
||||
int64_t time_to, time_from, timediff, daydiff;
|
||||
|
||||
if (!OPENSSL_tm_to_posix(to, &time_to) ||
|
||||
!OPENSSL_tm_to_posix(from, &time_from))
|
||||
return 0;
|
||||
|
||||
/* Times are in range, so these calculations cannot overflow. */
|
||||
OPENSSL_assert(SECS_PER_DAY <= INT_MAX);
|
||||
OPENSSL_assert((MAX_POSIX_TIME - MIN_POSIX_TIME) / SECS_PER_DAY <= INT_MAX);
|
||||
|
||||
timediff = time_to - time_from;
|
||||
daydiff = timediff / SECS_PER_DAY;
|
||||
timediff %= SECS_PER_DAY;
|
||||
|
||||
*out_secs = (int) timediff;
|
||||
*out_days = (int) daydiff;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,3 +94,5 @@ ASN1_TIME *ossl_asn1_time_from_tm(ASN1_TIME *s, struct tm *ts, int type);
|
||||
|
||||
int ossl_asn1_item_ex_new_intern(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
OSSL_LIB_CTX *libctx, const char *propq);
|
||||
int ossl_asn1_time_time_t_to_tm(const time_t *time, struct tm *out_tm);
|
||||
int ossl_asn1_time_tm_to_time_t(const struct tm *tm, time_t *out);
|
||||
|
||||
@@ -14,7 +14,7 @@ SOURCE[../../libcrypto]=\
|
||||
asn1_gen.c asn1_parse.c asn1_lib.c asn1_err.c a_strnid.c \
|
||||
evp_asn1.c asn_pack.c p5_pbe.c p5_pbev2.c p5_scrypt.c p8_pkey.c \
|
||||
asn_moid.c asn_mstbl.c asn1_item_list.c \
|
||||
d2i_param.c
|
||||
d2i_param.c a_time_posix.c
|
||||
IF[{- !$disabled{'rsa'} and !$disabled{'rc4'} -}]
|
||||
SOURCE[../../libcrypto]=n_pkey.c
|
||||
ENDIF
|
||||
|
||||
@@ -104,7 +104,7 @@ $UTIL_COMMON=\
|
||||
|
||||
SOURCE[../libcrypto]=$UTIL_COMMON \
|
||||
mem.c mem_sec.c \
|
||||
comp_methods.c cversion.c info.c cpt_err.c ebcdic.c uid.c o_time.c \
|
||||
comp_methods.c cversion.c info.c cpt_err.c ebcdic.c uid.c \
|
||||
o_dir.c o_fopen.c getenv.c o_init.c init.c trace.c provider.c \
|
||||
provider_child.c punycode.c passphrase.c sleep.c \
|
||||
quic_vlint.c time.c defaults.c ssl_err.c
|
||||
|
||||
200
crypto/o_time.c
200
crypto/o_time.c
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/e_os2.h>
|
||||
#include <string.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result)
|
||||
{
|
||||
struct tm *ts = NULL;
|
||||
|
||||
#if defined(OPENSSL_THREADS) && defined(OPENSSL_SYS_VMS)
|
||||
{
|
||||
/*
|
||||
* On VMS, gmtime_r() takes a 32-bit pointer as second argument.
|
||||
* Since we can't know that |result| is in a space that can easily
|
||||
* translate to a 32-bit pointer, we must store temporarily on stack
|
||||
* and copy the result. The stack is always reachable with 32-bit
|
||||
* pointers.
|
||||
*/
|
||||
#if defined(OPENSSL_SYS_VMS) && __INITIAL_POINTER_SIZE
|
||||
# pragma pointer_size save
|
||||
# pragma pointer_size 32
|
||||
#endif
|
||||
struct tm data, *ts2 = &data;
|
||||
#if defined OPENSSL_SYS_VMS && __INITIAL_POINTER_SIZE
|
||||
# pragma pointer_size restore
|
||||
#endif
|
||||
if (gmtime_r(timer, ts2) == NULL)
|
||||
return NULL;
|
||||
memcpy(result, ts2, sizeof(struct tm));
|
||||
ts = result;
|
||||
}
|
||||
#elif defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_SYS_MACOSX)
|
||||
if (gmtime_r(timer, result) == NULL)
|
||||
return NULL;
|
||||
ts = result;
|
||||
#elif defined (OPENSSL_SYS_WINDOWS) && defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(_WIN32_WCE)
|
||||
if (gmtime_s(result, timer))
|
||||
return NULL;
|
||||
ts = result;
|
||||
#else
|
||||
ts = gmtime(timer);
|
||||
if (ts == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(result, ts, sizeof(struct tm));
|
||||
ts = result;
|
||||
#endif
|
||||
return ts;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a tm structure and add an offset to it. This avoids any OS issues
|
||||
* with restricted date types and overflows which cause the year 2038
|
||||
* problem.
|
||||
*/
|
||||
|
||||
#define SECS_PER_DAY (24 * 60 * 60)
|
||||
|
||||
static long date_to_julian(int y, int m, int d);
|
||||
static void julian_to_date(long jd, int *y, int *m, int *d);
|
||||
static int julian_adj(const struct tm *tm, int off_day, long offset_sec,
|
||||
long *pday, int *psec);
|
||||
|
||||
int OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec)
|
||||
{
|
||||
int time_sec, time_year, time_month, time_day;
|
||||
long time_jd;
|
||||
|
||||
/* Convert time and offset into Julian day and seconds */
|
||||
if (!julian_adj(tm, off_day, offset_sec, &time_jd, &time_sec))
|
||||
return 0;
|
||||
|
||||
/* Convert Julian day back to date */
|
||||
|
||||
julian_to_date(time_jd, &time_year, &time_month, &time_day);
|
||||
|
||||
if (time_year < 1900 || time_year > 9999)
|
||||
return 0;
|
||||
|
||||
/* Update tm structure */
|
||||
|
||||
tm->tm_year = time_year - 1900;
|
||||
tm->tm_mon = time_month - 1;
|
||||
tm->tm_mday = time_day;
|
||||
|
||||
tm->tm_hour = time_sec / 3600;
|
||||
tm->tm_min = (time_sec / 60) % 60;
|
||||
tm->tm_sec = time_sec % 60;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int OPENSSL_gmtime_diff(int *pday, int *psec,
|
||||
const struct tm *from, const struct tm *to)
|
||||
{
|
||||
int from_sec, to_sec, diff_sec;
|
||||
long from_jd, to_jd, diff_day;
|
||||
if (!julian_adj(from, 0, 0, &from_jd, &from_sec))
|
||||
return 0;
|
||||
if (!julian_adj(to, 0, 0, &to_jd, &to_sec))
|
||||
return 0;
|
||||
diff_day = to_jd - from_jd;
|
||||
diff_sec = to_sec - from_sec;
|
||||
/* Adjust differences so both positive or both negative */
|
||||
if (diff_day > 0 && diff_sec < 0) {
|
||||
diff_day--;
|
||||
diff_sec += SECS_PER_DAY;
|
||||
}
|
||||
if (diff_day < 0 && diff_sec > 0) {
|
||||
diff_day++;
|
||||
diff_sec -= SECS_PER_DAY;
|
||||
}
|
||||
|
||||
if (pday)
|
||||
*pday = (int)diff_day;
|
||||
if (psec)
|
||||
*psec = diff_sec;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Convert tm structure and offset into julian day and seconds */
|
||||
static int julian_adj(const struct tm *tm, int off_day, long offset_sec,
|
||||
long *pday, int *psec)
|
||||
{
|
||||
int offset_hms;
|
||||
long offset_day, time_jd;
|
||||
int time_year, time_month, time_day;
|
||||
/* split offset into days and day seconds */
|
||||
offset_day = offset_sec / SECS_PER_DAY;
|
||||
/* Avoid sign issues with % operator */
|
||||
offset_hms = offset_sec - (offset_day * SECS_PER_DAY);
|
||||
offset_day += off_day;
|
||||
/* Add current time seconds to offset */
|
||||
offset_hms += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
|
||||
/* Adjust day seconds if overflow */
|
||||
if (offset_hms >= SECS_PER_DAY) {
|
||||
offset_day++;
|
||||
offset_hms -= SECS_PER_DAY;
|
||||
} else if (offset_hms < 0) {
|
||||
offset_day--;
|
||||
offset_hms += SECS_PER_DAY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert date of time structure into a Julian day number.
|
||||
*/
|
||||
|
||||
time_year = tm->tm_year + 1900;
|
||||
time_month = tm->tm_mon + 1;
|
||||
time_day = tm->tm_mday;
|
||||
|
||||
time_jd = date_to_julian(time_year, time_month, time_day);
|
||||
|
||||
/* Work out Julian day of new date */
|
||||
time_jd += offset_day;
|
||||
|
||||
if (time_jd < 0)
|
||||
return 0;
|
||||
|
||||
*pday = time_jd;
|
||||
*psec = offset_hms;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert date to and from julian day Uses Fliegel & Van Flandern algorithm
|
||||
*/
|
||||
static long date_to_julian(int y, int m, int d)
|
||||
{
|
||||
return (1461 * (y + 4800 + (m - 14) / 12)) / 4 +
|
||||
(367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 -
|
||||
(3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075;
|
||||
}
|
||||
|
||||
static void julian_to_date(long jd, int *y, int *m, int *d)
|
||||
{
|
||||
long L = jd + 68569;
|
||||
long n = (4 * L) / 146097;
|
||||
long i, j;
|
||||
|
||||
L = L - (146097 * n + 3) / 4;
|
||||
i = (4000 * (L + 1)) / 1461001;
|
||||
L = L - (1461 * i) / 4 + 31;
|
||||
j = (80 * L) / 2447;
|
||||
*d = L - (2447 * j) / 80;
|
||||
L = j / 11;
|
||||
*m = j + 2 - (12 * L);
|
||||
*y = 100 * (n - 49) + i + L;
|
||||
}
|
||||
@@ -4,7 +4,10 @@
|
||||
|
||||
OPENSSL_gmtime,
|
||||
OPENSSL_gmtime_adj,
|
||||
OPENSSL_gmtime_diff - platform-agnostic OpenSSL time routines
|
||||
OPENSSL_gmtime_diff,
|
||||
OPENSSL_timegm,
|
||||
OPENSSL_posix_to_tm,
|
||||
OPENSSL_tm_to_posix - platform-agnostic OpenSSL time routines
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@@ -15,15 +18,35 @@ OPENSSL_gmtime_diff - platform-agnostic OpenSSL time routines
|
||||
int OPENSSL_gmtime_diff(int *pday, int *psec,
|
||||
const struct tm *from, const struct tm *to);
|
||||
|
||||
#include <openssl/posix_time.h>
|
||||
int OPENSSL_timegm(const struct tm *tm, time_t *out_time);
|
||||
int OPENSSL_posix_to_tm(int64_t time struct tm *out_tm);
|
||||
int OPENSSL_tm_to_posix(struct tm t_tm int64_t *out);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
OPENSSL_gmtime() returns the UTC time specified by I<timer> into the provided
|
||||
I<result> argument.
|
||||
OPENSSL_gmtime() returns the UTC time specified by I<timer> into the
|
||||
provided I<result> argument. |timer| must be in the range of year 0 to
|
||||
9999. Only the fields I<tm_year>, I<tm_mon>, I<tm_mday>, I<tm_hour>,
|
||||
I<tm_min>, and I<tm_sec> will be updated in I<result> on success,
|
||||
all other fields will be zeroed.
|
||||
|
||||
OPENSSL_gmtime_adj() adds the offsets in I<offset_day> and I<offset_sec> to I<tm>.
|
||||
|
||||
OPENSSL_gmtime_diff() calculates the difference between I<from> and I<to>.
|
||||
|
||||
OPENSSL_timegm() converts a time structure in UTC time in I<tm> to a time_t value in
|
||||
I<out_time>.
|
||||
|
||||
OPENSSL_posix_to_tm() converts a int64_t POSIX time value in I<time>,
|
||||
which must be in the range of year 0 to 9999, to a broken out time
|
||||
value in I<tm>. Only the fields I<tm_year>, I<tm_mon>, I<tm_mday>,
|
||||
I<tm_hour>, I<tm_min>, and I<tm_sec> will be updated in I<tm>
|
||||
on success, all other fields will be zeroed.
|
||||
|
||||
OPENSSL_tm_to_posix() converts a time value between the years 0 and 9999 in I<tm>
|
||||
to a POSIX time value in I<out>.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
It is an error to call OPENSSL_gmtime() with I<result> equal to NULL. The
|
||||
@@ -41,7 +64,17 @@ than the number of seconds per day (3600). Leap seconds are not considered.
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
OPENSSL_gmtime() returns NULL on error, or I<result> on success.
|
||||
OPENSSL_gmtime returns I<result> on success or NULL for failure.
|
||||
It can fail if the time is not representable in a struct tm,
|
||||
or if the year is less than 0 or more than 9999.
|
||||
|
||||
OPENSSL_timegm() returns 1 for success or 0 for failure.
|
||||
It can fail if the time is not representable in a time_t,
|
||||
or if the year is less than 0 or more than 9999.
|
||||
|
||||
OPENSSL_posix_to_tm() and OPENSSL_tm_to_posix()
|
||||
return 1 for success or 0 on failure.
|
||||
It is a failure if the year is less than 0 or more than 9999.
|
||||
|
||||
OPENSSL_gmtime_adj() and OPENSSL_gmtime_diff() return 0 on error, and 1 on success.
|
||||
|
||||
@@ -49,6 +82,8 @@ OPENSSL_gmtime_adj() and OPENSSL_gmtime_diff() return 0 on error, and 1 on succe
|
||||
|
||||
OPENSSL_gmtime(), OPENSSL_gmtime_adj() and OPENSSL_gmtime_diff() have been
|
||||
in OpenSSL since 1.0.0.
|
||||
OPENSSL_timegm(), OPENSSL_posix_to_tm() and OPENSSL_tm_to_posix() were originally
|
||||
from BoringSSL and have been in OpenSSL since 4.0.0
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
|
||||
48
include/openssl/posix_time.h
Normal file
48
include/openssl/posix_time.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_HEADER_POSIX_TIME_H
|
||||
# define OPENSSL_HEADER_POSIX_TIME_H
|
||||
# include <stdint.h>
|
||||
# include <time.h>
|
||||
|
||||
# if defined(__cplusplus)
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
/*
|
||||
* OPENSSL_posix_to_tm converts a int64_t POSIX time value in
|
||||
* |time|, which must be in the range of year 0000 to 9999, to a
|
||||
* broken out time value in |tm|. It returns one on success and
|
||||
* zero on error.
|
||||
*/
|
||||
int OPENSSL_posix_to_tm(int64_t time, struct tm *out_tm);
|
||||
|
||||
/*
|
||||
* OPENSSL_tm_to_posix converts a time value between the years 0
|
||||
* and 9999 in |tm| to a POSIX time value in |out|. One is
|
||||
* returned on success, zero is returned on failure. It is a
|
||||
* failure if |tm| contains out of range values.
|
||||
*/
|
||||
int OPENSSL_tm_to_posix(const struct tm *tm, int64_t *out);
|
||||
|
||||
/*
|
||||
* OPENSSL_timegm converts a time value between the years 0 and
|
||||
* 9999 in |tm| to a time_t value in |out|. One is returned on
|
||||
* success, zero is returned on failure. It is a failure if the
|
||||
* converted time can not be represented in a time_t, or if the tm
|
||||
* contains out of range values.
|
||||
*/
|
||||
int OPENSSL_timegm(const struct tm *tm, time_t *out);
|
||||
|
||||
# if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
# endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_POSIX_TIME_H */
|
||||
@@ -569,6 +569,7 @@ include/openssl/pem.h
|
||||
include/openssl/pemerr.h
|
||||
include/openssl/pkcs7.h.in
|
||||
include/openssl/pkcs7err.h
|
||||
include/openssl/posix_time.h
|
||||
include/openssl/prov_ssl.h
|
||||
include/openssl/proverr.h
|
||||
include/openssl/provider.h
|
||||
|
||||
@@ -5947,3 +5947,6 @@ CRYPTO_realloc_array ? 4_0_0 EXIST::FUNCTION:
|
||||
CRYPTO_clear_realloc_array ? 4_0_0 EXIST::FUNCTION:
|
||||
CRYPTO_secure_malloc_array ? 4_0_0 EXIST::FUNCTION:
|
||||
CRYPTO_secure_calloc ? 4_0_0 EXIST::FUNCTION:
|
||||
OPENSSL_posix_to_tm ? 4_0_0 EXIST::FUNCTION:
|
||||
OPENSSL_tm_to_posix ? 4_0_0 EXIST::FUNCTION:
|
||||
OPENSSL_timegm ? 4_0_0 EXIST::FUNCTION:
|
||||
|
||||
Reference in New Issue
Block a user