Refactor TimeConversion class 11/51911/2
authorKyungwook Tak <k.tak@samsung.com>
Tue, 17 Nov 2015 04:55:25 +0000 (13:55 +0900)
committerKyungwook Tak <k.tak@samsung.com>
Tue, 17 Nov 2015 07:55:55 +0000 (16:55 +0900)
 * use latest code from openssl of tizen
 * use one code of time conversion in signature validator

Change-Id: I8c4ef63bcd1e65b42a7f9a0a4a70f51129b806df
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
tests/CMakeLists.txt
tests/vcore/CMakeLists.txt
tests/vcore/test-time-conversion.cpp [new file with mode: 0644]
vcore/vcore/Certificate.cpp
vcore/vcore/SignatureValidator.cpp
vcore/vcore/TimeConversion.cpp
vcore/vcore/TimeConversion.h

index 3ab883e..a49d84e 100644 (file)
@@ -21,6 +21,7 @@ SET(TARGET_PLUGIN_SAMPLE "cert-svc-validator-plugin")
 PKG_CHECK_MODULES(TEST_DEP
     REQUIRED
     libpcrecpp
+    openssl
     )
 
 SET(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR})
@@ -45,7 +46,6 @@ SET(DPL_TEST_SOURCES
 INCLUDE_DIRECTORIES(
     SYSTEM
     ${TEST_DEP_INCLUDE_DIRS}
-    ${PROJECT_SOURCE_DIR}/include
     ${PROJECT_SOURCE_DIR}/vcore
     ${TEST_DIR}/dpl/include
     )
index 77d9f56..1d96ca2 100644 (file)
@@ -27,10 +27,10 @@ SET(VCORE_TESTS_SOURCES
     ${CERT_SVC_VCORE_TESTS_DIR}/test-common.cpp
     ${CERT_SVC_VCORE_TESTS_DIR}/test-signature-validator.cpp
     ${CERT_SVC_VCORE_TESTS_DIR}/test-ocsp-check.cpp
+    ${CERT_SVC_VCORE_TESTS_DIR}/test-time-conversion.cpp
     )
 
 INCLUDE_DIRECTORIES(
-    ${PROJECT_SOURCE_DIR}/vcore/src
     ${CERT_SVC_VCORE_TESTS_DIR}
     )
 
diff --git a/tests/vcore/test-time-conversion.cpp b/tests/vcore/test-time-conversion.cpp
new file mode 100644 (file)
index 0000000..95cbc3f
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        test-time-conversion.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Internal class unit test : TimeConversion
+ */
+
+#include <cstring>
+#include <openssl/asn1.h>
+
+#include <dpl/test/test_runner.h>
+
+#include "test-common.h"
+
+#include <vcore/TimeConversion.h>
+
+static void UnitWrapper(const char *str, int type, int expected)
+{
+       ASN1_TIME asn1Time;
+
+       memset(&asn1Time, 0, sizeof(ASN1_TIME));
+
+       ASN1_STRING_set(&asn1Time, str, strlen(str));
+       asn1Time.type = type;
+
+       time_t t = 0;
+       int ret = ValidationCore::asn1TimeToTimeT(&asn1Time, &t);
+       RUNNER_ASSERT_MSG(ret == expected,
+               "ret: " << ret
+               << " expected: " << expected
+               << " time t: " << t);
+}
+
+RUNNER_TEST_GROUP_INIT(T0040_TIME_CONVERSION)
+
+RUNNER_TEST(T004101_utctime_positive_sec_and_Z_terminated)
+{
+       UnitWrapper("991231235959Z", V_ASN1_UTCTIME, 1);
+}
+
+RUNNER_TEST(T004102_utctime_positive_no_sec_and_Z_terminated)
+{
+       UnitWrapper("9912312359Z", V_ASN1_UTCTIME, 1);
+}
+
+RUNNER_TEST(T004103_utctime_positive_sec_and_plus)
+{
+       UnitWrapper("991231235959+1259", V_ASN1_UTCTIME, 1);
+}
+
+RUNNER_TEST(T004104_utctime_positive_sec_and_minus)
+{
+       UnitWrapper("991231235959-1259", V_ASN1_UTCTIME, 1);
+}
+
+RUNNER_TEST(T004105_utctime_positive_no_sec_and_plus)
+{
+       UnitWrapper("9912312359+1259", V_ASN1_UTCTIME, 1);
+}
+
+RUNNER_TEST(T004106_utctime_positive_no_sec_and_minus)
+{
+       UnitWrapper("9912312359-1259", V_ASN1_UTCTIME, 1);
+}
+
+
+
+RUNNER_TEST(T004201_utctime_negative_invalid_format_no_Z)
+{
+       UnitWrapper("9912312359", V_ASN1_UTCTIME, 0);
+}
+
+RUNNER_TEST(T004202_utctime_negative_invalid_format_no_minute)
+{
+       UnitWrapper("991231235Z", V_ASN1_UTCTIME, 0);
+}
+
+RUNNER_TEST(T004203_utctime_negative_invalid_format_too_long)
+{
+       UnitWrapper("9912312359+12590", V_ASN1_UTCTIME, 0);
+}
+
+
+
+RUNNER_TEST(T004301_gentime_positive_full_local_only)
+{
+       UnitWrapper("20001231235959.999", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+RUNNER_TEST(T004302_gentime_positive_full_utc_only)
+{
+       UnitWrapper("20001231235959.999Z", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+RUNNER_TEST(T004303_gentime_positive_full_local_and_utc_plus)
+{
+       UnitWrapper("20001231235959.999+1259", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+RUNNER_TEST(T004304_gentime_positive_full_local_and_utc_minus)
+{
+       UnitWrapper("20001231235959.999-1259", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+RUNNER_TEST(T004305_gentime_positive_no_fff_local_only)
+{
+       UnitWrapper("20001231235959", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+RUNNER_TEST(T004306_gentime_positive_no_fff_utc_only)
+{
+       UnitWrapper("20001231235959Z", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+RUNNER_TEST(T004307_gentime_positive_no_fff_local_and_utc_plus)
+{
+       UnitWrapper("20001231235959+1259", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+RUNNER_TEST(T004308_gentime_positive_no_fff_local_and_utc_minus)
+{
+       UnitWrapper("20001231235959-1259", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+RUNNER_TEST(T004309_gentime_positive_no_sec_utc_only)
+{
+       UnitWrapper("200012312359Z", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+RUNNER_TEST(T004310_gentime_positive_no_sec_local_and_utc_plus)
+{
+       UnitWrapper("200012312359+1259", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+RUNNER_TEST(T004311_gentime_positive_no_sec_local_and_utc_minus)
+{
+       UnitWrapper("200012312359-1259", V_ASN1_GENERALIZEDTIME, 1);
+}
+
+
+
+RUNNER_TEST(T004401_gentime_negative_invalid_format)
+{
+       UnitWrapper("200012312359599999", V_ASN1_GENERALIZEDTIME, 0);
+}
+
+RUNNER_TEST(T004402_gentime_negative_invalid_format)
+{
+       UnitWrapper("200012312359591", V_ASN1_GENERALIZEDTIME, 0);
+}
+
+RUNNER_TEST(T004403_gentime_negative_invalid_format)
+{
+       UnitWrapper("2000123123595A", V_ASN1_GENERALIZEDTIME, 0);
+}
+
+RUNNER_TEST(T004404_gentime_negative_invalid_format)
+{
+       UnitWrapper("20001231235959A", V_ASN1_GENERALIZEDTIME, 0);
+}
+
+RUNNER_TEST(T004405_gentime_negative_invalid_format)
+{
+       UnitWrapper("2000123123595", V_ASN1_GENERALIZEDTIME, 0);
+}
+
+RUNNER_TEST(T004406_gentime_negative_invalid_format)
+{
+       UnitWrapper("20001231235959+-", V_ASN1_GENERALIZEDTIME, 0);
+}
+
+RUNNER_TEST(T004407_gentime_negative_invalid_format)
+{
+       UnitWrapper("20001231235959+12599", V_ASN1_GENERALIZEDTIME, 0);
+}
+
+RUNNER_TEST(T004408_gentime_negative_invalid_format)
+{
+       UnitWrapper("20001231235959+1359", V_ASN1_GENERALIZEDTIME, 0);
+}
+
+RUNNER_TEST(T004409_gentime_negative_invalid_format)
+{
+       UnitWrapper("20000031235959", V_ASN1_GENERALIZEDTIME, 0);
+}
+
+/* k.tak : From openssl source, it's negative case for now */
+RUNNER_TEST(T004410_gentime_negative_no_sec_local_only)
+{
+       UnitWrapper("200012312359", V_ASN1_GENERALIZEDTIME, 0);
+}
+
index ccdc1a6..ba27346 100644 (file)
@@ -446,7 +446,7 @@ time_t Certificate::getNotAfter() const
                       "Reading Not After error.");
 
     time_t output;
-    if (asn1TimeToTimeT(time, &output))
+    if (asn1TimeToTimeT(time, &output) == 0)
         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
                       "Converting ASN1_time to time_t error.");
 
@@ -461,7 +461,7 @@ time_t Certificate::getNotBefore() const
                       "Reading Not Before error.");
 
     time_t output;
-    if (asn1TimeToTimeT(time, &output))
+    if (asn1TimeToTimeT(time, &output) == 0)
         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
                       "Converting ASN1_time to time_t error.");
 
index f899339..5cbda8a 100644 (file)
@@ -53,105 +53,22 @@ enum class CertTimeStatus : int {
        EXPIRED
 };
 
-struct tm _ASN1_GetTimeT(ASN1_TIME *time)
+inline time_t _getMidTime(time_t lower, time_t upper)
 {
-       struct tm t;
-       const char *str = (const char *)time->data;
-       size_t i = 0;
-
-       memset(&t, 0, sizeof(t));
-
-       if (time->type == V_ASN1_UTCTIME) {
-               /* two digit year */
-               t.tm_year = (str[i] - '0') * 10 + (str[i + 1] - '0');
-               i += 2;
-               if (t.tm_year < 70)
-                       t.tm_year += 100;
-       } else if (time->type == V_ASN1_GENERALIZEDTIME) {
-               /* four digit year */
-               t.tm_year =
-                       (str[i] - '0') * 1000
-                       + (str[i + 1] - '0') * 100
-                       + (str[i + 2] - '0') * 10
-                       + (str[i + 3] - '0');
-               i += 4;
-               t.tm_year -= 1900;
-       }
-
-       t.tm_mon  = (str[i]     - '0') * 10 + (str[i + 1] - '0') - 1; // -1 since January is 0 not 1.
-       t.tm_mday = (str[i + 2] - '0') * 10 + (str[i + 3] - '0');
-       t.tm_hour = (str[i + 4] - '0') * 10 + (str[i + 5] - '0');
-       t.tm_min  = (str[i + 6] - '0') * 10 + (str[i + 7] - '0');
-       t.tm_sec  = (str[i + 8] - '0') * 10 + (str[i + 9] - '0');
-
-       /* Note: we did not adjust the time based on time zone information */
-       return t;
+       return (lower >> 1) + (upper >> 1);
 }
 
-struct tm getMidTime(const struct tm &tb, const struct tm &ta)
+inline CertTimeStatus _timeValidation(time_t lower, time_t upper, time_t current)
 {
-       struct tm tMid;
-       memset(&tMid, 0, sizeof(tMid));
-
-       LogDebug("Certificate's notBeforeTime : Year["
-               << (tb.tm_year + 1900)
-               << "] Month[" << (tb.tm_mon + 1)
-               << "] Day[" << tb.tm_mday << "]  ");
-
-       LogDebug("Certificate's notAfterTime : Year["
-               << (ta.tm_year + 1900)
-               << "] Month[" << (ta.tm_mon + 1)
-               << "] Day[" << ta.tm_mday << "]  ");
-
-       int year = (ta.tm_year - tb.tm_year) / 4;
-
-       if (year == 0) {
-               tMid.tm_year = tb.tm_year;
-               tMid.tm_mon = tb.tm_mon + 1;
-               tMid.tm_mday = tb.tm_mday;
-
-               if (tMid.tm_mon == 12) {
-                       tMid.tm_year = ta.tm_year;
-                       tMid.tm_mon = ta.tm_mon - 1;
-                       tMid.tm_mday = ta.tm_mday;
-
-                       if (tMid.tm_mon < 0) {
-                               tMid.tm_year = ta.tm_year;
-                               tMid.tm_mon = ta.tm_mon;
-                               tMid.tm_mday = ta.tm_mday - 1;
-
-                               if (tMid.tm_mday == 0) {
-                                       tMid.tm_year = tb.tm_year;
-                                       tMid.tm_mon = tb.tm_mon;
-                                       tMid.tm_mday = tb.tm_mday + 1;
-                               }
-                       }
-               }
-       } else {
-               tMid.tm_year = tb.tm_year + year;
-               tMid.tm_mon = (tb.tm_mon + ta.tm_mon) / 2;
-               tMid.tm_mday = (tb.tm_mday + ta.tm_mday) / 2;
-       }
-
-       LogDebug("cmp cert with validation time. Year["
-               << (tMid.tm_year + 1900)
-               << "] Month[" << (tMid.tm_mon + 1)
-               << "] Day[" << tMid.tm_mday << "]  ");
-
-       return tMid;
-}
-
-inline CertTimeStatus timeValidation(ASN1_TIME *min, ASN1_TIME *max, time_t *cur)
-{
-       if (X509_cmp_time(min, cur) > 0)
+       if (current < lower)
                return CertTimeStatus::NOT_YET;
-       else if (X509_cmp_time(max, cur) < 0)
+       else if (current > upper)
                return CertTimeStatus::EXPIRED;
        else
                return CertTimeStatus::VALID;
 }
 
-inline bool isTimeStrict(const Set &stores)
+inline bool _isTimeStrict(const Set &stores)
 {
        return (stores.contains(TIZEN_TEST) || stores.contains(TIZEN_VERIFY))
                ? true : false;
@@ -383,22 +300,23 @@ VCerr SignatureValidator::Impl::preStep(void)
        m_context.certificatePtr = m_data.getCertList().back();
 
        /* certificate time check */
-       ASN1_TIME *notAfterTime = m_data.getEndEntityCertificatePtr()->getNotAfterTime();
-       ASN1_TIME *notBeforeTime = m_data.getEndEntityCertificatePtr()->getNotBeforeTime();
-
-       time_t nowTime = time(NULL);
+       time_t lower = m_data.getEndEntityCertificatePtr()->getNotBefore();
+       time_t upper = m_data.getEndEntityCertificatePtr()->getNotAfter();
+       time_t current = time(NULL);
+       CertTimeStatus status = _timeValidation(lower, upper, current);
 
-       CertTimeStatus status = timeValidation(notBeforeTime, notAfterTime, &nowTime);
        if (status != CertTimeStatus::VALID) {
-               if (isTimeStrict(storeIdSet))
+               if (_isTimeStrict(storeIdSet))
                        return status == CertTimeStatus::EXPIRED
                                        ? E_SIG_CERT_EXPIRED : E_SIG_CERT_NOT_YET;
 
-               struct tm tMid = getMidTime(
-                               _ASN1_GetTimeT(notBeforeTime),
-                               _ASN1_GetTimeT(notAfterTime));
-
-               m_context.validationTime = mktime(&tMid);
+               time_t mid = _getMidTime(lower, upper);
+               LogInfo("Use middle notBeforeTime and notAfterTime."
+                               " lower: " << lower
+                               << " upper: " << upper
+                               << " mid: " << mid
+                               << " current: " << current);
+               m_context.validationTime = mid;
        }
 
        return E_SIG_NONE;
index 98c80f3..a796ce7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
  */
 #include <vcore/TimeConversion.h>
 
-#include <string.h>
+#include <cstring>
 
-#include <dpl/log/log.h>
-#include <dpl/assert.h>
+namespace {
 
-namespace ValidationCore {
+void _gmtime_adj(struct tm *tm, int offset)
+{
+    time_t t = mktime(tm);
+    t += offset;
 
-int asn1TimeToTimeT(ASN1_TIME *t, time_t *res)
+    memset(tm, 0, sizeof(struct tm));
+
+    gmtime_r(&t, tm);
+}
+
+/*
+ * from openssl/crypto/asn1/a_gentm.c, openssl version 1.0.2d
+ * return 1 on success, 0 on error
+ * 1. local time only                        : yyyymmddHHMMSS[.fff]
+ * 2. UTC time only                          : yyyymmddHHMM[SS[.fff]]Z
+ * 3. Difference between local and UTC times : yyyymmddHHMM[SS[.fff]](+|-)HHMM
+ */
+int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d)
 {
-    struct tm tm;
-    int offset;
+    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 };
+    char *a;
+    int n, i, l, o;
+
+    if (d->type != V_ASN1_GENERALIZEDTIME)
+        return (0);
+    l = d->length;
+    a = (char *)d->data;
+    o = 0;
+    /*
+     * 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 < 13)
+        goto err;
+    for (i = 0; i < 7; i++) {
+        if ((i == 6) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
+            i++;
+            if (tm)
+                tm->tm_sec = 0;
+            break;
+        }
+        if ((a[o] < '0') || (a[o] > '9'))
+            goto err;
+        n = a[o] - '0';
+        if (++o > l)
+            goto err;
+
+        if ((a[o] < '0') || (a[o] > '9'))
+            goto err;
+        n = (n * 10) + a[o] - '0';
+        if (++o > l)
+            goto err;
 
-    (*res) = 0;
-    if (!ASN1_TIME_check(t)) {
-        return -1;
+        if ((n < min[i]) || (n > max[i]))
+            goto err;
+        if (tm) {
+            switch (i) {
+            case 0:
+                tm->tm_year = n * 100 - 1900;
+                break;
+            case 1:
+                tm->tm_year += n;
+                break;
+            case 2:
+                tm->tm_mon = n - 1;
+                break;
+            case 3:
+                tm->tm_mday = n;
+                break;
+            case 4:
+                tm->tm_hour = n;
+                break;
+            case 5:
+                tm->tm_min = n;
+                break;
+            case 6:
+                tm->tm_sec = n;
+                break;
+            }
+        }
+    }
+    /*
+     * Optional fractional seconds: decimal point followed by one or more
+     * digits.
+     */
+    if (a[o] == '.') {
+        if (++o > l)
+            goto err;
+        i = o;
+        while ((a[o] >= '0') && (a[o] <= '9') && (o <= l))
+            o++;
+        /* Must have at least one digit after decimal point */
+        if (i == o)
+            goto err;
     }
 
-    memset(&tm, 0, sizeof(tm));
+    if (a[o] == 'Z')
+        o++;
+    else if ((a[o] == '+') || (a[o] == '-')) {
+        int offsign = a[o] == '-' ? -1 : 1, offset = 0;
+        o++;
+        if (o + 4 > l)
+            goto err;
+        for (i = 7; i < 9; i++) {
+            if ((a[o] < '0') || (a[o] > '9'))
+                goto err;
+            n = a[o] - '0';
+            o++;
+            if ((a[o] < '0') || (a[o] > '9'))
+                goto err;
+            n = (n * 10) + a[o] - '0';
+            if ((n < min[i]) || (n > max[i]))
+                goto err;
+            if (tm) {
+                if (i == 7)
+                    offset = n * 3600;
+                else if (i == 8)
+                    offset += n * 60;
+            }
+            o++;
+        }
+        if (offset)
+            _gmtime_adj(tm, offset * offsign);
+    } else if (a[o]) {
+        /* Missing time zone information. */
+        goto err;
+    }
+    return (o == l);
+ err:
+    return (0);
+}
+
+/*
+ * from openssl/crypto/asn1/a_utctm.c, openssl version 1.0.2d
+ * return 1 on success, 0 on error
+ * 1. yymmddHHMM[SS]Z
+ * 2. yymmddHHMM[SS](+|-)HHMM
+ */
+int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
+{
+    static const int min[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };
+    static const int max[8] = { 99, 12, 31, 23, 59, 59, 12, 59 };
+    char *a;
+    int n, i, l, o;
 
-#define g2(p) (((p)[0] - '0') * 10 + (p)[1] - '0')
-    if (t->type == V_ASN1_UTCTIME) {
-        Assert(t->length > 12);
+    if (d->type != V_ASN1_UTCTIME)
+        return (0);
+    l = d->length;
+    a = (char *)d->data;
+    o = 0;
 
-        /*   this code is copied from OpenSSL asn1/a_utctm.c file */
-        tm.tm_year = g2(t->data);
-        if (tm.tm_year < 50) {
-            tm.tm_year += 100;
+    if (l < 11)
+        goto err;
+    for (i = 0; i < 6; i++) {
+        if ((i == 5) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
+            i++;
+            if (tm)
+                tm->tm_sec = 0;
+            break;
         }
-        tm.tm_mon = g2(t->data + 2) - 1;
-        tm.tm_mday = g2(t->data + 4);
-        tm.tm_hour = g2(t->data + 6);
-        tm.tm_min = g2(t->data + 8);
-        tm.tm_sec = g2(t->data + 10);
-        if (t->data[12] == 'Z') {
-            offset = 0;
-        } else {
-            Assert(t->length > 16);
-
-            offset = g2(t->data + 13) * 60 + g2(t->data + 15);
-            if (t->data[12] == '-') {
-                offset = -offset;
+        if ((a[o] < '0') || (a[o] > '9'))
+            goto err;
+        n = a[o] - '0';
+        if (++o > l)
+            goto err;
+
+        if ((a[o] < '0') || (a[o] > '9'))
+            goto err;
+        n = (n * 10) + a[o] - '0';
+        if (++o > l)
+            goto err;
+
+        if ((n < min[i]) || (n > max[i]))
+            goto err;
+        if (tm) {
+            switch (i) {
+            case 0:
+                tm->tm_year = n < 50 ? n + 100 : n;
+                break;
+            case 1:
+                tm->tm_mon = n - 1;
+                break;
+            case 2:
+                tm->tm_mday = n;
+                break;
+            case 3:
+                tm->tm_hour = n;
+                break;
+            case 4:
+                tm->tm_min = n;
+                break;
+            case 5:
+                tm->tm_sec = n;
+                break;
             }
         }
-        tm.tm_isdst = -1;
-    } else {
-        Assert(t->length > 14);
-
-        tm.tm_year = g2(t->data) * 100 + g2(t->data + 2);
-        tm.tm_mon = g2(t->data + 4) - 1;
-        tm.tm_mday = g2(t->data + 6);
-        tm.tm_hour = g2(t->data + 8);
-        tm.tm_min = g2(t->data + 10);
-        tm.tm_sec = g2(t->data + 12);
-        if (t->data[14] == 'Z') {
-            offset = 0;
-        } else {
-            Assert(t->length > 18);
-
-            offset = g2(t->data + 15) * 60 + g2(t->data + 17);
-            if (t->data[14] == '-') {
-                offset = -offset;
+    }
+    if (a[o] == 'Z')
+        o++;
+    else if ((a[o] == '+') || (a[o] == '-')) {
+        int offsign = a[o] == '-' ? -1 : 1, offset = 0;
+        o++;
+        if (o + 4 > l)
+            goto err;
+        for (i = 6; i < 8; i++) {
+            if ((a[o] < '0') || (a[o] > '9'))
+                goto err;
+            n = a[o] - '0';
+            o++;
+            if ((a[o] < '0') || (a[o] > '9'))
+                goto err;
+            n = (n * 10) + a[o] - '0';
+            if ((n < min[i]) || (n > max[i]))
+                goto err;
+            if (tm) {
+                if (i == 6)
+                    offset = n * 3600;
+                else if (i == 7)
+                    offset += n * 60;
             }
+            o++;
         }
-        tm.tm_isdst = -1;
+        if (offset)
+            _gmtime_adj(tm, offset * offsign);
     }
-#undef g2
-    (*res) = timegm(&tm) - offset * 60;
+    return o == l;
+ err:
     return 0;
 }
 
-int asn1GeneralizedTimeToTimeT(ASN1_GENERALIZEDTIME *tm, time_t *res)
-{
-    /*
-     * This code is based on following assumption:
-     * from openssl/a_gentm.c:
-     * 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
-     */
-    const int DATE_BUFFER_LENGTH = 15; // YYYYMMDDHHMMSSZ
+} // namespace anonymous
 
-    if (NULL == res || NULL == tm) {
-        LogError("NULL pointer");
-        return -1;
-    }
+namespace ValidationCore {
 
-    if (DATE_BUFFER_LENGTH != tm->length || NULL == tm->data) {
-        LogError("Invalid ASN1_GENERALIZEDTIME");
-        return -1;
-    }
+int asn1TimeToTimeT(ASN1_TIME *t, time_t *res)
+{
+    if (res == NULL)
+        return 0;
 
-    struct tm time_s;
-    if (sscanf ((char*)tm->data,
-                "%4d%2d%2d%2d%2d%2d",
-                &time_s.tm_year,
-                &time_s.tm_mon,
-                &time_s.tm_mday,
-                &time_s.tm_hour,
-                &time_s.tm_min,
-                &time_s.tm_sec) < 6)
-    {
-        LogError("Could not extract time data from ASN1_GENERALIZEDTIME");
-        return -1;
-    }
+    int ret = 0;
+    struct tm tm;
 
-    time_s.tm_year -= 1900;
-    time_s.tm_mon -= 1;
-    time_s.tm_isdst = 0;   // UTC
-    time_s.tm_gmtoff = 0;  // UTC
-    time_s.tm_zone = NULL; // UTC
+    memset(&tm, 0, sizeof(tm));
 
-    *res = mktime(&time_s);
+    if (t->type == V_ASN1_UTCTIME)
+        ret = asn1_utctime_to_tm(&tm, t);
+    else if (t->type == V_ASN1_GENERALIZEDTIME)
+        ret = asn1_generalizedtime_to_tm(&tm, t);
+    else
+        ret = 0;
 
-    return 0;
+    if (ret == 0)
+        return 0;
+
+    *res = mktime(&tm);
+    return 1;
 }
 
 } // namespace ValidationCore
index c3df017..3cf2acd 100644 (file)
 #include <openssl/asn1.h>
 
 namespace ValidationCore {
-// from OpenSSL asn1/a_utctm.c code
+
+/*
+ * openssl/crypto/asn1/a_time.c based version 1.0.2d
+ * return 1 on success, 0 on error
+ */
 int asn1TimeToTimeT(ASN1_TIME *t, time_t *res);
 
-int asn1GeneralizedTimeToTimeT(ASN1_GENERALIZEDTIME *tm,
-                               time_t *res);
 } // namespace ValidationCore
 
 #endif // _VALIDATION_CORE_TIMECONVERSION_H_
-