[rs-commit] r34 - in /redwax-tool/trunk: config.h.in configure.ac redwax_openssl.c

rs-commit at redwax.eu rs-commit at redwax.eu
Wed Nov 17 10:34:20 CET 2021


Author: minfrin at redwax.eu
Date: Wed Nov 17 10:34:19 2021
New Revision: 34

Log:
Work around partially backported openssl 1.1.x APIs on
various distros.

Modified:
    redwax-tool/trunk/config.h.in
    redwax-tool/trunk/configure.ac
    redwax-tool/trunk/redwax_openssl.c

Modified: redwax-tool/trunk/config.h.in
==============================================================================
--- redwax-tool/trunk/config.h.in	(original)
+++ redwax-tool/trunk/config.h.in	Wed Nov 17 10:34:19 2021
@@ -5,9 +5,6 @@
 
 /* Define to 1 if you have the `ASN1_TIME_diff' function. */
 #undef HAVE_ASN1_TIME_DIFF
-
-/* Define to 1 if you have the `ASN1_TIME_to_tm' function. */
-#undef HAVE_ASN1_TIME_TO_TM
 
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #undef HAVE_DLFCN_H
@@ -33,9 +30,6 @@
 
 /* Define to 1 if you have the <openssl/core_names.h> header file. */
 #undef HAVE_OPENSSL_CORE_NAMES_H
-
-/* Define to 1 if you have the `OPENSSL_gmtime_diff' function. */
-#undef HAVE_OPENSSL_GMTIME_DIFF
 
 /* Define to 1 if you have the `OPENSSL_init_crypto' function. */
 #undef HAVE_OPENSSL_INIT_CRYPTO

Modified: redwax-tool/trunk/configure.ac
==============================================================================
--- redwax-tool/trunk/configure.ac	(original)
+++ redwax-tool/trunk/configure.ac	Wed Nov 17 10:34:19 2021
@@ -96,7 +96,7 @@
 
 # Checks for library functions.
 AC_FUNC_MALLOC
-AC_CHECK_FUNCS([OPENSSL_init_crypto ASN1_TIME_diff ASN1_TIME_to_tm OPENSSL_gmtime_diff X509_STORE_get0_param X509_STORE_CTX_set0_trusted_stack X509_STORE_CTX_get_num_untrusted X509_get0_notBefore X509_get0_notAfter X509_get_extension_flags X509_up_ref EVP_PKEY_get0_description EVP_PKEY_get_bn_param RSA_get0_n RSA_get0_e RSA_get0_d RSA_get0_p RSA_get0_q RSA_get0_dmp1 RSA_get0_dmq1 RSA_get0_iqmp NSS_Initialize p11_kit_modules_load_and_initialize apr_crypto_clear])
+AC_CHECK_FUNCS([OPENSSL_init_crypto ASN1_TIME_diff X509_STORE_get0_param X509_STORE_CTX_set0_trusted_stack X509_STORE_CTX_get_num_untrusted X509_get0_notBefore X509_get0_notAfter X509_get_extension_flags X509_up_ref EVP_PKEY_get0_description EVP_PKEY_get_bn_param RSA_get0_n RSA_get0_e RSA_get0_d RSA_get0_p RSA_get0_q RSA_get0_dmp1 RSA_get0_dmq1 RSA_get0_iqmp NSS_Initialize p11_kit_modules_load_and_initialize apr_crypto_clear])
 
 AC_OUTPUT
 

Modified: redwax-tool/trunk/redwax_openssl.c
==============================================================================
--- redwax-tool/trunk/redwax_openssl.c	(original)
+++ redwax-tool/trunk/redwax_openssl.c	Wed Nov 17 10:34:19 2021
@@ -31,6 +31,7 @@
 
 #include <openssl/asn1.h>
 #include <openssl/bio.h>
+#include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/pem.h>
 #include <openssl/pkcs12.h>
@@ -78,7 +79,316 @@
     return redwax_x509_store_ctx_idx;
 }
 
-#if !HAVE_OPENSSL_GMTIME_DIFF
+/*
+ * Work around new APIs that don't exist on openssl 1.0.x.
+ *
+ * Also work around new APIs that were backported to openssl 1.0.x but
+ * not added to the headers, breaking the autoconf detection and causing
+ * havoc.
+ */
+#if !HAVE_ASN1_TIME_DIFF
+
+struct tm *redwax_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
+    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;
+}
+
+#ifndef ASN1_STRING_FLAG_X509_TIME
+#define ASN1_STRING_FLAG_X509_TIME 0x100
+#endif
+
+static int leap_year(const int year)
+{
+    if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
+        return 1;
+    return 0;
+}
+
+int ascii_isdigit(const char inchar) {
+    if (inchar > 0x2F && inchar < 0x3A)
+        return 1;
+    return 0;
+}
+
+/*
+ * Compute the day of the week and the day of the year from the year, month
+ * and day.  The day of the year is straightforward, the day of the week uses
+ * a form of Zeller's congruence.  For this months start with March and are
+ * numbered 4 through 15.
+ */
+static void determine_days(struct tm *tm)
+{
+    static const int ydays[12] = {
+        0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+    };
+    int y = tm->tm_year + 1900;
+    int m = tm->tm_mon;
+    int d = tm->tm_mday;
+    int c;
+
+    tm->tm_yday = ydays[m] + d - 1;
+    if (m >= 2) {
+        /* March and onwards can be one day further into the year */
+        tm->tm_yday += leap_year(y);
+        m += 2;
+    } else {
+        /* Treat January and February as part of the previous year */
+        m += 14;
+        y--;
+    }
+    c = y / 100;
+    y %= 100;
+    /* Zeller's congruence */
+    tm->tm_wday = (d + (13 * m) / 5 + y + y / 4 + c / 4 + 5 * c + 6) % 7;
+}
+
+int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d)
+{
+    static const int min[9] = { 0, 0, 1, 1, 0, 0, 0, 0, 0 };
+    static const int max[9] = { 99, 99, 12, 31, 23, 59, 59, 12, 59 };
+    static const int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+    char *a;
+    int n, i, i2, l, o, min_l = 11, strict = 0, end = 6, btz = 5, md;
+    struct tm tmp;
+#if defined(CHARSET_EBCDIC)
+    const char upper_z = 0x5A, num_zero = 0x30, period = 0x2E, minus = 0x2D, plus = 0x2B;
+#else
+    const char upper_z = 'Z', num_zero = '0', period = '.', minus = '-', plus = '+';
+#endif
+    /*
+     * ASN1_STRING_FLAG_X509_TIME is used to enforce RFC 5280
+     * time string format, in which:
+     *
+     * 1. "seconds" is a 'MUST'
+     * 2. "Zulu" timezone is a 'MUST'
+     * 3. "+|-" is not allowed to indicate a time zone
+     */
+    if (d->type == V_ASN1_UTCTIME) {
+        if (d->flags & ASN1_STRING_FLAG_X509_TIME) {
+            min_l = 13;
+            strict = 1;
+        }
+    } else if (d->type == V_ASN1_GENERALIZEDTIME) {
+        end = 7;
+        btz = 6;
+        if (d->flags & ASN1_STRING_FLAG_X509_TIME) {
+            min_l = 15;
+            strict = 1;
+        } else {
+            min_l = 13;
+        }
+    } else {
+        return 0;
+    }
+
+    l = d->length;
+    a = (char *)d->data;
+    o = 0;
+    memset(&tmp, 0, sizeof(tmp));
+
+    /*
+     * GENERALIZEDTIME is similar to UTCTIME except the year is represented
+     * as YYYY. This stuff treats everything as a two digit field so make
+     * first two fields 00 to 99
+     */
+
+    if (l < min_l)
+        goto err;
+    for (i = 0; i < end; i++) {
+        if (!strict && (i == btz) && ((a[o] == upper_z) || (a[o] == plus) || (a[
+o] == minus))) {
+            i++;
+            break;
+        }
+        if (!ascii_isdigit(a[o]))
+            goto err;
+        n = a[o] - num_zero;
+        /* incomplete 2-digital number */
+        if (++o == l)
+            goto err;
+
+        if (!ascii_isdigit(a[o]))
+            goto err;
+        n = (n * 10) + a[o] - num_zero;
+        /* no more bytes to read, but we haven't seen time-zone yet */
+        if (++o == l)
+            goto err;
+
+        i2 = (d->type == V_ASN1_UTCTIME) ? i + 1 : i;
+
+        if ((n < min[i2]) || (n > max[i2]))
+            goto err;
+        switch (i2) {
+        case 0:
+            /* UTC will never be here */
+            tmp.tm_year = n * 100 - 1900;
+            break;
+        case 1:
+            if (d->type == V_ASN1_UTCTIME)
+                tmp.tm_year = n < 50 ? n + 100 : n;
+            else
+                tmp.tm_year += n;
+            break;
+        case 2:
+            tmp.tm_mon = n - 1;
+            break;
+        case 3:
+            /* check if tm_mday is valid in tm_mon */
+            if (tmp.tm_mon == 1) {
+                /* it's February */
+                md = mdays[1] + leap_year(tmp.tm_year + 1900);
+            } else {
+                md = mdays[tmp.tm_mon];
+            }
+            if (n > md)
+                goto err;
+            tmp.tm_mday = n;
+            determine_days(&tmp);
+            break;
+        case 4:
+            tmp.tm_hour = n;
+            break;
+        case 5:
+            tmp.tm_min = n;
+            break;
+        case 6:
+            tmp.tm_sec = n;
+            break;
+        }
+    }
+
+    /*
+     * Optional fractional seconds: decimal point followed by one or more
+     * digits.
+     */
+    if (d->type == V_ASN1_GENERALIZEDTIME && a[o] == period) {
+        if (strict)
+            /* RFC 5280 forbids fractional seconds */
+            goto err;
+        if (++o == l)
+            goto err;
+        i = o;
+        while ((o < l) && ascii_isdigit(a[o]))
+            o++;
+        /* Must have at least one digit after decimal point */
+        if (i == o)
+            goto err;
+        /* no more bytes to read, but we haven't seen time-zone yet */
+        if (o == l)
+            goto err;
+    }
+
+    /*
+     * 'o' will never point to '\0' at this point, the only chance
+     * 'o' can point to '\0' is either the subsequent if or the first
+     * else if is true.
+     */
+    if (a[o] == upper_z) {
+        o++;
+    } else if (!strict && ((a[o] == plus) || (a[o] == minus))) {
+        int offsign = a[o] == minus ? 1 : -1;
+        int offset = 0;
+
+        o++;
+        /*
+         * if not equal, no need to do subsequent checks
+         * since the following for-loop will add 'o' by 4
+         * and the final return statement will check if 'l'
+         * and 'o' are equal.
+         */
+        if (o + 4 != l)
+            goto err;
+        for (i = end; i < end + 2; i++) {
+            if (!ascii_isdigit(a[o]))
+                goto err;
+            n = a[o] - num_zero;
+            o++;
+            if (!ascii_isdigit(a[o]))
+                goto err;
+            n = (n * 10) + a[o] - num_zero;
+            i2 = (d->type == V_ASN1_UTCTIME) ? i + 1 : i;
+            if ((n < min[i2]) || (n > max[i2]))
+                goto err;
+            /* if tm is NULL, no need to adjust */
+            if (tm != NULL) {
+                if (i == end)
+                    offset = n * 3600;
+                else if (i == end + 1)
+                    offset += n * 60;
+            }
+            o++;
+        }
+        if (offset && !redwax_OPENSSL_gmtime_adj(&tmp, 0, offset * offsign))
+            goto err;
+    } else {
+        /* not Z, or not +/- in non-strict mode */
+        goto err;
+    }
+    if (o == l) {
+        /* success, check if tm should be filled */
+        if (tm != NULL)
+            *tm = tmp;
+        return 1;
+    }
+err:
+    return 0;
+}
+
+int redwax_ASN1_TIME_to_tm(const ASN1_TIME *s, struct tm *tm)
+{
+    if (s == NULL) {
+        time_t now_t;
+
+        time(&now_t);
+        memset(tm, 0, sizeof(*tm));
+        if (redwax_OPENSSL_gmtime(&now_t, tm) != NULL)
+            return 1;
+        return 0;
+    }
+
+    return asn1_time_to_tm(tm, s);
+}
+
 /*
  * Convert date to and from julian day Uses Fliegel & Van Flandern algorithm
  */
@@ -133,7 +443,7 @@
     return 1;
 }
 
-int OPENSSL_gmtime_diff(int *pday, int *psec,
+int redwax_OPENSSL_gmtime_diff(int *pday, int *psec,
                         const struct tm *from, const struct tm *to)
 {
     int from_sec, to_sec, diff_sec;
@@ -162,19 +472,17 @@
     return 1;
 
 }
-#endif
-
-#if !HAVE_ASN1_TIME_DIFF
+
 int ASN1_TIME_diff(int *pday, int *psec,
                    const ASN1_TIME *from, const ASN1_TIME *to)
 {
     struct tm tm_from, tm_to;
 
-    if (!ASN1_TIME_to_tm(from, &tm_from))
+    if (!redwax_ASN1_TIME_to_tm(from, &tm_from))
         return 0;
-    if (!ASN1_TIME_to_tm(to, &tm_to))
+    if (!redwax_ASN1_TIME_to_tm(to, &tm_to))
         return 0;
-    return OPENSSL_gmtime_diff(pday, psec, &tm_from, &tm_to);
+    return redwax_OPENSSL_gmtime_diff(pday, psec, &tm_from, &tm_to);
 }
 #endif
 



More information about the rs-commit mailing list