You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2014/06/27 23:36:59 UTC

svn commit: r1606252 - in /subversion/branches/svn-auth-x509/subversion: libsvn_subr/x509.h libsvn_subr/x509parse.c tests/libsvn_subr/x509-test.c

Author: breser
Date: Fri Jun 27 21:36:58 2014
New Revision: 1606252

URL: http://svn.apache.org/r1606252
Log:
On svn-auth-x509 branch, Support GeneralizedTime format for validity dates.

* subversion/tests/libsvn_subr/x509-test.c
  (cert_tests): Add a cert with a GeneralizedTime format date.

* subversion/libsvn_subr/x509.h
  (ASN1_GENERALIZED_TIME): New macro.
  (x509_utc_to_apr_time): Remove function.
  (x509_get_date): New function, that supports retrieving one date
    in UTCTime or GeneralizedTime and converts it to an apr_time_t.  While
    doing this get rid of the static buffer and memset/memcpy.  Use the
    more specific apr_time_exp_gmt_get() in preference to the ambigously
    named apr_time_exp_get().
  (x509_get_dates): Use x509_get_date(), reorder arguments to our norm of
    output arguments coming first, take a scratch_pool argument.
  (svn_x509_parse_cert): Update x509_get_dates() calls to the new signature.

Modified:
    subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509.h
    subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c
    subversion/branches/svn-auth-x509/subversion/tests/libsvn_subr/x509-test.c

Modified: subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509.h?rev=1606252&r1=1606251&r2=1606252&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509.h (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509.h Fri Jun 27 21:36:58 2014
@@ -58,6 +58,7 @@
 #define ASN1_T61_STRING              0x14
 #define ASN1_IA5_STRING              0x16
 #define ASN1_UTC_TIME                0x17
+#define ASN1_GENERALIZED_TIME        0x18
 #define ASN1_UNIVERSAL_STRING        0x1C
 #define ASN1_BMP_STRING              0x1E
 #define ASN1_PRIMITIVE               0x00

Modified: subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c?rev=1606252&r1=1606251&r2=1606252&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c Fri Jun 27 21:36:58 2014
@@ -343,19 +343,68 @@ x509_get_name(const unsigned char **p, c
   return svn_error_trace(x509_get_name(p, end2, cur->next, result_pool));
 }
 
-/* Convert from X.509 UTCTime to apr_time_t.
- * X.509 UTCTime is defined in RFC 5280 § 4.1.2.5.1 */
+/* Retrieve the date from the X.509 cert data between *P and END in either
+ * UTCTime or GeneralizedTime format (as defined in RFC 5280 § 4.1.2.5.1 and
+ * 4.1.2.5.2 respectively) and place the result in WHEN using  SCRATCH_POOL
+ * for temporary allocations. */
 static svn_error_t *
-x509_utc_to_apr_time(apr_time_t *time, const char *date)
+x509_get_date(apr_time_t *when,
+              const unsigned char **p,
+              const unsigned char *end,
+              apr_pool_t *scratch_pool)
 {
-  apr_time_exp_t xt = { 0 };
+  svn_error_t *err;
   apr_status_t ret;
+  int len, tag;
+  char *date;
+  apr_time_exp_t xt = { 0 };
   char tz;
 
-  if (sscanf(date, "%2d%2d%2d%2d%2d%2d%c",
-       &xt.tm_year, &xt.tm_mon, &xt.tm_mday,
-       &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
+  tag = **p;
+  err = asn1_get_tag(p, end, &len, ASN1_UTC_TIME);
+  if (err && err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
+    {
+      svn_error_clear(err);
+      tag = **p;
+      err = asn1_get_tag(p, end, &len, ASN1_GENERALIZED_TIME);
+    }
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
+
+  date = apr_pstrndup(scratch_pool, (const char *) *p, len);
+  switch (tag)
+    {
+      case ASN1_UTC_TIME:
+        if (sscanf(date, "%2d%2d%2d%2d%2d%2d%c",
+                   &xt.tm_year, &xt.tm_mon, &xt.tm_mday,
+                   &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6)
+          return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
+
+        /* UTCTime only provides a 2 digit year.  X.509 specifies that years
+         * greater than or equal to 50 must be interpreted as 19YY and years
+         * less than 50 be interpreted as 20YY.  This format is not used for
+         * years greater than 2049. apr_time_exp_t wants years as the number
+         * of years since 1900, so don't convert to 4 digits here. */
+        xt.tm_year += 100 * (xt.tm_year < 50);
+        break;
+
+      case ASN1_GENERALIZED_TIME:
+        if (sscanf(date, "%4d%2d%2d%2d%2d%2d%c",
+                   &xt.tm_year, &xt.tm_mon, &xt.tm_mday,
+                   &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6)
+          return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
+
+        /* GeneralizedTime has the full 4 digit year.  But apr_time_exp_t
+         * wants years as the number of years since 1900. */
+        xt.tm_year -= 1900;
+        break;
+
+      default:
+        /* shouldn't ever get here because we should error out above in the
+         * asn1_get_tag() bits but doesn't hurt to be extra paranoid. */
+        return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
+        break;
+    }
 
   /* check that the timezone is GMT
    * ASN.1 allows for the timezone to be specified but X.509 says it must
@@ -364,20 +413,15 @@ x509_utc_to_apr_time(apr_time_t *time, c
   if (tz != 'Z')
     return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
 
-  /* UTCTime only provides a 2 digit year.  X.509 specifies that years
-   * greater than or equal to 50 must be interpreted as 19YY and years less
-   * than 50 be interpreted as 20YY.  This format is not used for years
-   * greater than 2049. apr_time_exp_t wants years as the number of years
-   * since 1900, so don't convert to 4 digits here. */
-  xt.tm_year += 100 * (xt.tm_year < 50);
-
   /* apr_time_exp_t expects months to be zero indexed, 0=Jan, 11=Dec. */
   xt.tm_mon -= 1;
 
-  ret = apr_time_exp_get(time, &xt);
+  ret = apr_time_exp_gmt_get(when, &xt);
   if (ret)
     return svn_error_wrap_apr(ret, NULL);
 
+  *p += len;
+
   return SVN_NO_ERROR;
 }
 
@@ -391,12 +435,14 @@ x509_utc_to_apr_time(apr_time_t *time, c
  *     generalTime  GeneralizedTime }
  */
 static svn_error_t *
-x509_get_dates(const unsigned char **p,
-               const unsigned char *end, apr_time_t * from, apr_time_t * to)
+x509_get_dates(apr_time_t *from,
+               apr_time_t *to,
+               const unsigned char **p,
+               const unsigned char *end,
+               apr_pool_t *scratch_pool)
 {
   svn_error_t *err;
   int len;
-  char date[64];
 
   err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
   if (err)
@@ -404,28 +450,9 @@ x509_get_dates(const unsigned char **p,
 
   end = *p + len;
 
-  /*
-   * TODO: also handle GeneralizedTime
-   */
-  err = asn1_get_tag(p, end, &len, ASN1_UTC_TIME);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
-
-  memset(date, 0, sizeof(date));
-  memcpy(date, *p, (len < (int)sizeof(date) - 1) ?
-         len : (int)sizeof(date) - 1);
-  SVN_ERR(x509_utc_to_apr_time(from, date));
-  *p += len;
-
-  err = asn1_get_tag(p, end, &len, ASN1_UTC_TIME);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
+  SVN_ERR(x509_get_date(from, p, end, scratch_pool));
 
-  memset(date, 0, sizeof(date));
-  memcpy(date, *p, (len < (int)sizeof(date) - 1) ?
-         len : (int)sizeof(date) - 1);
-  SVN_ERR(x509_utc_to_apr_time(to, date));
-  *p += len;
+  SVN_ERR(x509_get_date(to, p, end, scratch_pool));
 
   if (*p != end)
     {
@@ -684,7 +711,8 @@ svn_x509_parse_cert(apr_hash_t **certinf
    *              notAfter           Time }
    *
    */
-  SVN_ERR(x509_get_dates(&p, end, &crt->valid_from, &crt->valid_to));
+  SVN_ERR(x509_get_dates(&crt->valid_from, &crt->valid_to, &p, end,
+                         scratch_pool));
 
   /*
    * subject                              Name

Modified: subversion/branches/svn-auth-x509/subversion/tests/libsvn_subr/x509-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/tests/libsvn_subr/x509-test.c?rev=1606252&r1=1606251&r2=1606252&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/tests/libsvn_subr/x509-test.c (original)
+++ subversion/branches/svn-auth-x509/subversion/tests/libsvn_subr/x509-test.c Fri Jun 27 21:36:58 2014
@@ -76,6 +76,34 @@ static struct x509_test cert_tests[] = {
     "C=US, O=Thawte, Inc., CN=Thawte SSL CA",
     "2014-04-11T00:00:00.000000Z",
     "2016-04-07T23:59:59.000000Z" },
+  /* the expiration is after 2049 so the expiration is in the
+   * generalized format, while the start date is still in the UTC
+   * format. Note this is actually a CA cert but that really doesn't
+   * matter here. */
+  { "timestamp-after-2049",
+    "MIIDtzCCAp+gAwIBAgIJAJKX85dqh3RvMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV"
+    "BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX"
+    "aWRnaXRzIFB0eSBMdGQwIBcNMTQwNjI3MTczMTUxWhgPMjExNDA2MDMxNzMxNTFa"
+    "MEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJ"
+    "bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw"
+    "ggEKAoIBAQDaa4gwNBB6vgWrlOIEMdzvD06zmmiocEt6UnTHtmAcfrBuDnKrBwEh"
+    "f5JxneL16XIuKwK6n/4omBtem/PPjjpOLM9PMQuoO0cpQ0UGFnfpmko6PSQoqRHl"
+    "qTbDGv4usn7qdZV+FKz/B9CMonRSzWHMz5YPmqfob6BqaaJY/qJEzHJA24bm4jPH"
+    "IsaVCInEGpqAUpejwBzNujfbLibBNrVX7K846zk+tnsNR90kP5h3IRP3SdWVywKC"
+    "AMN2izzhmaDhuPzaTBobovr+ySJShmX6gdB5PpWkm6rcBl6RJ+tM0ZBSJjQvkYp4"
+    "seV+rcXFgpJP/aQL3vhDON32tjWh3A2JAgMBAAGjgacwgaQwHQYDVR0OBBYEFF+N"
+    "7TyDI8THpAbx1pfzFFtl5z4iMHUGA1UdIwRuMGyAFF+N7TyDI8THpAbx1pfzFFtl"
+    "5z4ioUmkRzBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8G"
+    "A1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkggkAkpfzl2qHdG8wDAYDVR0T"
+    "BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAo4t9fYe2I+XIQn8i/KI9UFEE9fue"
+    "w6rQMnf9yyd8nwL+IcV84hvyNrq0+7SptUBMq3rsEf5UIBIBI4Oa614mJ/Kt976O"
+    "S7Sa1IPH7j+zb/jqH/xGskEVi25dZz7psFCmi7Hm9dnVz9YKa2yLW6R2KZcTVxCx"
+    "SSdDRlD7SonsYeq2fGrAo7Y9xfZsiJ2ZbJ18kHs2coMWuhgSrN9jrML6mb5B+k22"
+    "/rgsCJgFsBDPBYR3ju0Ahqg7v6kwg9O2PJzyb4ljsw8oI0sCwHTZW5I5FMq2D9g6"
+    "hj80N2fhS9QWoLyeKoMTNB2Do6VaNrLrCJiscZWrsnM1f+XBqV8hMuHX8A==",
+    "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd",
+    "2014-06-27T17:31:51.000000Z",
+    "2114-06-03T17:31:51.000000Z" },
   { NULL }
 };