From f21279a16d6bd54f2e4c617a28077aea6954f74e Mon Sep 17 00:00:00 2001 From: tb Date: Sun, 18 Feb 2024 16:28:37 +0000 Subject: [PATCH] Add posix_time.h from BoringSSL This is prepares to expose some internal API as OPENSSL_tm_to_posix() and OPENSSL_posix_to_tm(). They will be used in libtls and ocspcheck(8) to get rid of the portability nightmare that is timegm(). Also fix the location of OPENSSL_gmtime() and OPENSSL_timegm() (this API is not yet exposed). The former is from OpenSSL and surprisingly lives in crypto.h, not asn1.h, and the latter is BoringSSL API and lives in the new posix_time.h. Initial diff from beck, this pulls in further upstream work after review feedback. ok jsing --- lib/libcrypto/Makefile | 3 +- lib/libcrypto/Symbols.namespace | 4 + lib/libcrypto/asn1/a_time_posix.c | 106 ++++++++++++---------- lib/libcrypto/asn1/asn1.h | 7 +- lib/libcrypto/asn1/asn1_local.h | 4 +- lib/libcrypto/asn1/posix_time.h | 54 +++++++++++ lib/libcrypto/crypto.h | 10 +- lib/libcrypto/hidden/openssl/posix_time.h | 32 +++++++ 8 files changed, 160 insertions(+), 60 deletions(-) create mode 100644 lib/libcrypto/asn1/posix_time.h create mode 100644 lib/libcrypto/hidden/openssl/posix_time.h diff --git a/lib/libcrypto/Makefile b/lib/libcrypto/Makefile index 2ac252aabcb..0ddf74246c0 100644 --- a/lib/libcrypto/Makefile +++ b/lib/libcrypto/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.167 2024/01/27 17:14:33 tb Exp $ +# $OpenBSD: Makefile,v 1.168 2024/02/18 16:28:37 tb Exp $ LIB= crypto LIBREBUILD=y @@ -705,6 +705,7 @@ HDRS=\ ${LCRYPTO_SRC}/aes/aes.h \ ${LCRYPTO_SRC}/asn1/asn1.h \ ${LCRYPTO_SRC}/asn1/asn1t.h \ + ${LCRYPTO_SRC}/asn1/posix_time.h \ ${LCRYPTO_SRC}/bf/blowfish.h \ ${LCRYPTO_SRC}/bio/bio.h \ ${LCRYPTO_SRC}/bn/bn.h \ diff --git a/lib/libcrypto/Symbols.namespace b/lib/libcrypto/Symbols.namespace index 08f070e79ca..62d6b5a3ad7 100644 --- a/lib/libcrypto/Symbols.namespace +++ b/lib/libcrypto/Symbols.namespace @@ -2645,3 +2645,7 @@ _libre_i2d_DHparams _libre_DHparams_print_fp _libre_DHparams_print _libre_ERR_load_DH_strings +_libre_OPENSSL_gmtime +_libre_OPENSSL_timegm +_libre_OPENSSL_posix_to_tm +_libre_OPENSSL_tm_to_posix diff --git a/lib/libcrypto/asn1/a_time_posix.c b/lib/libcrypto/asn1/a_time_posix.c index 5d10d21d3c6..d4439b47010 100644 --- a/lib/libcrypto/asn1/a_time_posix.c +++ b/lib/libcrypto/asn1/a_time_posix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: a_time_posix.c,v 1.4 2023/11/13 12:46:07 beck Exp $ */ +/* $OpenBSD: a_time_posix.c,v 1.5 2024/02/18 16:28:38 tb Exp $ */ /* * Copyright (c) 2022, Google Inc. * Copyright (c) 2022, Bob Beck @@ -23,10 +23,14 @@ #include #include +#include #include #include #include +#include + +#include "crypto_internal.h" #define SECS_PER_HOUR (int64_t)(60 * 60) #define SECS_PER_DAY (int64_t)(24 * SECS_PER_HOUR) @@ -36,7 +40,7 @@ * to 9999? */ static int -is_valid_date(int year, int month, int day) +is_valid_date(int64_t year, int64_t month, int64_t day) { int days_in_month; if (day < 1 || month < 1 || year < 0 || year > 9999) @@ -80,13 +84,16 @@ is_valid_time(int hours, int minutes, int seconds) 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_epoch_time(int64_t time) +is_valid_posix_time(int64_t time) { - /* 0000-01-01 00:00:00 UTC to 9999-12-31 23:59:59 UTC */ - return (int64_t)-62167219200LL <= time && - time <= (int64_t)253402300799LL; + return MIN_POSIX_TIME <= time && time <= MAX_POSIX_TIME; } /* @@ -95,8 +102,8 @@ is_valid_epoch_time(int64_t time) * (Public Domain) */ static int -posix_time_from_utc(int year, int month, int day, int hours, int minutes, - int seconds, int64_t *out_time) +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; @@ -132,7 +139,7 @@ utc_from_posix_time(int64_t time, int *out_year, int *out_month, int *out_day, int64_t days, leftover_seconds, era, day_of_era, year_of_era, day_of_year, month_of_year; - if (!is_valid_epoch_time(time)) + if (!is_valid_posix_time(time)) return 0; days = time / SECS_PER_DAY; @@ -167,40 +174,41 @@ utc_from_posix_time(int64_t time, int *out_year, int *out_month, int *out_day, return 1; } -static int -asn1_time_tm_to_posix(const struct tm *tm, int64_t *out) +int +OPENSSL_tm_to_posix(const struct tm *tm, int64_t *out) { - /* Ensure additions below do not overflow */ - if (tm->tm_year > 9999) - return 0; - if (tm->tm_mon > 12) - return 0; - - return posix_time_from_utc(tm->tm_year + 1900, tm->tm_mon + 1, - tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, 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); } +LCRYPTO_ALIAS(OPENSSL_tm_to_posix); -static int -asn1_time_posix_to_tm(int64_t time, struct tm *out_tm) +int +OPENSSL_posix_to_tm(int64_t time, struct tm *out_tm) { - memset(out_tm, 0, sizeof(struct tm)); - if (!utc_from_posix_time(time, &out_tm->tm_year, &out_tm->tm_mon, - &out_tm->tm_mday, &out_tm->tm_hour, &out_tm->tm_min, - &out_tm->tm_sec)) + 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; - out_tm->tm_year -= 1900; - out_tm->tm_mon -= 1; + tmp_tm.tm_year -= 1900; + tmp_tm.tm_mon -= 1; + + *out_tm = tmp_tm; return 1; } +LCRYPTO_ALIAS(OPENSSL_posix_to_tm); int asn1_time_tm_to_time_t(const struct tm *tm, time_t *out) { int64_t posix_time; - if (!asn1_time_tm_to_posix(tm, &posix_time)) + if (!OPENSSL_tm_to_posix(tm, &posix_time)) return 0; #ifdef SMALL_TIME_T @@ -219,7 +227,7 @@ asn1_time_time_t_to_tm(const time_t *time, struct tm *out_tm) { int64_t posix_time = *time; - return asn1_time_posix_to_tm(posix_time, out_tm); + return OPENSSL_posix_to_tm(posix_time, out_tm); } int @@ -236,28 +244,29 @@ OPENSSL_gmtime(const time_t *time, struct tm *out_tm) { } LCRYPTO_ALIAS(OPENSSL_gmtime); +/* Public API in OpenSSL. BoringSSL uses int64_t instead of long. */ int -OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec) +OPENSSL_gmtime_adj(struct tm *tm, int offset_day, int64_t offset_sec) { int64_t posix_time; - /* Ensure additions below do not overflow */ - if (tm->tm_year > 9999) - return 0; - if (tm->tm_mon > 12) + if (!OPENSSL_tm_to_posix(tm, &posix_time)) return 0; - if (!posix_time_from_utc(tm->tm_year + 1900, tm->tm_mon + 1, - tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, &posix_time)) - return 0; + CTASSERT(INT_MAX <= INT64_MAX / SECS_PER_DAY); + CTASSERT(MAX_POSIX_TIME <= INT64_MAX - INT_MAX * SECS_PER_DAY); + CTASSERT(MIN_POSIX_TIME >= INT64_MIN - INT_MIN * SECS_PER_DAY); + + posix_time += offset_day * SECS_PER_DAY; - if (!utc_from_posix_time(posix_time + off_day * SECS_PER_DAY + - offset_sec, &tm->tm_year, &tm->tm_mon, &tm->tm_mday, &tm->tm_hour, - &tm->tm_min, &tm->tm_sec)) + 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; - tm->tm_year -= 1900; - tm->tm_mon -= 1; + if (!OPENSSL_posix_to_tm(posix_time, tm)) + return 0; return 1; } @@ -268,20 +277,17 @@ OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from, { int64_t time_to, time_from, timediff, daydiff; - if (!posix_time_from_utc(to->tm_year + 1900, to->tm_mon + 1, - to->tm_mday, to->tm_hour, to->tm_min, to->tm_sec, &time_to)) + if (!OPENSSL_tm_to_posix(to, &time_to) || + !OPENSSL_tm_to_posix(from, &time_from)) return 0; - if (!posix_time_from_utc(from->tm_year + 1900, from->tm_mon + 1, - from->tm_mday, from->tm_hour, from->tm_min, - from->tm_sec, &time_from)) - return 0; + /* Times are in range, so these calculations cannot overflow. */ + CTASSERT(SECS_PER_DAY <= INT_MAX); + CTASSERT((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; - if (daydiff > INT_MAX || daydiff < INT_MIN) - return 0; *out_secs = timediff; *out_days = daydiff; diff --git a/lib/libcrypto/asn1/asn1.h b/lib/libcrypto/asn1/asn1.h index d876b25b0b7..cf288e50603 100644 --- a/lib/libcrypto/asn1/asn1.h +++ b/lib/libcrypto/asn1/asn1.h @@ -1,4 +1,4 @@ -/* $OpenBSD: asn1.h,v 1.82 2023/12/16 12:25:02 tb Exp $ */ +/* $OpenBSD: asn1.h,v 1.83 2024/02/18 16:28:38 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -915,11 +915,6 @@ int SMIME_text(BIO *in, BIO *out); void ERR_load_ASN1_strings(void); -#if defined(LIBRESSL_INTERNAL) || defined(LIBRESSL_NEXT_API) -int OPENSSL_timegm(const struct tm *tm, time_t *out); -struct tm *OPENSSL_gmtime(const time_t *time, struct tm *out_tm); -#endif - /* Error codes for the ASN1 functions. */ /* Function codes. */ diff --git a/lib/libcrypto/asn1/asn1_local.h b/lib/libcrypto/asn1/asn1_local.h index 499e160275e..a5478faa0b8 100644 --- a/lib/libcrypto/asn1/asn1_local.h +++ b/lib/libcrypto/asn1/asn1_local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: asn1_local.h,v 1.7 2024/01/06 20:47:01 tb Exp $ */ +/* $OpenBSD: asn1_local.h,v 1.8 2024/02/18 16:28:38 tb Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2006. */ @@ -160,7 +160,7 @@ ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a, int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp); ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, long length); -int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec); +int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, int64_t offset_sec); int OPENSSL_gmtime_diff(int *pday, int *psec, const struct tm *from, const struct tm *to); int asn1_time_time_t_to_tm(const time_t *time, struct tm *out_tm); diff --git a/lib/libcrypto/asn1/posix_time.h b/lib/libcrypto/asn1/posix_time.h new file mode 100644 index 00000000000..82b3f30bc2f --- /dev/null +++ b/lib/libcrypto/asn1/posix_time.h @@ -0,0 +1,54 @@ +/* $OpenBSD: posix_time.h,v 1.1 2024/02/18 16:28:38 tb Exp $ */ +/* + * Copyright (c) 2022, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef OPENSSL_HEADER_POSIX_TIME_H +#define OPENSSL_HEADER_POSIX_TIME_H + +#include +#include + +#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 */ diff --git a/lib/libcrypto/crypto.h b/lib/libcrypto/crypto.h index 07a55ec1f60..47e7eff37cc 100644 --- a/lib/libcrypto/crypto.h +++ b/lib/libcrypto/crypto.h @@ -1,4 +1,4 @@ -/* $OpenBSD: crypto.h,v 1.63 2023/07/28 10:19:20 tb Exp $ */ +/* $OpenBSD: crypto.h,v 1.64 2024/02/18 16:28:37 tb Exp $ */ /* ==================================================================== * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. * @@ -522,6 +522,14 @@ int CRYPTO_memcmp(const void *a, const void *b, size_t len); int OPENSSL_init_crypto(uint64_t opts, const void *settings); void OPENSSL_cleanup(void); +/* + * OpenSSL helpfully put OPENSSL_gmtime() here because all other time related + * functions are in asn1.h. + */ +#if defined(LIBRESSL_INTERNAL) || defined(LIBRESSL_NEXT_API) +struct tm *OPENSSL_gmtime(const time_t *time, struct tm *out_tm); +#endif + void ERR_load_CRYPTO_strings(void); /* Error codes for the CRYPTO functions. */ diff --git a/lib/libcrypto/hidden/openssl/posix_time.h b/lib/libcrypto/hidden/openssl/posix_time.h new file mode 100644 index 00000000000..306d43eae5a --- /dev/null +++ b/lib/libcrypto/hidden/openssl/posix_time.h @@ -0,0 +1,32 @@ +/* $OpenBSD: posix_time.h,v 1.1 2024/02/18 16:28:38 tb Exp $ */ +/* + * Copyright (c) 2024 Bob Beck + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LIBCRYPTO_POSIX_TIME_H +#define _LIBCRYPTO_POSIX_TIME_H + +#ifndef _MSC_VER +#include_next +#else +#include "../include/openssl/posix_time.h" +#endif +#include "crypto_namespace.h" + +LCRYPTO_USED(OPENSSL_posix_to_tm); +LCRYPTO_USED(OPENSSL_tm_to_posix); +LCRYPTO_USED(OPENSSL_timegm); + +#endif /* _LIBCRYPTO_POSIX_TIME_H */ -- 2.20.1