subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From i...@apache.org
Subject svn commit: r1617225 [2/3] - in /subversion/branches/svn-auth-x509: subversion/include/ subversion/libsvn_fs_base/ subversion/libsvn_fs_base/bdb/ subversion/libsvn_fs_fs/ subversion/libsvn_fs_x/ subversion/libsvn_subr/ subversion/libsvn_wc/ subversion/...
Date Mon, 11 Aug 2014 08:54:39 GMT
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=1617225&r1=1617224&r2=1617225&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c Mon Aug 11 08:54:38 2014
@@ -1,1196 +1,1196 @@
-/*
- *  X.509 certificate and private key decoding
- *
- *  Based on XySSL: Copyright (C) 2006-2008   Christophe Devine
- *
- *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
- *
- *  All rights reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions
- *  are met:
- *
- *    * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *    * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/*
- *  The ITU-T X.509 standard defines a certificate format for PKI.
- *
- *  http://www.ietf.org/rfc/rfc5280.txt
- *  http://www.ietf.org/rfc/rfc3279.txt
- *  http://www.ietf.org/rfc/rfc6818.txt
- *
- *  ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
- *
- *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
- *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
- */
-
-#include <apr_pools.h>
-#include <apr_tables.h>
-#include "svn_hash.h"
-#include "svn_string.h"
-#include "svn_time.h"
-#include "svn_checksum.h"
-#include "svn_utf.h"
-#include "svn_ctype.h"
-#include "svn_x509.h"
-#include "private/svn_utf_private.h"
-#include "private/svn_string_private.h"
-
-#include "x509.h"
-
-#include <string.h>
-#include <stdio.h>
-
-/*
- * ASN.1 DER decoding routines
- */
-static svn_error_t *
-asn1_get_len(const unsigned char **p, const unsigned char *end,
-             ptrdiff_t *len)
-{
-  if ((end - *p) < 1)
-    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
-
-  if ((**p & 0x80) == 0)
-    *len = *(*p)++;
-  else
-    switch (**p & 0x7F)
-      {
-      case 1:
-        if ((end - *p) < 2)
-          return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
-
-        *len = (*p)[1];
-        (*p) += 2;
-        break;
-
-      case 2:
-        if ((end - *p) < 3)
-          return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
-
-        *len = ((*p)[1] << 8) | (*p)[2];
-        (*p) += 3;
-        break;
-
-      default:
-        return svn_error_create(SVN_ERR_ASN1_INVALID_LENGTH, NULL, NULL);
-        break;
-      }
-
-  if (*len > (end - *p))
-    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-asn1_get_tag(const unsigned char **p,
-             const unsigned char *end, ptrdiff_t *len, int tag)
-{
-  if ((end - *p) < 1)
-    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
-
-  if (**p != tag)
-    return svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
-
-  (*p)++;
-
-  return svn_error_trace(asn1_get_len(p, end, len));
-}
-
-static svn_error_t *
-asn1_get_int(const unsigned char **p, const unsigned char *end, int *val)
-{
-  ptrdiff_t len;
-
-  SVN_ERR(asn1_get_tag(p, end, &len, ASN1_INTEGER));
-
-  if (len > (int)sizeof(int) || (**p & 0x80) != 0)
-    return svn_error_create(SVN_ERR_ASN1_INVALID_LENGTH, NULL, NULL);
-
-  *val = 0;
-
-  while (len-- > 0) {
-    *val = (*val << 8) | **p;
-    (*p)++;
-  }
-
-  return SVN_NO_ERROR;
-}
-
-/*
- *  Version   ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
- */
-static svn_error_t *
-x509_get_version(const unsigned char **p, const unsigned char *end, int *ver)
-{
-  svn_error_t *err;
-  ptrdiff_t len;
-
-  err = asn1_get_tag(p, end, &len,
-                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0);
-  if (err)
-    {
-      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
-        {
-          svn_error_clear(err);
-          *ver = 0;
-          return SVN_NO_ERROR;
-        }
-
-      return svn_error_trace(err);
-    }
-
-  end = *p + len;
-
-  err = asn1_get_int(p, end, ver);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_VERSION, err, NULL);
-
-  if (*p != end)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_VERSION, err, NULL);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/*
- *  CertificateSerialNumber   ::=  INTEGER
- */
-static svn_error_t *
-x509_get_serial(const unsigned char **p,
-                const unsigned char *end, x509_buf * serial)
-{
-  svn_error_t *err;
-
-  if ((end - *p) < 1)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
-    }
-
-  if (**p != (ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2) &&
-      **p != ASN1_INTEGER)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
-    }
-
-  serial->tag = *(*p)++;
-
-  err = asn1_get_len(p, end, &serial->len);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
-
-  serial->p = *p;
-  *p += serial->len;
-
-  return SVN_NO_ERROR;
-}
-
-/*
- *  AlgorithmIdentifier   ::=  SEQUENCE  {
- *     algorithm         OBJECT IDENTIFIER,
- *     parameters        ANY DEFINED BY algorithm OPTIONAL  }
- */
-static svn_error_t *
-x509_get_alg(const unsigned char **p, const unsigned char *end, x509_buf * alg)
-{
-  svn_error_t *err;
-  ptrdiff_t len;
-
-  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
-
-  end = *p + len;
-  alg->tag = **p;
-
-  err = asn1_get_tag(p, end, &alg->len, ASN1_OID);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
-
-  alg->p = *p;
-  *p += alg->len;
-
-  if (*p == end)
-    return SVN_NO_ERROR;
-
-  /*
-   * assume the algorithm parameters must be NULL
-   */
-  err = asn1_get_tag(p, end, &len, ASN1_NULL);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
-
-  if (*p != end)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/*
- *  RelativeDistinguishedName ::=
- *    SET OF AttributeTypeAndValue
- *
- *  AttributeTypeAndValue ::= SEQUENCE {
- *    type     AttributeType,
- *    value     AttributeValue }
- *
- *  AttributeType ::= OBJECT IDENTIFIER
- *
- *  AttributeValue ::= ANY DEFINED BY AttributeType
- */
-static svn_error_t *
-x509_get_name(const unsigned char **p, const unsigned char *end,
-              x509_name * cur, apr_pool_t *result_pool)
-{
-  svn_error_t *err;
-  ptrdiff_t len;
-  const unsigned char *end2;
-  x509_buf *oid;
-  x509_buf *val;
-
-  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SET);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
-
-  end2 = end;
-  end = *p + len;
-
-  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
-
-  if (*p + len != end)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
-    }
-
-  oid = &cur->oid;
-  oid->tag = **p;
-
-  err = asn1_get_tag(p, end, &oid->len, ASN1_OID);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
-
-  oid->p = *p;
-  *p += oid->len;
-
-  if ((end - *p) < 1)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
-    }
-
-  if (**p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING &&
-      **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING &&
-      **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
-    }
-
-  val = &cur->val;
-  val->tag = *(*p)++;
-
-  err = asn1_get_len(p, end, &val->len);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
-
-  val->p = *p;
-  *p += val->len;
-
-  cur->next = NULL;
-
-  if (*p != end)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
-    }
-
-  /*
-   * recurse until end of SEQUENCE is reached
-   */
-  if (*p == end2)
-    return SVN_NO_ERROR;
-
-  cur->next = (x509_name *) apr_palloc(result_pool, sizeof(x509_name));
-
-  if (cur->next == NULL)
-    return SVN_NO_ERROR;
-
-  return svn_error_trace(x509_get_name(p, end2, cur->next, result_pool));
-}
-
-/* Retrieve the date from the X.509 cert data between *P and END in either
- * UTCTime or GeneralizedTime format (as defined in RFC 5280 s. 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_get_date(apr_time_t *when,
-              const unsigned char **p,
-              const unsigned char *end,
-              apr_pool_t *scratch_pool)
-{
-  svn_error_t *err;
-  apr_status_t ret;
-  int tag;
-  ptrdiff_t len;
-  char *date;
-  apr_time_exp_t xt = { 0 };
-  char tz;
-
-  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
-   * always be GMT.  A little bit of extra paranoia here seems like a good
-   * idea. */
-  if (tz != 'Z')
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
-
-  /* apr_time_exp_t expects months to be zero indexed, 0=Jan, 11=Dec. */
-  xt.tm_mon -= 1;
-
-  ret = apr_time_exp_gmt_get(when, &xt);
-  if (ret)
-    return svn_error_wrap_apr(ret, NULL);
-
-  *p += len;
-
-  return SVN_NO_ERROR;
-}
-
-/*
- *  Validity ::= SEQUENCE {
- *     notBefore    Time,
- *     notAfter    Time }
- *
- *  Time ::= CHOICE {
- *     utcTime    UTCTime,
- *     generalTime  GeneralizedTime }
- */
-static svn_error_t *
-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;
-  ptrdiff_t len;
-
-  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
-
-  end = *p + len;
-
-  SVN_ERR(x509_get_date(from, p, end, scratch_pool));
-
-  SVN_ERR(x509_get_date(to, p, end, scratch_pool));
-
-  if (*p != end)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-x509_get_sig(const unsigned char **p, const unsigned char *end, x509_buf * sig)
-{
-  svn_error_t *err;
-  ptrdiff_t len;
-
-  sig->tag = **p;
-
-  err = asn1_get_tag(p, end, &len, ASN1_BIT_STRING);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, err, NULL);
-
-  if (--len < 1 || *(*p)++ != 0)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, NULL, NULL);
-
-  sig->len = len;
-  sig->p = *p;
-
-  *p += len;
-
-  return SVN_NO_ERROR;
-}
-
-/*
- * X.509 v2/v3 unique identifier (not parsed)
- */
-static svn_error_t *
-x509_get_uid(const unsigned char **p,
-             const unsigned char *end, x509_buf * uid, int n)
-{
-  svn_error_t *err;
-
-  if (*p == end)
-    return SVN_NO_ERROR;
-
-  uid->tag = **p;
-
-  err = asn1_get_tag(p, end, &uid->len,
-                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n);
-  if (err)
-    {
-      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
-        {
-          svn_error_clear(err);
-          return SVN_NO_ERROR;
-        }
-
-      return svn_error_trace(err);
-    }
-
-  uid->p = *p;
-  *p += uid->len;
-
-  return SVN_NO_ERROR;
-}
-
-/*
- * X.509 v3 extensions (not parsed)
- */
-static svn_error_t *
-x509_get_ext(apr_array_header_t *dnsnames,
-             const unsigned char **p,
-             const unsigned char *end)
-{
-  svn_error_t *err;
-  ptrdiff_t len;
-
-  if (*p == end)
-    return SVN_NO_ERROR;
-
-  err = asn1_get_tag(p, end, &len,
-                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3);
-  if (err)
-    {
-      /* If there aren't extensions that's ok they aren't required */
-      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
-        {
-          svn_error_clear(err);
-          return SVN_NO_ERROR;
-        }
-
-      return svn_error_trace(err);
-    }
-
-  end = *p + len;
-
-  SVN_ERR(asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE));
-
-  if (end != *p + len)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL);
-    }
-
-  while (*p < end)
-    {
-      ptrdiff_t ext_len;
-      const unsigned char *ext_start, *sna_end;
-      err = asn1_get_tag(p, end, &ext_len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
-      if (err)
-        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
-                                NULL);
-      ext_start = *p;
-
-      err = asn1_get_tag(p, end, &len, ASN1_OID);
-      if (err)
-        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
-                                NULL);
-
-      /* skip all extensions except SubjectAltName */
-      if (len != sizeof(OID_SUBJECT_ALT_NAME) - 1 ||
-          memcmp(*p, OID_SUBJECT_ALT_NAME, sizeof(OID_SUBJECT_ALT_NAME) - 1) != 0)
-        {
-          *p += ext_len - (*p - ext_start);
-          continue;
-        }
-      *p += len;
-
-      err = asn1_get_tag(p, end, &len, ASN1_OCTET_STRING);
-      if (err)
-        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
-                                NULL);
-
-      /*   SubjectAltName ::= GeneralNames
-
-           GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
-
-           GeneralName ::= CHOICE {
-                other Name                      [0]     OtherName,
-                rfc822Name                      [1]     IA5String,
-                dNSName                         [2]     IA5String,
-                x400Address                     [3]     ORAddress,
-                directoryName                   [4]     Name,
-                ediPartyName                    [5]     EDIPartyName,
-                uniformResourceIdentifier       [6]     IA5String,
-                iPAddress                       [7]     OCTET STRING,
-                registeredID                    [8]     OBJECT IDENTIFIER } */
-      sna_end = *p + len;
-
-      err = asn1_get_tag(p, sna_end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
-      if (err)
-        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
-                                NULL);
-
-      if (sna_end != *p + len)
-        {
-          err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
-          return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL);
-        }
-
-      while (*p < sna_end)
-        {
-          err = asn1_get_tag(p, sna_end, &len, ASN1_CONTEXT_SPECIFIC |
-                             ASN1_PRIMITIVE | 2);
-          if (err)
-            {
-              /* not not a dNSName */
-              if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
-                {
-                  svn_error_clear(err);
-                  /* need to skip the tag and then find the length to
-                   * skip to ignore this SNA entry. */
-                  (*p)++;
-                  SVN_ERR(asn1_get_len(p, sna_end, &len));
-                  *p += len;
-                  continue;
-                }
-            }
-          else
-            {
-              /* We found a dNSName entry */
-              x509_buf *dnsname = apr_palloc(dnsnames->pool,
-                                             sizeof(x509_buf));
-              dnsname->tag = ASN1_IA5_STRING; /* implicit based on dNSName */
-              dnsname->len = len;
-              dnsname->p = *p;
-              APR_ARRAY_PUSH(dnsnames, x509_buf *) = dnsname;
-            }
-
-          *p += len;
-        }
-
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Escape all non-ascii or control characters similar to
- * svn_xml_fuzzy_escape() and svn_utf_cstring_from_utf8_fuzzy().
- * All of the encoding formats somewhat overlap with ascii (BMPString
- * and UniversalString are actually always wider so you'll end up
- * with a bunch of escaped nul bytes, but ideally we don't get here
- * for those). */
-static const svn_string_t *
-fuzzy_escape(const svn_string_t *src, apr_pool_t *result_pool)
-{
-  const char *end = src->data + src->len;
-  const char *p = src->data, *q;
-  svn_stringbuf_t *outstr;
-  char escaped_char[6]; /* ? \ u u u \0 */
-
-  for (q = p; q < end; q++)
-    {
-      if (!svn_ctype_isascii(*q) || svn_ctype_iscntrl(*q))
-        break;
-    }
-
-  if (q == end)
-    return src;
-
-  outstr = svn_stringbuf_create_empty(result_pool);
-  while (1)
-    {
-      q = p;
-
-      /* Traverse till either unsafe character or eos. */
-      while (q < end && svn_ctype_isascii(*q) && !svn_ctype_iscntrl(*q))
-        q++;
-
-      /* copy chunk before marker */
-      svn_stringbuf_appendbytes(outstr, p, q - p);
-
-      if (q == end)
-        break;
-
-      apr_snprintf(escaped_char, sizeof(escaped_char), "?\\%03u",
-                   (unsigned char) *q);
-      svn_stringbuf_appendcstr(outstr, escaped_char);
-
-      p = q + 1;
-    }
-
-  return svn_stringbuf__morph_into_string(outstr);
-}
-
-/* Escape only NUL characters from a string that is presumed to
- * be UTF-8 encoded. */
-static const svn_string_t *
-nul_escape(const svn_string_t *src, apr_pool_t *result_pool)
-{
-  const char *end = src->data + src->len;
-  const char *p = src->data, *q;
-  svn_stringbuf_t *outstr;
-
-  for (q = p; q < end; q++)
-    {
-      if (*q == '\0')
-        break;
-    }
-
-  if (q == end)
-    return src;
-
-  outstr = svn_stringbuf_create_empty(result_pool);
-  while (1)
-    {
-      q = p;
-
-      /* Traverse till either unsafe character or eos. */
-      while (q < end && *q != '\0')
-        q++;
-
-      /* copy chunk before marker */
-      svn_stringbuf_appendbytes(outstr, p, q - p);
-
-      if (q == end)
-        break;
-
-      svn_stringbuf_appendcstr(outstr, "?\\000");
-
-      p = q + 1;
-    }
-
-  return svn_stringbuf__morph_into_string(outstr);
-}
-
-
-/* Convert an ISO-8859-1 (Latin-1) string to UTF-8.
-   ISO-8859-1 is a strict subset of Unicode. */
-static svn_error_t *
-latin1_to_utf8(const svn_string_t **result, const svn_string_t *src,
-               apr_pool_t *result_pool)
-{
-  apr_int32_t *ucs4buf;
-  svn_membuf_t resultbuf;
-  apr_size_t length;
-  apr_size_t i;
-  svn_string_t *res;
-
-  ucs4buf = apr_palloc(result_pool, src->len * sizeof(*ucs4buf));
-  for (i = 0; i < src->len; ++i)
-    ucs4buf[i] = (unsigned char)(src->data[i]);
-
-  svn_membuf__create(&resultbuf, 2 * src->len, result_pool);
-  SVN_ERR(svn_utf__encode_ucs4_string(
-              &resultbuf, ucs4buf, src->len, &length));
-
-  res = apr_palloc(result_pool, sizeof(*res));
-  res->data = resultbuf.data;
-  res->len = length;
-  *result = res;
-  return SVN_NO_ERROR;
-}
-
-/* Make a best effort to convert a X.509 name to a UTF-8 encoded
- * string and return it.  If we can't properly convert just do a
- * fuzzy conversion so we have something to display. */
-static const svn_string_t *
-x509name_to_utf8_string(const x509_name *name, apr_pool_t *result_pool)
-{
-  const svn_string_t *src_string;
-  const svn_string_t *utf8_string;
-  svn_error_t *err;
-
-  src_string = svn_string_ncreate((const char *)name->val.p,
-                                  name->val.len,
-                                  result_pool);
-  switch (name->val.tag)
-    {
-    case ASN1_UTF8_STRING:
-      if (svn_utf__is_valid(src_string->data, src_string->len))
-        return nul_escape(src_string, result_pool);
-      else
-        /* not a valid UTF-8 string, who knows what it is,
-         * so run it through the fuzzy_escape code.  */
-        return fuzzy_escape(src_string, result_pool);
-      break;
-
-      /* Both BMP and UNIVERSAL should always be in Big Endian (aka
-       * network byte order).  But rumor has it that there are certs
-       * out there with other endianess and even Byte Order Marks.
-       * If we actually run into these, we might need to do something
-       * about it. */
-
-    case ASN1_BMP_STRING:
-      if (0 != src_string->len % sizeof(apr_uint16_t))
-          return fuzzy_escape(src_string, result_pool);
-      err = svn_utf__utf16_to_utf8(&utf8_string,
-                                   (const void*)(src_string->data),
-                                   src_string->len / sizeof(apr_uint16_t),
-                                   TRUE, result_pool, result_pool);
-      break;
-
-    case ASN1_UNIVERSAL_STRING:
-      if (0 != src_string->len % sizeof(apr_int32_t))
-          return fuzzy_escape(src_string, result_pool);
-      err = svn_utf__utf32_to_utf8(&utf8_string,
-                                   (const void*)(src_string->data),
-                                   src_string->len / sizeof(apr_int32_t),
-                                   TRUE, result_pool, result_pool);
-      break;
-
-      /* Despite what all the IETF, ISO, ITU bits say everything out
-       * on the Internet that I can find treats this as ISO-8859-1.
-       * Even the name is misleading, it's not actually T.61.  All the
-       * gory details can be found in the Character Sets section of:
-       * https://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
-       */
-    case ASN1_T61_STRING:
-      err = latin1_to_utf8(&utf8_string, src_string, result_pool);
-      break;
-
-      /* This leaves two types out there in the wild.  PrintableString,
-       * which is just a subset of ASCII and IA5 which is ASCII (though
-       * 0x24 '$' and 0x23 '#' may be defined with differnet symbols
-       * depending on the location, in practice it seems everyone just
-       * treats it as ASCII).  Since these are just ASCII run through
-       * the fuzzy_escape code to deal with anything that isn't actually
-       * ASCII.  There shouldn't be any other types here but if we find
-       * a cert with some other encoding, the best we can do is the
-       * fuzzy_escape().  Note: Technically IA5 isn't valid in this
-       * context, however in the real world it may pop up. */
-    default:
-      return fuzzy_escape(src_string, result_pool);
-    }
-
-  if (err)
-    {
-      svn_error_clear(err);
-      return fuzzy_escape(src_string, result_pool);
-    }
-
-  return nul_escape(utf8_string, result_pool);
-}
-
-/*
- * Store the name from dn in printable form into buf,
- * using scratch_pool for any temporary allocations.
- */
-static void
-x509parse_dn_gets(svn_stringbuf_t *buf, const x509_name * dn,
-                  apr_pool_t *scratch_pool)
-{
-  const x509_name *name;
-  const char *temp;
-
-  name = dn;
-
-  while (name != NULL) {
-    const svn_string_t *utf8_value;
-
-    if (name != dn)
-      svn_stringbuf_appendcstr(buf, ", ");
-
-    if (memcmp(name->oid.p, OID_X520, 2) == 0) {
-      switch (name->oid.p[2]) {
-      case X520_COMMON_NAME:
-        svn_stringbuf_appendcstr(buf, "CN=");
-        break;
-
-      case X520_COUNTRY:
-        svn_stringbuf_appendcstr(buf, "C=");
-        break;
-
-      case X520_LOCALITY:
-        svn_stringbuf_appendcstr(buf, "L=");
-        break;
-
-      case X520_STATE:
-        svn_stringbuf_appendcstr(buf, "ST=");
-        break;
-
-      case X520_ORGANIZATION:
-        svn_stringbuf_appendcstr(buf, "O=");
-        break;
-
-      case X520_ORG_UNIT:
-        svn_stringbuf_appendcstr(buf, "OU=");
-        break;
-
-      default:
-        temp = apr_psprintf(scratch_pool, "0x%02X=", name->oid.p[2]);
-        svn_stringbuf_appendcstr(buf, temp);
-        break;
-      }
-    } else if (memcmp(name->oid.p, OID_PKCS9, 8) == 0) {
-      switch (name->oid.p[8]) {
-      case PKCS9_EMAIL:
-        svn_stringbuf_appendcstr(buf, "emailAddress=");
-        break;
-
-      default:
-        temp = apr_psprintf(scratch_pool, "0x%02X=", name->oid.p[8]);
-        svn_stringbuf_appendcstr(buf, temp);
-        break;
-      }
-    } else
-      svn_stringbuf_appendcstr(buf, "\?\?=");
-
-    utf8_value = x509name_to_utf8_string(name, scratch_pool);
-    if (utf8_value)
-      svn_stringbuf_appendbytes(buf, utf8_value->data, utf8_value->len);
-    else
-      /* this should never happen */
-      svn_stringbuf_appendfill(buf, '?', 2);
-
-    name = name->next;
-  }
-}
-
-static svn_boolean_t
-is_hostname(const svn_string_t *str)
-{
-  apr_size_t i;
-
-  for (i = 0; i < str->len; i++)
-    {
-      char c = str->data[i];
-
-      /* '-' is only legal when not at the start or end of a label */
-      if (c == '-')
-        {
-          if (i + 1 != str->len)
-            {
-              if (str->data[i + 1] == '.')
-                return FALSE; /* '-' preceeds a '.' */
-            }
-          else
-            return FALSE; /* '-' is at end of string */
-
-          /* determine the previous character. */
-          if (i == 0)
-            return FALSE; /* '-' is at start of string */
-          else
-            if (str->data[i - 1] == '.')
-              return FALSE; /* '-' follows a '.' */
-        }
-      else if (c != '*' && c != '.' && !svn_ctype_isalnum(c))
-        return FALSE; /* some character not allowed */
-    }
-
-  return TRUE;
-}
-
-static void
-x509parse_get_hostnames(apr_array_header_t **names, x509_cert *crt,
-                        apr_pool_t *result_pool, apr_pool_t *scratch_pool)
-{
-  if (crt->dnsnames->nelts > 0)
-    {
-      int i;
-
-      *names = apr_array_make(result_pool, crt->dnsnames->nelts,
-                             sizeof(const char*));
-
-      /* Subject Alt Names take priority */
-      for (i = 0; i < crt->dnsnames->nelts; i++)
-        {
-          x509_buf *dnsname = APR_ARRAY_IDX(crt->dnsnames, i, x509_buf *);
-          const svn_string_t *temp = svn_string_ncreate((const char *)dnsname->p,
-                                                        dnsname->len,
-                                                        scratch_pool);
-
-          temp = fuzzy_escape(temp, result_pool);
-          APR_ARRAY_PUSH(*names, const char*) = temp->data;
-        }
-    }
-  else
-    {
-      const x509_name *name = &crt->subject;
-      const svn_string_t *utf8_value = NULL;
-
-      /* no SAN then get the hostname from the CommonName on the cert */
-      while (name != NULL)
-        {
-          if (memcmp(name->oid.p, OID_X520, 2) == 0)
-            {
-              if (name->oid.p[2] == X520_COMMON_NAME)
-                {
-                  utf8_value = x509name_to_utf8_string(name, scratch_pool);
-                  if (is_hostname(utf8_value))
-                    break;
-                  else
-                    utf8_value = NULL;
-                }
-            }
-          name = name->next;
-        }
-
-      if (utf8_value)
-        {
-          *names = apr_array_make(result_pool, 1, sizeof(const char*));
-          APR_ARRAY_PUSH(*names, const char*) = utf8_value->data;
-        }
-    }
-}
-
-/*
- * Parse one certificate.
- */
-svn_error_t *
-svn_x509_parse_cert(svn_x509_certinfo_t **certinfo,
-                    const char *buf,
-                    apr_size_t buflen,
-                    apr_pool_t *result_pool,
-                    apr_pool_t *scratch_pool)
-{
-  svn_error_t *err;
-  ptrdiff_t len;
-  const unsigned char *p;
-  const unsigned char *end;
-  x509_cert *crt;
-  svn_x509_certinfo_t *ci;
-  svn_stringbuf_t *namebuf;
-
-  crt = apr_pcalloc(scratch_pool, sizeof(*crt));
-  p = (const unsigned char *)buf;
-  len = buflen;
-  end = p + len;
-
-  /*
-   * Certificate  ::=      SEQUENCE  {
-   *              tbsCertificate           TBSCertificate,
-   *              signatureAlgorithm       AlgorithmIdentifier,
-   *              signatureValue           BIT STRING      }
-   */
-  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, NULL, NULL);
-
-  if (len != (end - p))
-    {
-      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
-    }
-
-  /*
-   * TBSCertificate  ::=  SEQUENCE  {
-   */
-  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
-
-  end = p + len;
-
-  /*
-   * Version      ::=      INTEGER  {      v1(0), v2(1), v3(2)  }
-   *
-   * CertificateSerialNumber      ::=      INTEGER
-   *
-   * signature                    AlgorithmIdentifier
-   */
-  SVN_ERR(x509_get_version(&p, end, &crt->version));
-  SVN_ERR(x509_get_serial(&p, end, &crt->serial));
-  SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid1));
-
-  crt->version++;
-
-  if (crt->version > 3)
-    return svn_error_create(SVN_ERR_X509_CERT_UNKNOWN_VERSION, NULL, NULL);
-
-  /*
-   * issuer                               Name
-   */
-  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
-
-  SVN_ERR(x509_get_name(&p, p + len, &crt->issuer, scratch_pool));
-
-  /*
-   * Validity ::= SEQUENCE {
-   *              notBefore          Time,
-   *              notAfter           Time }
-   *
-   */
-  SVN_ERR(x509_get_dates(&crt->valid_from, &crt->valid_to, &p, end,
-                         scratch_pool));
-
-  /*
-   * subject                              Name
-   */
-  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
-
-  SVN_ERR(x509_get_name(&p, p + len, &crt->subject, scratch_pool));
-
-  /*
-   * SubjectPublicKeyInfo  ::=  SEQUENCE
-   *              algorithm                        AlgorithmIdentifier,
-   *              subjectPublicKey         BIT STRING      }
-   */
-  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
-  if (err)
-    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
-
-  /* Skip pubkey. */
-  p += len;
-
-  /*
-   *      issuerUniqueID  [1]      IMPLICIT UniqueIdentifier OPTIONAL,
-   *                                               -- If present, version shall be v2 or v3
-   *      subjectUniqueID [2]      IMPLICIT UniqueIdentifier OPTIONAL,
-   *                                               -- If present, version shall be v2 or v3
-   *      extensions              [3]      EXPLICIT Extensions OPTIONAL
-   *                                               -- If present, version shall be v3
-   */
-  if (crt->version == 2 || crt->version == 3)
-    SVN_ERR(x509_get_uid(&p, end, &crt->issuer_id, 1));
-
-  if (crt->version == 2 || crt->version == 3)
-    SVN_ERR(x509_get_uid(&p, end, &crt->subject_id, 2));
-
-  if (crt->version == 3)
-    {
-      crt->dnsnames = apr_array_make(scratch_pool, 3, sizeof(x509_buf *));
-      SVN_ERR(x509_get_ext(crt->dnsnames, &p, end));
-    }
-
-  if (p != end)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
-    }
-
-  end = (const unsigned char*) buf + buflen;
-
-  /*
-   *      signatureAlgorithm       AlgorithmIdentifier,
-   *      signatureValue           BIT STRING
-   */
-  SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid2));
-
-  if (memcmp(crt->sig_oid1.p, crt->sig_oid2.p, 9) != 0)
-    return svn_error_create(SVN_ERR_X509_CERT_SIG_MISMATCH, NULL, NULL);
-
-  SVN_ERR(x509_get_sig(&p, end, &crt->sig));
-
-  if (p != end)
-    {
-      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
-      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
-    }
-
-  ci = apr_pcalloc(result_pool, sizeof(*ci));
-
-  /* Get the subject name */
-  namebuf = svn_stringbuf_create_empty(result_pool);
-  x509parse_dn_gets(namebuf, &crt->subject, scratch_pool);
-  ci->subject = namebuf->data;
-
-  /* Get the issuer name */
-  namebuf = svn_stringbuf_create_empty(result_pool);
-  x509parse_dn_gets(namebuf, &crt->issuer, scratch_pool);
-  ci->issuer = namebuf->data;
-
-  /* Copy the validity range */
-  ci->valid_from = crt->valid_from;
-  ci->valid_to = crt->valid_to;
-
-  /* Calculate the SHA1 digest of the certificate, otherwise known as
-    the fingerprint */
-  SVN_ERR(svn_checksum(&ci->digest, svn_checksum_sha1, buf, buflen,
-                       result_pool));
-
-  /* Construct the array of host names */
-  x509parse_get_hostnames(&ci->hostnames, crt, result_pool, scratch_pool);
-
-  *certinfo = ci;
-  return SVN_NO_ERROR;
-}
-
+/*
+ *  X.509 certificate and private key decoding
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008   Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ *  The ITU-T X.509 standard defines a certificate format for PKI.
+ *
+ *  http://www.ietf.org/rfc/rfc5280.txt
+ *  http://www.ietf.org/rfc/rfc3279.txt
+ *  http://www.ietf.org/rfc/rfc6818.txt
+ *
+ *  ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
+ *
+ *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
+ *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
+ */
+
+#include <apr_pools.h>
+#include <apr_tables.h>
+#include "svn_hash.h"
+#include "svn_string.h"
+#include "svn_time.h"
+#include "svn_checksum.h"
+#include "svn_utf.h"
+#include "svn_ctype.h"
+#include "svn_x509.h"
+#include "private/svn_utf_private.h"
+#include "private/svn_string_private.h"
+
+#include "x509.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * ASN.1 DER decoding routines
+ */
+static svn_error_t *
+asn1_get_len(const unsigned char **p, const unsigned char *end,
+             ptrdiff_t *len)
+{
+  if ((end - *p) < 1)
+    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
+
+  if ((**p & 0x80) == 0)
+    *len = *(*p)++;
+  else
+    switch (**p & 0x7F)
+      {
+      case 1:
+        if ((end - *p) < 2)
+          return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
+
+        *len = (*p)[1];
+        (*p) += 2;
+        break;
+
+      case 2:
+        if ((end - *p) < 3)
+          return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
+
+        *len = ((*p)[1] << 8) | (*p)[2];
+        (*p) += 3;
+        break;
+
+      default:
+        return svn_error_create(SVN_ERR_ASN1_INVALID_LENGTH, NULL, NULL);
+        break;
+      }
+
+  if (*len > (end - *p))
+    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+asn1_get_tag(const unsigned char **p,
+             const unsigned char *end, ptrdiff_t *len, int tag)
+{
+  if ((end - *p) < 1)
+    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
+
+  if (**p != tag)
+    return svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
+
+  (*p)++;
+
+  return svn_error_trace(asn1_get_len(p, end, len));
+}
+
+static svn_error_t *
+asn1_get_int(const unsigned char **p, const unsigned char *end, int *val)
+{
+  ptrdiff_t len;
+
+  SVN_ERR(asn1_get_tag(p, end, &len, ASN1_INTEGER));
+
+  if (len > (int)sizeof(int) || (**p & 0x80) != 0)
+    return svn_error_create(SVN_ERR_ASN1_INVALID_LENGTH, NULL, NULL);
+
+  *val = 0;
+
+  while (len-- > 0) {
+    *val = (*val << 8) | **p;
+    (*p)++;
+  }
+
+  return SVN_NO_ERROR;
+}
+
+/*
+ *  Version   ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+ */
+static svn_error_t *
+x509_get_version(const unsigned char **p, const unsigned char *end, int *ver)
+{
+  svn_error_t *err;
+  ptrdiff_t len;
+
+  err = asn1_get_tag(p, end, &len,
+                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
+        {
+          svn_error_clear(err);
+          *ver = 0;
+          return SVN_NO_ERROR;
+        }
+
+      return svn_error_trace(err);
+    }
+
+  end = *p + len;
+
+  err = asn1_get_int(p, end, ver);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_VERSION, err, NULL);
+
+  if (*p != end)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_VERSION, err, NULL);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/*
+ *  CertificateSerialNumber   ::=  INTEGER
+ */
+static svn_error_t *
+x509_get_serial(const unsigned char **p,
+                const unsigned char *end, x509_buf * serial)
+{
+  svn_error_t *err;
+
+  if ((end - *p) < 1)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
+    }
+
+  if (**p != (ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2) &&
+      **p != ASN1_INTEGER)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
+    }
+
+  serial->tag = *(*p)++;
+
+  err = asn1_get_len(p, end, &serial->len);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
+
+  serial->p = *p;
+  *p += serial->len;
+
+  return SVN_NO_ERROR;
+}
+
+/*
+ *  AlgorithmIdentifier   ::=  SEQUENCE  {
+ *     algorithm         OBJECT IDENTIFIER,
+ *     parameters        ANY DEFINED BY algorithm OPTIONAL  }
+ */
+static svn_error_t *
+x509_get_alg(const unsigned char **p, const unsigned char *end, x509_buf * alg)
+{
+  svn_error_t *err;
+  ptrdiff_t len;
+
+  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
+
+  end = *p + len;
+  alg->tag = **p;
+
+  err = asn1_get_tag(p, end, &alg->len, ASN1_OID);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
+
+  alg->p = *p;
+  *p += alg->len;
+
+  if (*p == end)
+    return SVN_NO_ERROR;
+
+  /*
+   * assume the algorithm parameters must be NULL
+   */
+  err = asn1_get_tag(p, end, &len, ASN1_NULL);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
+
+  if (*p != end)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/*
+ *  RelativeDistinguishedName ::=
+ *    SET OF AttributeTypeAndValue
+ *
+ *  AttributeTypeAndValue ::= SEQUENCE {
+ *    type     AttributeType,
+ *    value     AttributeValue }
+ *
+ *  AttributeType ::= OBJECT IDENTIFIER
+ *
+ *  AttributeValue ::= ANY DEFINED BY AttributeType
+ */
+static svn_error_t *
+x509_get_name(const unsigned char **p, const unsigned char *end,
+              x509_name * cur, apr_pool_t *result_pool)
+{
+  svn_error_t *err;
+  ptrdiff_t len;
+  const unsigned char *end2;
+  x509_buf *oid;
+  x509_buf *val;
+
+  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SET);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
+
+  end2 = end;
+  end = *p + len;
+
+  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
+
+  if (*p + len != end)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
+    }
+
+  oid = &cur->oid;
+  oid->tag = **p;
+
+  err = asn1_get_tag(p, end, &oid->len, ASN1_OID);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
+
+  oid->p = *p;
+  *p += oid->len;
+
+  if ((end - *p) < 1)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
+    }
+
+  if (**p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING &&
+      **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING &&
+      **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
+    }
+
+  val = &cur->val;
+  val->tag = *(*p)++;
+
+  err = asn1_get_len(p, end, &val->len);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
+
+  val->p = *p;
+  *p += val->len;
+
+  cur->next = NULL;
+
+  if (*p != end)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
+    }
+
+  /*
+   * recurse until end of SEQUENCE is reached
+   */
+  if (*p == end2)
+    return SVN_NO_ERROR;
+
+  cur->next = (x509_name *) apr_palloc(result_pool, sizeof(x509_name));
+
+  if (cur->next == NULL)
+    return SVN_NO_ERROR;
+
+  return svn_error_trace(x509_get_name(p, end2, cur->next, result_pool));
+}
+
+/* Retrieve the date from the X.509 cert data between *P and END in either
+ * UTCTime or GeneralizedTime format (as defined in RFC 5280 s. 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_get_date(apr_time_t *when,
+              const unsigned char **p,
+              const unsigned char *end,
+              apr_pool_t *scratch_pool)
+{
+  svn_error_t *err;
+  apr_status_t ret;
+  int tag;
+  ptrdiff_t len;
+  char *date;
+  apr_time_exp_t xt = { 0 };
+  char tz;
+
+  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
+   * always be GMT.  A little bit of extra paranoia here seems like a good
+   * idea. */
+  if (tz != 'Z')
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
+
+  /* apr_time_exp_t expects months to be zero indexed, 0=Jan, 11=Dec. */
+  xt.tm_mon -= 1;
+
+  ret = apr_time_exp_gmt_get(when, &xt);
+  if (ret)
+    return svn_error_wrap_apr(ret, NULL);
+
+  *p += len;
+
+  return SVN_NO_ERROR;
+}
+
+/*
+ *  Validity ::= SEQUENCE {
+ *     notBefore    Time,
+ *     notAfter    Time }
+ *
+ *  Time ::= CHOICE {
+ *     utcTime    UTCTime,
+ *     generalTime  GeneralizedTime }
+ */
+static svn_error_t *
+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;
+  ptrdiff_t len;
+
+  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
+
+  end = *p + len;
+
+  SVN_ERR(x509_get_date(from, p, end, scratch_pool));
+
+  SVN_ERR(x509_get_date(to, p, end, scratch_pool));
+
+  if (*p != end)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+x509_get_sig(const unsigned char **p, const unsigned char *end, x509_buf * sig)
+{
+  svn_error_t *err;
+  ptrdiff_t len;
+
+  sig->tag = **p;
+
+  err = asn1_get_tag(p, end, &len, ASN1_BIT_STRING);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, err, NULL);
+
+  if (--len < 1 || *(*p)++ != 0)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, NULL, NULL);
+
+  sig->len = len;
+  sig->p = *p;
+
+  *p += len;
+
+  return SVN_NO_ERROR;
+}
+
+/*
+ * X.509 v2/v3 unique identifier (not parsed)
+ */
+static svn_error_t *
+x509_get_uid(const unsigned char **p,
+             const unsigned char *end, x509_buf * uid, int n)
+{
+  svn_error_t *err;
+
+  if (*p == end)
+    return SVN_NO_ERROR;
+
+  uid->tag = **p;
+
+  err = asn1_get_tag(p, end, &uid->len,
+                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
+        {
+          svn_error_clear(err);
+          return SVN_NO_ERROR;
+        }
+
+      return svn_error_trace(err);
+    }
+
+  uid->p = *p;
+  *p += uid->len;
+
+  return SVN_NO_ERROR;
+}
+
+/*
+ * X.509 v3 extensions (not parsed)
+ */
+static svn_error_t *
+x509_get_ext(apr_array_header_t *dnsnames,
+             const unsigned char **p,
+             const unsigned char *end)
+{
+  svn_error_t *err;
+  ptrdiff_t len;
+
+  if (*p == end)
+    return SVN_NO_ERROR;
+
+  err = asn1_get_tag(p, end, &len,
+                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3);
+  if (err)
+    {
+      /* If there aren't extensions that's ok they aren't required */
+      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
+        {
+          svn_error_clear(err);
+          return SVN_NO_ERROR;
+        }
+
+      return svn_error_trace(err);
+    }
+
+  end = *p + len;
+
+  SVN_ERR(asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE));
+
+  if (end != *p + len)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL);
+    }
+
+  while (*p < end)
+    {
+      ptrdiff_t ext_len;
+      const unsigned char *ext_start, *sna_end;
+      err = asn1_get_tag(p, end, &ext_len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
+      if (err)
+        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
+                                NULL);
+      ext_start = *p;
+
+      err = asn1_get_tag(p, end, &len, ASN1_OID);
+      if (err)
+        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
+                                NULL);
+
+      /* skip all extensions except SubjectAltName */
+      if (len != sizeof(OID_SUBJECT_ALT_NAME) - 1 ||
+          memcmp(*p, OID_SUBJECT_ALT_NAME, sizeof(OID_SUBJECT_ALT_NAME) - 1) != 0)
+        {
+          *p += ext_len - (*p - ext_start);
+          continue;
+        }
+      *p += len;
+
+      err = asn1_get_tag(p, end, &len, ASN1_OCTET_STRING);
+      if (err)
+        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
+                                NULL);
+
+      /*   SubjectAltName ::= GeneralNames
+
+           GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+
+           GeneralName ::= CHOICE {
+                other Name                      [0]     OtherName,
+                rfc822Name                      [1]     IA5String,
+                dNSName                         [2]     IA5String,
+                x400Address                     [3]     ORAddress,
+                directoryName                   [4]     Name,
+                ediPartyName                    [5]     EDIPartyName,
+                uniformResourceIdentifier       [6]     IA5String,
+                iPAddress                       [7]     OCTET STRING,
+                registeredID                    [8]     OBJECT IDENTIFIER } */
+      sna_end = *p + len;
+
+      err = asn1_get_tag(p, sna_end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
+      if (err)
+        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
+                                NULL);
+
+      if (sna_end != *p + len)
+        {
+          err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
+          return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL);
+        }
+
+      while (*p < sna_end)
+        {
+          err = asn1_get_tag(p, sna_end, &len, ASN1_CONTEXT_SPECIFIC |
+                             ASN1_PRIMITIVE | 2);
+          if (err)
+            {
+              /* not not a dNSName */
+              if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
+                {
+                  svn_error_clear(err);
+                  /* need to skip the tag and then find the length to
+                   * skip to ignore this SNA entry. */
+                  (*p)++;
+                  SVN_ERR(asn1_get_len(p, sna_end, &len));
+                  *p += len;
+                  continue;
+                }
+            }
+          else
+            {
+              /* We found a dNSName entry */
+              x509_buf *dnsname = apr_palloc(dnsnames->pool,
+                                             sizeof(x509_buf));
+              dnsname->tag = ASN1_IA5_STRING; /* implicit based on dNSName */
+              dnsname->len = len;
+              dnsname->p = *p;
+              APR_ARRAY_PUSH(dnsnames, x509_buf *) = dnsname;
+            }
+
+          *p += len;
+        }
+
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Escape all non-ascii or control characters similar to
+ * svn_xml_fuzzy_escape() and svn_utf_cstring_from_utf8_fuzzy().
+ * All of the encoding formats somewhat overlap with ascii (BMPString
+ * and UniversalString are actually always wider so you'll end up
+ * with a bunch of escaped nul bytes, but ideally we don't get here
+ * for those). */
+static const svn_string_t *
+fuzzy_escape(const svn_string_t *src, apr_pool_t *result_pool)
+{
+  const char *end = src->data + src->len;
+  const char *p = src->data, *q;
+  svn_stringbuf_t *outstr;
+  char escaped_char[6]; /* ? \ u u u \0 */
+
+  for (q = p; q < end; q++)
+    {
+      if (!svn_ctype_isascii(*q) || svn_ctype_iscntrl(*q))
+        break;
+    }
+
+  if (q == end)
+    return src;
+
+  outstr = svn_stringbuf_create_empty(result_pool);
+  while (1)
+    {
+      q = p;
+
+      /* Traverse till either unsafe character or eos. */
+      while (q < end && svn_ctype_isascii(*q) && !svn_ctype_iscntrl(*q))
+        q++;
+
+      /* copy chunk before marker */
+      svn_stringbuf_appendbytes(outstr, p, q - p);
+
+      if (q == end)
+        break;
+
+      apr_snprintf(escaped_char, sizeof(escaped_char), "?\\%03u",
+                   (unsigned char) *q);
+      svn_stringbuf_appendcstr(outstr, escaped_char);
+
+      p = q + 1;
+    }
+
+  return svn_stringbuf__morph_into_string(outstr);
+}
+
+/* Escape only NUL characters from a string that is presumed to
+ * be UTF-8 encoded. */
+static const svn_string_t *
+nul_escape(const svn_string_t *src, apr_pool_t *result_pool)
+{
+  const char *end = src->data + src->len;
+  const char *p = src->data, *q;
+  svn_stringbuf_t *outstr;
+
+  for (q = p; q < end; q++)
+    {
+      if (*q == '\0')
+        break;
+    }
+
+  if (q == end)
+    return src;
+
+  outstr = svn_stringbuf_create_empty(result_pool);
+  while (1)
+    {
+      q = p;
+
+      /* Traverse till either unsafe character or eos. */
+      while (q < end && *q != '\0')
+        q++;
+
+      /* copy chunk before marker */
+      svn_stringbuf_appendbytes(outstr, p, q - p);
+
+      if (q == end)
+        break;
+
+      svn_stringbuf_appendcstr(outstr, "?\\000");
+
+      p = q + 1;
+    }
+
+  return svn_stringbuf__morph_into_string(outstr);
+}
+
+
+/* Convert an ISO-8859-1 (Latin-1) string to UTF-8.
+   ISO-8859-1 is a strict subset of Unicode. */
+static svn_error_t *
+latin1_to_utf8(const svn_string_t **result, const svn_string_t *src,
+               apr_pool_t *result_pool)
+{
+  apr_int32_t *ucs4buf;
+  svn_membuf_t resultbuf;
+  apr_size_t length;
+  apr_size_t i;
+  svn_string_t *res;
+
+  ucs4buf = apr_palloc(result_pool, src->len * sizeof(*ucs4buf));
+  for (i = 0; i < src->len; ++i)
+    ucs4buf[i] = (unsigned char)(src->data[i]);
+
+  svn_membuf__create(&resultbuf, 2 * src->len, result_pool);
+  SVN_ERR(svn_utf__encode_ucs4_string(
+              &resultbuf, ucs4buf, src->len, &length));
+
+  res = apr_palloc(result_pool, sizeof(*res));
+  res->data = resultbuf.data;
+  res->len = length;
+  *result = res;
+  return SVN_NO_ERROR;
+}
+
+/* Make a best effort to convert a X.509 name to a UTF-8 encoded
+ * string and return it.  If we can't properly convert just do a
+ * fuzzy conversion so we have something to display. */
+static const svn_string_t *
+x509name_to_utf8_string(const x509_name *name, apr_pool_t *result_pool)
+{
+  const svn_string_t *src_string;
+  const svn_string_t *utf8_string;
+  svn_error_t *err;
+
+  src_string = svn_string_ncreate((const char *)name->val.p,
+                                  name->val.len,
+                                  result_pool);
+  switch (name->val.tag)
+    {
+    case ASN1_UTF8_STRING:
+      if (svn_utf__is_valid(src_string->data, src_string->len))
+        return nul_escape(src_string, result_pool);
+      else
+        /* not a valid UTF-8 string, who knows what it is,
+         * so run it through the fuzzy_escape code.  */
+        return fuzzy_escape(src_string, result_pool);
+      break;
+
+      /* Both BMP and UNIVERSAL should always be in Big Endian (aka
+       * network byte order).  But rumor has it that there are certs
+       * out there with other endianess and even Byte Order Marks.
+       * If we actually run into these, we might need to do something
+       * about it. */
+
+    case ASN1_BMP_STRING:
+      if (0 != src_string->len % sizeof(apr_uint16_t))
+          return fuzzy_escape(src_string, result_pool);
+      err = svn_utf__utf16_to_utf8(&utf8_string,
+                                   (const void*)(src_string->data),
+                                   src_string->len / sizeof(apr_uint16_t),
+                                   TRUE, result_pool, result_pool);
+      break;
+
+    case ASN1_UNIVERSAL_STRING:
+      if (0 != src_string->len % sizeof(apr_int32_t))
+          return fuzzy_escape(src_string, result_pool);
+      err = svn_utf__utf32_to_utf8(&utf8_string,
+                                   (const void*)(src_string->data),
+                                   src_string->len / sizeof(apr_int32_t),
+                                   TRUE, result_pool, result_pool);
+      break;
+
+      /* Despite what all the IETF, ISO, ITU bits say everything out
+       * on the Internet that I can find treats this as ISO-8859-1.
+       * Even the name is misleading, it's not actually T.61.  All the
+       * gory details can be found in the Character Sets section of:
+       * https://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
+       */
+    case ASN1_T61_STRING:
+      err = latin1_to_utf8(&utf8_string, src_string, result_pool);
+      break;
+
+      /* This leaves two types out there in the wild.  PrintableString,
+       * which is just a subset of ASCII and IA5 which is ASCII (though
+       * 0x24 '$' and 0x23 '#' may be defined with differnet symbols
+       * depending on the location, in practice it seems everyone just
+       * treats it as ASCII).  Since these are just ASCII run through
+       * the fuzzy_escape code to deal with anything that isn't actually
+       * ASCII.  There shouldn't be any other types here but if we find
+       * a cert with some other encoding, the best we can do is the
+       * fuzzy_escape().  Note: Technically IA5 isn't valid in this
+       * context, however in the real world it may pop up. */
+    default:
+      return fuzzy_escape(src_string, result_pool);
+    }
+
+  if (err)
+    {
+      svn_error_clear(err);
+      return fuzzy_escape(src_string, result_pool);
+    }
+
+  return nul_escape(utf8_string, result_pool);
+}
+
+/*
+ * Store the name from dn in printable form into buf,
+ * using scratch_pool for any temporary allocations.
+ */
+static void
+x509parse_dn_gets(svn_stringbuf_t *buf, const x509_name * dn,
+                  apr_pool_t *scratch_pool)
+{
+  const x509_name *name;
+  const char *temp;
+
+  name = dn;
+
+  while (name != NULL) {
+    const svn_string_t *utf8_value;
+
+    if (name != dn)
+      svn_stringbuf_appendcstr(buf, ", ");
+
+    if (memcmp(name->oid.p, OID_X520, 2) == 0) {
+      switch (name->oid.p[2]) {
+      case X520_COMMON_NAME:
+        svn_stringbuf_appendcstr(buf, "CN=");
+        break;
+
+      case X520_COUNTRY:
+        svn_stringbuf_appendcstr(buf, "C=");
+        break;
+
+      case X520_LOCALITY:
+        svn_stringbuf_appendcstr(buf, "L=");
+        break;
+
+      case X520_STATE:
+        svn_stringbuf_appendcstr(buf, "ST=");
+        break;
+
+      case X520_ORGANIZATION:
+        svn_stringbuf_appendcstr(buf, "O=");
+        break;
+
+      case X520_ORG_UNIT:
+        svn_stringbuf_appendcstr(buf, "OU=");
+        break;
+
+      default:
+        temp = apr_psprintf(scratch_pool, "0x%02X=", name->oid.p[2]);
+        svn_stringbuf_appendcstr(buf, temp);
+        break;
+      }
+    } else if (memcmp(name->oid.p, OID_PKCS9, 8) == 0) {
+      switch (name->oid.p[8]) {
+      case PKCS9_EMAIL:
+        svn_stringbuf_appendcstr(buf, "emailAddress=");
+        break;
+
+      default:
+        temp = apr_psprintf(scratch_pool, "0x%02X=", name->oid.p[8]);
+        svn_stringbuf_appendcstr(buf, temp);
+        break;
+      }
+    } else
+      svn_stringbuf_appendcstr(buf, "\?\?=");
+
+    utf8_value = x509name_to_utf8_string(name, scratch_pool);
+    if (utf8_value)
+      svn_stringbuf_appendbytes(buf, utf8_value->data, utf8_value->len);
+    else
+      /* this should never happen */
+      svn_stringbuf_appendfill(buf, '?', 2);
+
+    name = name->next;
+  }
+}
+
+static svn_boolean_t
+is_hostname(const svn_string_t *str)
+{
+  apr_size_t i;
+
+  for (i = 0; i < str->len; i++)
+    {
+      char c = str->data[i];
+
+      /* '-' is only legal when not at the start or end of a label */
+      if (c == '-')
+        {
+          if (i + 1 != str->len)
+            {
+              if (str->data[i + 1] == '.')
+                return FALSE; /* '-' preceeds a '.' */
+            }
+          else
+            return FALSE; /* '-' is at end of string */
+
+          /* determine the previous character. */
+          if (i == 0)
+            return FALSE; /* '-' is at start of string */
+          else
+            if (str->data[i - 1] == '.')
+              return FALSE; /* '-' follows a '.' */
+        }
+      else if (c != '*' && c != '.' && !svn_ctype_isalnum(c))
+        return FALSE; /* some character not allowed */
+    }
+
+  return TRUE;
+}
+
+static void
+x509parse_get_hostnames(apr_array_header_t **names, x509_cert *crt,
+                        apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  if (crt->dnsnames->nelts > 0)
+    {
+      int i;
+
+      *names = apr_array_make(result_pool, crt->dnsnames->nelts,
+                             sizeof(const char*));
+
+      /* Subject Alt Names take priority */
+      for (i = 0; i < crt->dnsnames->nelts; i++)
+        {
+          x509_buf *dnsname = APR_ARRAY_IDX(crt->dnsnames, i, x509_buf *);
+          const svn_string_t *temp = svn_string_ncreate((const char *)dnsname->p,
+                                                        dnsname->len,
+                                                        scratch_pool);
+
+          temp = fuzzy_escape(temp, result_pool);
+          APR_ARRAY_PUSH(*names, const char*) = temp->data;
+        }
+    }
+  else
+    {
+      const x509_name *name = &crt->subject;
+      const svn_string_t *utf8_value = NULL;
+
+      /* no SAN then get the hostname from the CommonName on the cert */
+      while (name != NULL)
+        {
+          if (memcmp(name->oid.p, OID_X520, 2) == 0)
+            {
+              if (name->oid.p[2] == X520_COMMON_NAME)
+                {
+                  utf8_value = x509name_to_utf8_string(name, scratch_pool);
+                  if (is_hostname(utf8_value))
+                    break;
+                  else
+                    utf8_value = NULL;
+                }
+            }
+          name = name->next;
+        }
+
+      if (utf8_value)
+        {
+          *names = apr_array_make(result_pool, 1, sizeof(const char*));
+          APR_ARRAY_PUSH(*names, const char*) = utf8_value->data;
+        }
+    }
+}
+
+/*
+ * Parse one certificate.
+ */
+svn_error_t *
+svn_x509_parse_cert(svn_x509_certinfo_t **certinfo,
+                    const char *buf,
+                    apr_size_t buflen,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  svn_error_t *err;
+  ptrdiff_t len;
+  const unsigned char *p;
+  const unsigned char *end;
+  x509_cert *crt;
+  svn_x509_certinfo_t *ci;
+  svn_stringbuf_t *namebuf;
+
+  crt = apr_pcalloc(scratch_pool, sizeof(*crt));
+  p = (const unsigned char *)buf;
+  len = buflen;
+  end = p + len;
+
+  /*
+   * Certificate  ::=      SEQUENCE  {
+   *              tbsCertificate           TBSCertificate,
+   *              signatureAlgorithm       AlgorithmIdentifier,
+   *              signatureValue           BIT STRING      }
+   */
+  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, NULL, NULL);
+
+  if (len != (end - p))
+    {
+      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
+    }
+
+  /*
+   * TBSCertificate  ::=  SEQUENCE  {
+   */
+  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
+
+  end = p + len;
+
+  /*
+   * Version      ::=      INTEGER  {      v1(0), v2(1), v3(2)  }
+   *
+   * CertificateSerialNumber      ::=      INTEGER
+   *
+   * signature                    AlgorithmIdentifier
+   */
+  SVN_ERR(x509_get_version(&p, end, &crt->version));
+  SVN_ERR(x509_get_serial(&p, end, &crt->serial));
+  SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid1));
+
+  crt->version++;
+
+  if (crt->version > 3)
+    return svn_error_create(SVN_ERR_X509_CERT_UNKNOWN_VERSION, NULL, NULL);
+
+  /*
+   * issuer                               Name
+   */
+  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
+
+  SVN_ERR(x509_get_name(&p, p + len, &crt->issuer, scratch_pool));
+
+  /*
+   * Validity ::= SEQUENCE {
+   *              notBefore          Time,
+   *              notAfter           Time }
+   *
+   */
+  SVN_ERR(x509_get_dates(&crt->valid_from, &crt->valid_to, &p, end,
+                         scratch_pool));
+
+  /*
+   * subject                              Name
+   */
+  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
+
+  SVN_ERR(x509_get_name(&p, p + len, &crt->subject, scratch_pool));
+
+  /*
+   * SubjectPublicKeyInfo  ::=  SEQUENCE
+   *              algorithm                        AlgorithmIdentifier,
+   *              subjectPublicKey         BIT STRING      }
+   */
+  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
+  if (err)
+    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
+
+  /* Skip pubkey. */
+  p += len;
+
+  /*
+   *      issuerUniqueID  [1]      IMPLICIT UniqueIdentifier OPTIONAL,
+   *                                               -- If present, version shall be v2 or v3
+   *      subjectUniqueID [2]      IMPLICIT UniqueIdentifier OPTIONAL,
+   *                                               -- If present, version shall be v2 or v3
+   *      extensions              [3]      EXPLICIT Extensions OPTIONAL
+   *                                               -- If present, version shall be v3
+   */
+  if (crt->version == 2 || crt->version == 3)
+    SVN_ERR(x509_get_uid(&p, end, &crt->issuer_id, 1));
+
+  if (crt->version == 2 || crt->version == 3)
+    SVN_ERR(x509_get_uid(&p, end, &crt->subject_id, 2));
+
+  if (crt->version == 3)
+    {
+      crt->dnsnames = apr_array_make(scratch_pool, 3, sizeof(x509_buf *));
+      SVN_ERR(x509_get_ext(crt->dnsnames, &p, end));
+    }
+
+  if (p != end)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
+    }
+
+  end = (const unsigned char*) buf + buflen;
+
+  /*
+   *      signatureAlgorithm       AlgorithmIdentifier,
+   *      signatureValue           BIT STRING
+   */
+  SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid2));
+
+  if (memcmp(crt->sig_oid1.p, crt->sig_oid2.p, 9) != 0)
+    return svn_error_create(SVN_ERR_X509_CERT_SIG_MISMATCH, NULL, NULL);
+
+  SVN_ERR(x509_get_sig(&p, end, &crt->sig));
+
+  if (p != end)
+    {
+      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
+      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
+    }
+
+  ci = apr_pcalloc(result_pool, sizeof(*ci));
+
+  /* Get the subject name */
+  namebuf = svn_stringbuf_create_empty(result_pool);
+  x509parse_dn_gets(namebuf, &crt->subject, scratch_pool);
+  ci->subject = namebuf->data;
+
+  /* Get the issuer name */
+  namebuf = svn_stringbuf_create_empty(result_pool);
+  x509parse_dn_gets(namebuf, &crt->issuer, scratch_pool);
+  ci->issuer = namebuf->data;
+
+  /* Copy the validity range */
+  ci->valid_from = crt->valid_from;
+  ci->valid_to = crt->valid_to;
+
+  /* Calculate the SHA1 digest of the certificate, otherwise known as
+    the fingerprint */
+  SVN_ERR(svn_checksum(&ci->digest, svn_checksum_sha1, buf, buflen,
+                       result_pool));
+
+  /* Construct the array of host names */
+  x509parse_get_hostnames(&ci->hostnames, crt, result_pool, scratch_pool);
+
+  *certinfo = ci;
+  return SVN_NO_ERROR;
+}
+

Propchange: subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c
            ('svn:eol-style' removed)

Modified: subversion/branches/svn-auth-x509/subversion/libsvn_wc/adm_crawler.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_wc/adm_crawler.c?rev=1617225&r1=1617224&r2=1617225&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_wc/adm_crawler.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_wc/adm_crawler.c Mon Aug 11 08:54:38 2014
@@ -1083,8 +1083,10 @@ svn_wc__internal_transmit_text_deltas(co
       /* ### Why '..._display()'?  expected_md5_checksum should never be all-
        * zero, but if it is, we would want to pass NULL not an all-zero
        * digest to apply_textdelta(), wouldn't we? */
-      base_digest_hex = svn_checksum_to_cstring_display(expected_md5_checksum,
-                                                        scratch_pool);
+      base_digest_hex =
+          svn_checksum_to_cstring_display2(expected_md5_checksum,
+                                           SVN_CHECKSUM_CSTRING_LOWER,
+                                           scratch_pool);
 
     SVN_ERR(editor->apply_textdelta(file_baton, base_digest_hex, scratch_pool,
                                     &handler, &wh_baton));

Modified: subversion/branches/svn-auth-x509/subversion/libsvn_wc/entries.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_wc/entries.c?rev=1617225&r1=1617224&r2=1617225&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_wc/entries.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_wc/entries.c Mon Aug 11 08:54:38 2014
@@ -2055,10 +2055,14 @@ write_entry(struct write_baton **entry_n
                                                          local_relpath,
                                                          scratch_pool),
                                          scratch_pool),
-                                       svn_checksum_to_cstring_display(
-                                         entry_md5_checksum, scratch_pool),
-                                       svn_checksum_to_cstring_display(
-                                         found_md5_checksum, scratch_pool));
+                                       svn_checksum_to_cstring_display2(
+                                         entry_md5_checksum,
+                                         SVN_CHECKSUM_CSTRING_LOWER,
+                                         scratch_pool),
+                                       svn_checksum_to_cstring_display2(
+                                         found_md5_checksum,
+                                         SVN_CHECKSUM_CSTRING_LOWER,
+                                         scratch_pool));
               else
                 {
                   /* ### Not sure what conditions this should cover. */

Modified: subversion/branches/svn-auth-x509/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_wc/update_editor.c?rev=1617225&r1=1617224&r2=1617225&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_wc/update_editor.c Mon Aug 11 08:54:38 2014
@@ -3703,10 +3703,12 @@ apply_textdelta(void *file_baton,
                        "   expected:  %s\n"
                        "   recorded:  %s\n"),
                      svn_dirent_local_style(fb->local_abspath, pool),
-                     svn_checksum_to_cstring_display(expected_base_checksum,
-                                                     pool),
-                     svn_checksum_to_cstring_display(recorded_base_checksum,
-                                                     pool));
+                     svn_checksum_to_cstring_display2(expected_base_checksum,
+                                                      SVN_CHECKSUM_CSTRING_LOWER,
+                                                      pool),
+                     svn_checksum_to_cstring_display2(recorded_base_checksum,
+                                                      SVN_CHECKSUM_CSTRING_LOWER,
+                                                      pool));
 
   /* Open the text base for reading, unless this is an added file. */
 

Modified: subversion/branches/svn-auth-x509/subversion/libsvn_wc/wc_db_pristine.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_wc/wc_db_pristine.c?rev=1617225&r1=1617224&r2=1617225&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_wc/wc_db_pristine.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_wc/wc_db_pristine.c Mon Aug 11 08:54:38 2014
@@ -127,8 +127,9 @@ svn_wc__db_pristine_get_path(const char 
     return svn_error_createf(SVN_ERR_WC_DB_ERROR, NULL,
                              _("The pristine text with checksum '%s' was "
                                "not found"),
-                             svn_checksum_to_cstring_display(sha1_checksum,
-                                                             scratch_pool));
+                             svn_checksum_to_cstring_display2(sha1_checksum,
+                                                              SVN_CHECKSUM_CSTRING_LOWER,
+                                                              scratch_pool));
 
   SVN_ERR(get_pristine_fname(pristine_abspath, wcroot->abspath,
                              sha1_checksum,
@@ -192,8 +193,9 @@ pristine_read_txn(svn_stream_t **content
     {
       return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
                                _("Pristine text '%s' not present"),
-                               svn_checksum_to_cstring_display(
-                                 sha1_checksum, scratch_pool));
+                               svn_checksum_to_cstring_display2(
+                                 sha1_checksum, SVN_CHECKSUM_CSTRING_LOWER,
+                                 scratch_pool));
     }
 
   /* Open the file as a readable stream.  It will remain readable even when
@@ -318,7 +320,9 @@ pristine_install_txn(svn_sqlite__db_t *s
             return svn_error_createf(
               SVN_ERR_WC_CORRUPT_TEXT_BASE, NULL,
               _("New pristine text '%s' has different size: %ld versus %ld"),
-              svn_checksum_to_cstring_display(sha1_checksum, scratch_pool),
+              svn_checksum_to_cstring_display2(sha1_checksum,
+                                               SVN_CHECKSUM_CSTRING_LOWER,
+                                               scratch_pool),
               (long int)finfo1.size, (long int)finfo2.size);
           }
       }
@@ -466,8 +470,9 @@ svn_wc__db_pristine_get_md5(const svn_ch
     return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt),
                              _("The pristine text with checksum '%s' was "
                                "not found"),
-                             svn_checksum_to_cstring_display(sha1_checksum,
-                                                             scratch_pool));
+                             svn_checksum_to_cstring_display2(sha1_checksum,
+                                                              SVN_CHECKSUM_CSTRING_LOWER,
+                                                              scratch_pool));
 
   SVN_ERR(svn_sqlite__column_checksum(md5_checksum, stmt, 0, result_pool));
   SVN_ERR_ASSERT((*md5_checksum)->kind == svn_checksum_md5);
@@ -505,8 +510,9 @@ svn_wc__db_pristine_get_sha1(const svn_c
     return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt),
                              _("The pristine text with MD5 checksum '%s' was "
                                "not found"),
-                             svn_checksum_to_cstring_display(md5_checksum,
-                                                             scratch_pool));
+                             svn_checksum_to_cstring_display2(md5_checksum,
+                                                              SVN_CHECKSUM_CSTRING_LOWER,
+                                                              scratch_pool));
 
   SVN_ERR(svn_sqlite__column_checksum(sha1_checksum, stmt, 0, result_pool));
   SVN_ERR_ASSERT((*sha1_checksum)->kind == svn_checksum_sha1);

Modified: subversion/branches/svn-auth-x509/subversion/mod_dav_svn/activity.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/mod_dav_svn/activity.c?rev=1617225&r1=1617224&r2=1617225&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/mod_dav_svn/activity.c (original)
+++ subversion/branches/svn-auth-x509/subversion/mod_dav_svn/activity.c Mon Aug 11 08:54:38 2014
@@ -53,7 +53,9 @@ escape_activity(const char *activity_id,
   svn_checksum_t *checksum;
   svn_error_clear(svn_checksum(&checksum, svn_checksum_md5, activity_id,
                                strlen(activity_id), pool));
-  return svn_checksum_to_cstring_display(checksum, pool);
+  return svn_checksum_to_cstring_display2(checksum,
+                                          SVN_CHECKSUM_CSTRING_LOWER,
+                                          pool);
 }
 
 /* Return filename for ACTIVITY_ID under the repository in REPOS. */

Modified: subversion/branches/svn-auth-x509/subversion/svn/auth-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svn/auth-cmd.c?rev=1617225&r1=1617224&r2=1617225&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/svn/auth-cmd.c (original)
+++ subversion/branches/svn-auth-x509/subversion/svn/auth-cmd.c Mon Aug 11 08:54:38 2014
@@ -193,8 +193,10 @@ show_cert(const svn_string_t *pem_cert, 
   SVN_ERR(svn_cmdline_printf(scratch_pool, _("Issuer: %s\n"),
                              svn_x509_certinfo_get_issuer(certinfo)));
   SVN_ERR(svn_cmdline_printf(scratch_pool, _("Fingerprint: %s\n"),
-                             svn_x509_fingerprint_to_display(
+                             svn_checksum_to_cstring_display2(
                                  svn_x509_certinfo_get_digest(certinfo),
+                                 SVN_CHECKSUM_CSTRING_UPPER |
+                                 SVN_CHECKSUM_CSTRING_COLONS,
                                  scratch_pool)));
 
   hostnames = svn_x509_certinfo_get_hostnames(certinfo);

Modified: subversion/branches/svn-auth-x509/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svnserve/serve.c?rev=1617225&r1=1617224&r2=1617225&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/svnserve/serve.c (original)
+++ subversion/branches/svn-auth-x509/subversion/svnserve/serve.c Mon Aug 11 08:54:38 2014
@@ -1562,7 +1562,9 @@ static svn_error_t *get_file(svn_ra_svn_
   SVN_CMD_ERR(svn_fs_revision_root(&root, b->repository->fs, rev, pool));
   SVN_CMD_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5, root,
                                    full_path, TRUE, pool));
-  hex_digest = svn_checksum_to_cstring_display(checksum, pool);
+  hex_digest = svn_checksum_to_cstring_display2(checksum,
+                                                SVN_CHECKSUM_CSTRING_LOWER,
+                                                pool);
 
   /* Fetch the file's explicit and/or inherited properties if
      requested.  Although the wants-iprops boolean was added to the

Modified: subversion/branches/svn-auth-x509/subversion/tests/libsvn_subr/checksum-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/tests/libsvn_subr/checksum-test.c?rev=1617225&r1=1617224&r2=1617225&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/tests/libsvn_subr/checksum-test.c (original)
+++ subversion/branches/svn-auth-x509/subversion/tests/libsvn_subr/checksum-test.c Mon Aug 11 08:54:38 2014
@@ -45,7 +45,9 @@ checksum_parse_kind(const char *digest,
   svn_checksum_t *checksum;
 
   SVN_ERR(svn_checksum_parse_hex(&checksum, kind, digest, pool));
-  checksum_display = svn_checksum_to_cstring_display(checksum, pool);
+  checksum_display = svn_checksum_to_cstring_display2(checksum,
+                                                      SVN_CHECKSUM_CSTRING_LOWER,
+                                                      pool);
 
   if (strcmp(checksum_display, digest) != 0)
     return svn_error_createf

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=1617225&r1=1617224&r2=1617225&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 Mon Aug 11 08:54:38 2014
@@ -474,8 +474,10 @@ compare_results(struct x509_test *xt,
                             xt->subject,
                             pool));
 
-  v = svn_checksum_to_cstring_display(
-      svn_x509_certinfo_get_digest(certinfo), pool);
+  v = svn_checksum_to_cstring_display2(
+          svn_x509_certinfo_get_digest(certinfo),
+          SVN_CHECKSUM_CSTRING_LOWER,
+          pool);
   if (!v)
     return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
                              "No SHA1 digest for cert '%s'", xt->subject);
@@ -515,27 +517,7 @@ test_x509_parse_cert(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-test_svn_x509_fingerprint_to_display(apr_pool_t *pool)
-{
-  svn_checksum_t *md5_fingerprint;
-  svn_checksum_t *sha1_fingerprint;
-
-  SVN_ERR(svn_checksum_parse_hex(&md5_fingerprint, svn_checksum_md5,
-                                 "8518b76f7a45fe4de2d0955085b41f98", pool));
-  SVN_ERR(svn_checksum_parse_hex(&sha1_fingerprint, svn_checksum_sha1,
-                                 "74d82379bcc6771454377db03b912c2b62704139", pool));
-
-  SVN_TEST_STRING_ASSERT(
-    svn_x509_fingerprint_to_display(md5_fingerprint, pool),
-    "85:18:B7:6F:7A:45:FE:4D:E2:D0:95:50:85:B4:1F:98");
-
-  SVN_TEST_STRING_ASSERT(
-    svn_x509_fingerprint_to_display(sha1_fingerprint, pool),
-    "74:D8:23:79:BC:C6:77:14:54:37:7D:B0:3B:91:2C:2B:62:70:41:39");
-
-  return SVN_NO_ERROR;
-}
+
 /* The test table.  */
 
 static int max_threads = 1;
@@ -545,8 +527,6 @@ static struct svn_test_descriptor_t test
     SVN_TEST_NULL,
     SVN_TEST_PASS2(test_x509_parse_cert,
                    "test svn_x509_parse_cert"),
-    SVN_TEST_PASS2(test_svn_x509_fingerprint_to_display,
-                   "test svn_x509_fingerprint_to_display"),
     SVN_TEST_NULL
   };
 

Propchange: subversion/branches/svn-auth-x509/subversion/tests/libsvn_subr/x509-test.c
            ('svn:eol-style' removed)



Mime
View raw message