#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);
+ 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. |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() returns the Unix/Posix time specified by I<timer>
+into the provided I<result> argument. |timer| must be a value of the
+number of seconds relative to 0 hours, 0 minutes, 0 seconds, January 1,
+1970, Coordinated Universal Time, without including leap seconds, and
+must be in the range of the year 0 to 9999 inclusively. I<result> will
+be zeroed, and 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.
OPENSSL_gmtime_adj() adds the offsets in I<offset_day> and I<offset_sec> to I<tm>.
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.
+to a broken out time value in I<tm>. I<time> must be a value of the
+number of seconds relative to 0 hours, 0 minutes, 0 seconds, January 1,
+1970, Coordinated Universal Time, without including leap seconds, and
+must be in the range of the year 0 to 9999 inclusively. I<tm> will be
+zeroed, and 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.
-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>.
+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
-contents of the time_t given by I<timer> are stored into the I<result>. Calling
-with I<timer> equal to NULL means use the current time.
+These functions are intended for use when using I<struct tm> values
+converted from ASN1_TIME values. They are not intended for general
+purpose time conversions, and should not be used for other purposes.
-OPENSSL_gmtime_adj() converts I<tm> into a days and seconds value, adds the
-offsets, then converts back into a I<struct tm> specified by I<tm>. Leap seconds
-are not considered.
+When these functions use a I<struct tm> as input, they consider only
+the I<tm_year>, I<tm_mon>, I<tm_mday>, I<tm_hour>, I<tm_min>, and
+I<tm_sec> fields of the structure, all other fields are ignored.
+Out of range values, including leap seconds, are not permitted.
-OPENSSL_gmtime_diff() calculates the difference between the two I<struct tm>
-structures I<from> and I<to>. The difference in days is placed into I<*pday>,
-the remaining seconds are placed to I<*psec>. The value in I<*psec> will be less
-than the number of seconds per day (3600). Leap seconds are not considered.
+OPENSSL_gmtime_adj() converts I<tm> into a days and seconds value,
+adds I<offset_day> and I<offset_sec> to the values, and then converts
+back into a I<struct tm> specified by I<tm>.
+
+It is an error to call OPENSSL_gmtime() with I<result> equal to
+NULL. The contents of the time_t given by I<timer> are stored into the
+I<result>. Calling with I<timer> equal to NULL means use the current
+time.
+
+OPENSSL_gmtime_adj() converts I<tm> into a days and seconds value,
+adds the offsets, then converts back into a I<struct tm> specified by
+I<tm>.
+
+OPENSSL_gmtime_diff() calculates the difference between the two
+I<struct tm> structures I<from> and I<to>. The difference in days is
+placed into I<*pday>, the remaining seconds are placed to
+I<*psec>. The value in I<*psec> will be less than the number of
+seconds per day (86400).
=head1 RETURN VALUES
-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_gmtime() returns I<result> on success or NULL for failure. It
+can fail if the input time is outside of the range of year 0 to 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() return 1 for success or 0 on failure. It
+can fail if the input time is outside of the range of year 0 to 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_timegm() and OPENSSL_tm_to_posix() return 1 for success or 0 for
+failure. OpenSSL_timegm() can fail it the time is not representable
+in a time_t, and both may fail on invalid or out of range input in the
+input tm.
OPENSSL_gmtime_adj() and OPENSSL_gmtime_diff() return 0 on error, and 1 on success.
+=head1 BUGS
+
+OPENSSL_gmtime() and OPENSSL_timegm() are not platform-agnostic due
+to possible limitations in the range of the platform I<time_t>
+type. OPENSSL_posix_to_tm() and OPENSSL_tm_to_posix() provide similar
+functionality in a platform independent manner.
+
=head1 HISTORY
+OPENSSL_gmtime() returns NULL on error, or I<result> on success.
+
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
return 1;
}
+static int test_asn1_time_conversion(char *time_string, const char *file,
+ int line)
+{
+ int ret = 0;
+ int is_utc = 0;
+ struct tm tm;
+ ASN1_TIME *asn1_time = NULL;
+ ASN1_TIME *result = NULL;
+
+ if (!TEST_ptr(asn1_time = ASN1_TIME_new()))
+ goto err;
+ if (!TEST_true(ASN1_TIME_set_string(asn1_time, time_string)))
+ goto err;
+ if (!TEST_true(ASN1_TIME_to_tm(asn1_time, &tm)))
+ goto err;
+ is_utc = (tm.tm_year >= 50 && tm.tm_year <= 1949);
+ if (is_utc) {
+ /* our original string could have been provided as gen, or utc */
+ if (strlen(time_string) == 13) {
+ if (!TEST_ptr(result = ossl_asn1_time_from_tm(result, &tm,
+ V_ASN1_UNDEF)))
+ goto err;
+ } else {
+ if (!TEST_ptr(result
+ = ossl_asn1_time_from_tm(result, &tm,
+ V_ASN1_GENERALIZEDTIME)))
+ goto err;
+ }
+ } else {
+ if (!TEST_ptr(result
+ = ossl_asn1_time_from_tm(result, &tm,
+ V_ASN1_GENERALIZEDTIME)))
+ goto err;
+ }
+ if (!TEST_true((strcmp(time_string,
+ (const char *)ASN1_STRING_get0_data(result))
+ == 0))) {
+ TEST_info("Expected time: %s, Got time: %s\n", time_string,
+ ASN1_STRING_get0_data(result));
+ goto err;
+ }
+
+ ret = 1;
+
+ err:
+ if (!ret)
+ TEST_info("Failed to convert time %s at %s:%d\n", time_string, file, line);
+ ASN1_STRING_free(asn1_time);
+ ASN1_STRING_free(result);
+ return ret;
+}
+
+/*
+ * These should not go through time_t so they should work on any
+ * platform.
+ */
+static int test_asn1_time_tm_conversions(void)
+{
+ int fails = 0;
+
+ fails += !test_asn1_time_conversion("00000101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("10000101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("16001231235959Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("16010101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("700101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("19691231235959Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("691231235959Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("19700101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("700101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("20000101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("20380119031407Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("20380119031408Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("20380119031409Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("21060207062814Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("21060207062815Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("21060207062816Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("30000101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("40000101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("50000101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("60000101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("70000101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("80000101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("90000101000000Z", __FILE__, __LINE__);
+ fails += !test_asn1_time_conversion("99991231235959Z", __FILE__, __LINE__);
+
+ return fails == 0;
+}
+
static int test_obj_create(void)
{
/* Stolen from evp_extra_test.c */
ADD_TEST(test_obj_create);
ADD_TEST(test_obj_nid_undef);
ADD_TEST(posix_time_test);
+ ADD_TEST(test_asn1_time_tm_conversions);
return 1;
}
/* Time tests for the asn1 module */
+#include <inttypes.h>
#include <limits.h>
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include "testutil.h"
+#include "internal/deprecated.h"
#include "internal/nelem.h"
struct testdata {
return 1;
}
+/* 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)
+#define SECS_PER_HOUR INT64_C(3600)
+#define SECS_PER_DAY (INT64_C(24) * SECS_PER_HOUR)
+
+static int test_gmtime_diff_limits(void)
+{
+ int ret = 0;
+ int64_t expected_days = (MAX_POSIX_TIME - MIN_POSIX_TIME) / SECS_PER_DAY;
+ int64_t expected_secs = (MAX_POSIX_TIME - MIN_POSIX_TIME) % SECS_PER_DAY;
+ char *min_asn1_time = "00000101000000Z";
+ char *max_asn1_time = "99991231235959Z";
+ struct tm min_tm, max_tm;
+ ASN1_TIME *min = NULL, *max = NULL;
+ int pday, psec, saved_value;
+ int64_t pd, ps;
+
+ if (!TEST_ptr(min = ASN1_STRING_new()))
+ goto err;
+ if (!TEST_ptr(max = ASN1_STRING_new()))
+ goto err;
+ if (!TEST_true(ASN1_TIME_set_string(min, min_asn1_time)))
+ goto err;
+ if (!TEST_true(ASN1_TIME_set_string(max, max_asn1_time)))
+ goto err;
+ if (!TEST_true(ASN1_TIME_to_tm(min, &min_tm)))
+ goto err;
+ if (!TEST_true(ASN1_TIME_to_tm(max, &max_tm)))
+ goto err;
+ if (!TEST_true(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm)))
+ goto err;
+ pd = pday;
+ ps = psec;
+ if (!TEST_int64_t_eq(pd, expected_days))
+ goto err;
+ if (!TEST_int64_t_eq(ps, expected_secs))
+ goto err;
+
+ if (!TEST_true(OPENSSL_gmtime_diff(&pday, &psec, &max_tm, &min_tm)))
+ goto err;
+ pd = pday;
+ ps = psec;
+ if (!TEST_int64_t_eq(pd, - expected_days))
+ goto err;
+ if (!TEST_int64_t_eq(ps, - expected_secs))
+ goto err;
+
+ /*
+ * OPENSSL_gmtime[diff/adj] use struct tm as input to public
+ * API. However unlike most platform provided time conversion
+ * functions, it does not validate the values in the tm as per C99
+ * spec before attempting to use it. It also only partly limits
+ * what it will convert to the ASN1_TIME date range, and does not
+ * support the entire range. The define below makes tests that
+ * fail pass to match the current behaviour.
+ */
+#define ITS_TRADITION_THAT_MAKES_IT_OK
+
+ /*
+ * Struct tm permits second 60 in C99. As neither of the values
+ * tested here are actually a for realsies leap second, (We do not
+ * consult any reference for valid leap seconds from the platform
+ * when doing this with Julian date calculations) it should either
+ * be rejected outright, or possibly discarded and treated as 59.
+ *
+ * As we currently reject a leap second in an ASN1 time, this is
+ * moot when using this in the normal way to compare values from
+ * ASN1_TIME, because we won't accept an ASN1_TIME with a seconds
+ * value of 60.
+ */
+ saved_value = max_tm.tm_sec;
+ max_tm.tm_sec = 60;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ pd = pday;
+ ps = psec;
+ if (!TEST_false((pd == expected_days + 1 && ps == 0))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly includes bogus leap second");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ } else {
+ if (!TEST_int64_t_eq(pd, expected_days))
+ goto err;
+ if (!TEST_int64_t_eq(ps, expected_secs))
+ goto err;
+ }
+ }
+ max_tm.tm_sec = saved_value;
+
+ saved_value = min_tm.tm_sec;
+ min_tm.tm_sec = 60;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ pd = pday;
+ ps = psec;
+ if (!TEST_false((pd == expected_days && ps == expected_secs - 60))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly includes bogus leap second");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ } else {
+ if (!TEST_int64_t_eq(pd, expected_days))
+ goto err;
+ if (!TEST_int64_t_eq(ps, expected_secs - 59))
+ goto err;
+ }
+ }
+ min_tm.tm_sec = saved_value;
+
+ saved_value = max_tm.tm_sec;
+ max_tm.tm_sec = 60;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ pd = pday;
+ ps = psec;
+ if (!TEST_false((pd == expected_days + 1 && ps == 0))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly includes bogus leap second");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ } else {
+ if (!TEST_int64_t_eq(pd, expected_days))
+ goto err;
+ if (!TEST_int64_t_eq(ps, expected_secs))
+ goto err;
+ }
+ }
+ max_tm.tm_sec = saved_value;
+
+ saved_value = min_tm.tm_mon;
+ min_tm.tm_mon = 12;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly allows month 12");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ min_tm.tm_mon = saved_value;
+
+ saved_value = min_tm.tm_mon;
+ min_tm.tm_mon = -1;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly allows month -1");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ min_tm.tm_mon = saved_value;
+
+ saved_value = min_tm.tm_mday;
+ min_tm.tm_mday = 32;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly allows the 32nd of January");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ min_tm.tm_mday = saved_value;
+
+ saved_value = min_tm.tm_mday;
+ min_tm.tm_mday = 0;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly allows the 0th of January");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ min_tm.tm_mday = saved_value;
+
+ saved_value = min_tm.tm_hour;
+ min_tm.tm_hour = 24;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly allows hour 24");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ min_tm.tm_hour = saved_value;
+
+ saved_value = min_tm.tm_hour;
+ min_tm.tm_hour = -1;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly allows hour -1");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ min_tm.tm_hour = saved_value;
+
+ saved_value = min_tm.tm_min;
+ min_tm.tm_min = 60;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly allows minute 60");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ min_tm.tm_min = saved_value;
+
+ saved_value = min_tm.tm_min;
+ min_tm.tm_min = -1;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly allows minute -1");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ min_tm.tm_min = saved_value;
+
+ saved_value = min_tm.tm_sec;
+ min_tm.tm_sec = -1;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly allows second -1");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ min_tm.tm_sec = saved_value;
+
+ saved_value = min_tm.tm_sec;
+ min_tm.tm_sec = 61; /* Not allowed per C99. */
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ TEST_info("OPENSSL_gmtime_diff incorrectly allows second 61");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ min_tm.tm_sec = saved_value;
+
+ saved_value = min_tm.tm_year;
+ min_tm.tm_year -= 1;
+ /* These should now be outside the asn1 time range. */
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ goto err;
+ }
+ min_tm.tm_year = saved_value;
+ expected_days -= 365;
+
+ saved_value = max_tm.tm_year;
+ max_tm.tm_year += 1;
+ if (!TEST_false(OPENSSL_gmtime_diff(&pday, &psec, &min_tm, &max_tm))) {
+ goto err;
+ }
+ max_tm.tm_year = saved_value;
+
+ ret = 1;
+
+err:
+ ASN1_STRING_free(min);
+ ASN1_STRING_free(max);
+ return ret;
+}
+
+static int64_t time_t_min(void)
+{
+ time_t t = (time_t) -1;
+
+ if (t > 0) {
+ /* time_t is unsigned 32 bit */
+ OPENSSL_assert(sizeof(time_t) == sizeof(uint32_t));
+ return INT64_C(0);
+ } else {
+#if defined(OPENSSL_SYS_WINDOWS)
+ /* Windows can't handle before 1970, even with signed time_t */
+ return INT64_C(0);
+#else
+ if (sizeof(time_t) == sizeof(int32_t))
+ return (int64_t)INT32_MIN;
+ OPENSSL_assert(sizeof(time_t) == sizeof(uint64_t));
+ return INT64_MIN;
+#endif
+ }
+}
+
+static int64_t time_t_max(void)
+{
+ time_t t = (time_t) -1;
+
+ if (t > 0) {
+ /* time_t is unsigned 32 bit */
+ OPENSSL_assert(sizeof(time_t) == sizeof(uint32_t));
+ return (int64_t)UINT32_MAX;
+ } else {
+ if (sizeof(time_t) == sizeof(int32_t))
+ return (int64_t)INT32_MAX;
+ OPENSSL_assert(sizeof(time_t) == sizeof(uint64_t));
+#if defined(OPENSSL_SYS_WINDOWS)
+ /* Windows can't do past year 3000 even on signed 64 bit time_t */
+ return INT64_C(32535215999);
+#else
+ return INT64_MAX;
+#endif
+ }
+}
+
+static int test_gmtime_range(void)
+{
+ int ret = 0;
+ struct tm tm, copy;
+ time_t tt;
+ int64_t i, platform_min, platform_max;
+ int days;
+ long seconds;
+
+ /*
+ * Ensure that OPENSSL_gmtime() can convert any value
+ * that is both within the range of an ASN1_TIME,
+ * and within the range of the platform time_t
+ */
+ platform_min = time_t_min() < MIN_POSIX_TIME ? MIN_POSIX_TIME : time_t_min();
+ platform_max = time_t_max() > MAX_POSIX_TIME ? MAX_POSIX_TIME : time_t_max();
+
+ for (i = platform_min; i < platform_max; i += 1000000) {
+ tt = (time_t)i;
+ memset(&tm, 0, sizeof(struct tm));
+ if (!TEST_ptr(OPENSSL_gmtime(&tt, &tm))) {
+ TEST_info("OPENSSL_gmtime failed unexpectedly for value %lld", (long long) tt);
+ goto err;
+ }
+ }
+ tt = (time_t)platform_max;
+ if (!TEST_ptr(OPENSSL_gmtime(&tt, &tm))) {
+ TEST_info("OPENSSL_gmtime failed unexpectedly for value %lld", (long long) tt);
+ goto err;
+ }
+
+ if (time_t_min() <= -1) {
+ tt = -1;
+ if (!TEST_ptr(OPENSSL_gmtime(&tt, &tm))) {
+ TEST_info("OPENSSL_gmtime failed unexpectedly for value %lld", (long long) tt);
+ goto err;
+ }
+ }
+ if (time_t_min() <= 0) {
+ tt = 0;
+ if (!TEST_ptr(OPENSSL_gmtime(&tt, &tm))) {
+ TEST_info("OPENSSL_gmtime failed unexpectedly for value %lld", (long long) tt);
+ goto err;
+ }
+ }
+
+ if (time_t_max() >= (int64_t)INT32_MAX) {
+ tt = (time_t)INT32_MAX;
+ if (!TEST_ptr(OPENSSL_gmtime(&tt, &tm))) {
+ TEST_info("OPENSSL_gmtime failed unexpectedly for value %lld", (long long) tt);
+ goto err;
+ }
+ }
+
+ if (time_t_min() >= (int64_t)UINT32_MAX) {
+ tt = (time_t)UINT32_MAX;
+ if (!TEST_ptr(OPENSSL_gmtime(&tt, &tm))) {
+ TEST_info("OPENSSL_gmtime failed unexpectedly for value %lld", (long long) tt);
+ goto err;
+ }
+ }
+
+ /* 00000101000000Z - MIN_POSIX_TIME. */
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = - 1900;
+ tm.tm_mday = 1;
+ memcpy(©, &tm, sizeof(tm));
+
+ /* Adj is expected to fail for a year less than 0000. */
+ if (!TEST_false(OPENSSL_gmtime_adj(©, 0, -1))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly succeeded for year -1");
+ goto err;
+ }
+
+ memcpy(©, &tm, sizeof(tm));
+ /* Adj should work for year 0000. */
+ if (!TEST_true(OPENSSL_gmtime_adj(©, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly failed for year 0");
+ /* ... except that it doesn't */
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+
+ memcpy(©, &tm, sizeof(tm));
+ days = (int) ((MAX_POSIX_TIME - MIN_POSIX_TIME) / SECS_PER_DAY);
+ seconds = (long) ((MAX_POSIX_TIME - MIN_POSIX_TIME) % SECS_PER_DAY);
+ if (!TEST_true(OPENSSL_gmtime_adj(©, days, seconds))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly failed for "
+ "%d days and %ld seconds", - days, - seconds);
+ goto err;
+ }
+ /*
+ * Adj currently fails for result times before 1900, but can
+ * start with a time before that, as long as the result is
+ * before year 10000.
+ */
+ if (!TEST_true(OPENSSL_gmtime_adj(©, - days, - seconds))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly failed for "
+ "%d days and %ld seconds", - days, - seconds);
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ if (!TEST_mem_eq(©, sizeof(copy), &tm, sizeof(tm))) {
+ TEST_info("tm does not have expected value after adj of "
+ "%d days and %ld seconds", days, seconds);
+ goto err;
+ }
+#endif
+ seconds = (long) ((MAX_POSIX_TIME - MIN_POSIX_TIME) % (int64_t)LONG_MAX);
+ days = (int) ((MAX_POSIX_TIME - MIN_POSIX_TIME
+ - (int64_t)seconds) / SECS_PER_DAY);
+ if (!TEST_true(OPENSSL_gmtime_adj(©, days, seconds))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly failed for "
+ "%d days and %ld seconds", - days, - seconds);
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ if (!TEST_true(OPENSSL_gmtime_adj(©, - days, - seconds))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly failed for "
+ "%d days and %ld seconds", - days, - seconds);
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ if (!TEST_mem_eq(©, sizeof(copy), &tm, sizeof(tm))) {
+ TEST_info("tm does not have expected value after adj of "
+ "%d days and %ld seconds", days, seconds);
+ goto err;
+ }
+#endif
+
+ /* 99991231235959Z - MAX_POSIX_TIME. */
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = 9999 - 1900;
+ tm.tm_mon = 11;
+ tm.tm_mday = 31;
+ tm.tm_hour = 23;
+ tm.tm_min = 59;
+ tm.tm_sec = 59;
+ memcpy(©, &tm, sizeof(tm));
+
+ /* Adjust back to the epoch, and back again. */
+ days = (int) (MAX_POSIX_TIME / SECS_PER_DAY);
+ seconds = (long) (MAX_POSIX_TIME % SECS_PER_DAY);
+ if (!TEST_true(OPENSSL_gmtime_adj(©, - days, - seconds))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly failed for "
+ "%d days and %ld seconds", - days, - seconds);
+ goto err;
+ }
+ if (!TEST_true(OPENSSL_gmtime_adj(©, days, seconds))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly failed for "
+ "%d days and %ld seconds", days, seconds);
+ goto err;
+ }
+ if (!TEST_mem_eq(©, sizeof(copy), &tm, sizeof(tm))) {
+ TEST_info("tm does not have expected value after adj of "
+ "%d days and %ld seconds", days, seconds);
+ goto err;
+ }
+
+ /*
+ * Adjust back to the epoch, and back again using as many
+ * seconds as possible.
+ */
+ seconds = (long) (MAX_POSIX_TIME % (int64_t)LONG_MAX);
+ days = (int) ((MAX_POSIX_TIME - (int64_t)seconds) / SECS_PER_DAY);
+ if (!TEST_true(OPENSSL_gmtime_adj(©, - days, - seconds))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly failed for "
+ "%d days and %ld seconds", - days, - seconds);
+ goto err;
+ }
+ if (!TEST_true(OPENSSL_gmtime_adj(©, days, seconds))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly failed for "
+ "%d days and %ld seconds", days, seconds);
+ goto err;
+ }
+ if (!TEST_mem_eq(©, sizeof(copy), &tm, sizeof(tm))) {
+ TEST_info("tm does not have expected value after adj of "
+ "%d days and %ld seconds", days, seconds);
+ goto err;
+ }
+
+ /* Adj is expected to work for year 9999. */
+ if (!TEST_true(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly failed");
+ goto err;
+ }
+
+ /* Adj is expected to fail for a year greater than 9999. */
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 1))) {
+ TEST_info("OPENSSL_gmtime_adj unexpectedly succeeded");
+ goto err;
+ }
+
+ /* The Epoch */
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = 1970 - 1900;
+ tm.tm_mday = 1;
+ memcpy(©, &tm, sizeof(tm));
+
+ tm.tm_mon = 12;
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly allows month 12");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ tm.tm_mon = -1;
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly allows month -1");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ tm.tm_mon = 0;
+
+ tm.tm_mday = 32;
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly allows 32nd of January");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ tm.tm_mday = 0;
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly allows the 0th of January");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ tm.tm_mday = 1;
+
+ tm.tm_hour = 24;
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly allows hour 24");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ tm.tm_hour = -1;
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly allows hour -1");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ tm.tm_hour = 0;
+
+ tm.tm_min = 60;
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly allows minute 60");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ tm.tm_min = -1;
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly allows minute -1");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ tm.tm_min = 0;
+
+ tm.tm_sec = -1;
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly allows second -1");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ tm.tm_sec = 61; /* Not allowed per C99. */
+ if (!TEST_false(OPENSSL_gmtime_adj(&tm, 0, 0))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly allows second 61");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ tm.tm_sec = 0;
+
+ /*
+ * 1970 does not have a leap second, although struct tm in C99
+ * allows them to be there. Since this is a bogus leap second, it
+ * should either be rejected, or should just be ignored and folded
+ * into second 59.
+ *
+ * Note this is moot for us when using tm's converted from an
+ * ASN1_TIME, because we don't allow second 60 in an ASN1_TIME.
+ */
+ tm.tm_sec = 59;
+ memcpy(©, &tm, sizeof(tm));
+ copy.tm_sec = 60;
+ if (!TEST_false(OPENSSL_gmtime_adj(©, 0, 0))) {
+ if (!TEST_mem_eq(©, sizeof(copy), &tm, sizeof(tm))) {
+ TEST_info("OPENSSL_gmtime_adj incorrectly accepted a bogus leap second");
+#if !defined(ITS_TRADITION_THAT_MAKES_IT_OK)
+ goto err;
+#endif
+ }
+ }
+ tm.tm_sec = 0;
+
+ ret = 1;
+
+err:
+ return ret;
+}
+
/*
* this test is here to exercise ossl_asn1_time_from_tm
* with an integer year close to INT_MAX.
ADD_TEST(test_time_dup);
ADD_ALL_TESTS(convert_asn1_to_time_t, OSSL_NELEM(asn1_to_utc));
ADD_TEST(convert_tm_to_asn1_time);
+ ADD_TEST(test_gmtime_diff_limits);
+ ADD_TEST(test_gmtime_range);
return 1;
}