djgpp: Set TZ=UTC to convert UTC timestamp to time_t
authorJ.W. Jagersma <jwjagersma@gmail.com>
Mon, 26 Sep 2022 18:35:46 +0000 (20:35 +0200)
committerTomas Mraz <tomas@openssl.org>
Thu, 29 Sep 2022 10:00:30 +0000 (12:00 +0200)
Since djgpp has neither a timezone variable or timegm(), this horrible
method must be used.  It is the only one I could find that produces
accurate results, and is recommended as portable alternative to
timegm() by the GNU libc manual.  Reference:

https://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html#index-timegm

Now, a much nicer alternative solution could be:

    timestamp_local = mktime(timestamp_tm);
    timestamp_utc = timestamp_local + timestamp_tm->tm_gmtoff
                                    - (timestamp_tm->tm_isdst ? 3600 : 0);

This works due to the fact that mktime() populates the tm_gmtoff and
tm_isdst fields in the source timestamp.  It is accurate everywhere in
the world, *except* on Lord Howe Island, Australia, where a 30 minute
DST offset is used.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19274)

crypto/asn1/a_time.c

index 23828b1e3148f95ce9af5fabd9d26afe372aa6cb..92be1109a2fc20411663de9e8a65fac44618677c 100644 (file)
@@ -605,7 +605,9 @@ time_t ossl_asn1_string_to_time_t(const char *asn1_string)
 {
     ASN1_TIME *timestamp_asn1 = NULL;
     struct tm *timestamp_tm = NULL;
-#ifndef USE_TIMEGM
+#if defined(__DJGPP__)
+    char *tz = NULL;
+#elif !defined(USE_TIMEGM)
     time_t timestamp_local;
 #endif
     time_t timestamp_utc;
@@ -627,17 +629,38 @@ time_t ossl_asn1_string_to_time_t(const char *asn1_string)
         ASN1_TIME_free(timestamp_asn1);
         return -1;
     }
+    ASN1_TIME_free(timestamp_asn1);
+
+#if defined(__DJGPP__)
+    /*
+     * This is NOT thread-safe.  Do not use this method for platforms other
+     * than djgpp.
+     */
+    tz = getenv("TZ");
+    if (tz != NULL) {
+        tz = OPENSSL_strdup(tz);
+        if (tz == NULL) {
+            OPENSSL_free(timestamp_tm);
+            return -1;
+        }
+    }
+    setenv("TZ", "UTC", 1);
+
+    timestamp_utc = mktime(timestamp_tm);
 
-#ifdef USE_TIMEGM
+    if (tz != NULL) {
+        setenv("TZ", tz, 1);
+        OPENSSL_free(tz);
+    } else {
+        unsetenv("TZ");
+    }
+#elif defined(USE_TIMEGM)
     timestamp_utc = timegm(timestamp_tm);
-    OPENSSL_free(timestamp_tm);
 #else
     timestamp_local = mktime(timestamp_tm);
-    OPENSSL_free(timestamp_tm);
-
     timestamp_utc = timestamp_local - timezone;
 #endif
+    OPENSSL_free(timestamp_tm);
 
-    ASN1_TIME_free(timestamp_asn1);
     return timestamp_utc;
 }