Here's a rough patch that makes svnauth show SSL certs as a list
of fields, rather than a long base64 string.

I'm adding a dependency on OpenSSL for certificate parsing.
I hope this is fine. If OpenSSL is not available svnauth falls
back to printing the base64 encoded form of the certificate.

Since I'm tweaking the build system, it would be nice if someone
could check whether this breaks the Windows build, or the build on
other *nix platforms. And if it does, help me with fixing my patch.

Thanks!

Index: Makefile.in
===================================================================
--- Makefile.in (revision 1501587)
+++ Makefile.in (working copy)
@@ -48,6 +48,7 @@ SVN_GPG_AGENT_LIBS = @SVN_GPG_AGENT_LIBS@
 SVN_GNOME_KEYRING_LIBS = @SVN_GNOME_KEYRING_LIBS@
 SVN_KWALLET_LIBS = @SVN_KWALLET_LIBS@
 SVN_MAGIC_LIBS = @SVN_MAGIC_LIBS@
+SVN_OPENSSL_LIBS = @SVN_OPENSSL_LIBS@
 SVN_SASL_LIBS = @SVN_SASL_LIBS@
 SVN_SERF_LIBS = @SVN_SERF_LIBS@
 SVN_SQLITE_LIBS = @SVN_SQLITE_LIBS@
@@ -123,7 +124,7 @@ LT_CXX_LIBADD = @LT_CXX_LIBADD@
 INCLUDES = -I$(top_srcdir)/subversion/include -I$(top_builddir)/subversion \
            @SVN_APR_INCLUDES@ @SVN_APRUTIL_INCLUDES@ 
@SVN_APR_MEMCACHE_INCLUDES@ \
            @SVN_DB_INCLUDES@ @SVN_GNOME_KEYRING_INCLUDES@ \
-           @SVN_KWALLET_INCLUDES@ @SVN_MAGIC_INCLUDES@ \
+           @SVN_KWALLET_INCLUDES@ @SVN_MAGIC_INCLUDES@ @SVN_OPENSSL_INCLUDES@ \
            @SVN_SASL_INCLUDES@ @SVN_SERF_INCLUDES@ @SVN_SQLITE_INCLUDES@ \
            @SVN_XML_INCLUDES@ @SVN_ZLIB_INCLUDES@
 
Index: aclocal.m4
===================================================================
--- aclocal.m4  (revision 1501587)
+++ aclocal.m4  (working copy)
@@ -39,6 +39,7 @@ sinclude(build/ac-macros/berkeley-db.m4)
 sinclude(build/ac-macros/compiler.m4)
 sinclude(build/ac-macros/ctypesgen.m4)
 sinclude(build/ac-macros/java.m4)
+sinclude(build/ac-macros/openssl.m4)
 sinclude(build/ac-macros/sasl.m4)
 sinclude(build/ac-macros/serf.m4)
 sinclude(build/ac-macros/sqlite.m4)
Index: build/ac-macros/openssl.m4
===================================================================
--- build/ac-macros/openssl.m4  (revision 0)
+++ build/ac-macros/openssl.m4  (working copy)
@@ -0,0 +1,106 @@
+dnl ===================================================================
+dnl   Licensed to the Apache Software Foundation (ASF) under one
+dnl   or more contributor license agreements.  See the NOTICE file
+dnl   distributed with this work for additional information
+dnl   regarding copyright ownership.  The ASF licenses this file
+dnl   to you under the Apache License, Version 2.0 (the
+dnl   "License"); you may not use this file except in compliance
+dnl   with the License.  You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl   Unless required by applicable law or agreed to in writing,
+dnl   software distributed under the License is distributed on an
+dnl   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+dnl   KIND, either express or implied.  See the License for the
+dnl   specific language governing permissions and limitations
+dnl   under the License.
+dnl ===================================================================
+dnl
+dnl  SVN_LIB_OPENSSL
+dnl
+dnl  Check configure options and assign variables related to
+dnl  the OpenSSL library.
+dnl
+dnl  If we find the library, set the shell variable
+dnl  `svn_lib_openssl' to `yes'.  Otherwise, set `svn_lib_openssl'
+dnl  to `no'.
+
+AC_DEFUN(SVN_LIB_OPENSSL,
+[
+  AC_ARG_WITH(openssl, [AS_HELP_STRING([--with-openssl=PATH],
+                                       [Compile with OpenSSL in PATH])],
+  [
+    with_openssl="$withval"
+    required="yes"
+  ],
+  [
+    with_openssl="yes"
+    required="no"
+  ])
+
+  AC_MSG_CHECKING([whether to look for OpenSSL])
+
+  if test "${with_openssl}" = "no"; then
+    AC_MSG_RESULT([no])
+    svn_lib_openssl=no
+  else
+    AC_MSG_RESULT([yes])
+    saved_LDFLAGS="$LDFLAGS"
+    saved_CPPFLAGS="$CPPFLAGS"
+
+    if test "$with_openssl" = "yes"; then
+      AC_MSG_NOTICE([Looking in default locations])
+      AC_CHECK_HEADER(openssl/ssl.h,
+       [AC_CHECK_LIB(crypto, d2i_X509,
+         [AC_CHECK_LIB(ssl, SSL_library_init, 
+                       svn_lib_openssl=yes,
+                       svn_lib_openssl=no,
+                       -lcrypto)],
+         svn_lib_openssl=no)],
+       svn_lib_openssl=no)
+      if test "$svn_lib_openssl" = "no"; then
+        with_openssl="/usr/local"
+      fi
+    else
+      svn_lib_openssl=no
+    fi
+
+    if test "$svn_lib_openssl" = "no"; then
+      SVN_OPENSSL_INCLUDES="-I${with_openssl}/include"
+      CPPFLAGS="$CPPFLAGS $SVN_OPENSSL_INCLUDES"
+      LDFLAGS="$LDFLAGS `SVN_REMOVE_STANDARD_LIB_DIRS(-L${with_openssl}/lib)`"
+
+      AC_CHECK_HEADER(openssl/ssl.h,
+       [AC_CHECK_LIB(crypto, d2i_X509,
+         [AC_CHECK_LIB(ssl, SSL_library_init, 
+                       svn_lib_openssl=yes,
+                       svn_lib_openssl=no,
+                       -lcrypto)],
+         svn_lib_openssl=no)],
+       svn_lib_openssl=no)
+    fi
+
+    AC_MSG_CHECKING([for availability of OpenSSL])
+    if test "$svn_lib_openssl" = "yes"; then
+      SVN_OPENSSL_LIBS="-lcrypto -lssl"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+
+      if test "$required" = "yes"; then
+        dnl The user explicitly requested OpenSSL, but we couldn't find it.
+        dnl Exit with an error message.
+        AC_MSG_ERROR([Could not find OpenSSL])
+      fi
+      
+      SVN_OPENSSL_INCLUDES=""
+      LDFLAGS="$saved_LDFLAGS"
+    fi
+
+    CPPFLAGS="$saved_CPPFLAGS"
+  fi
+    
+  AC_SUBST(SVN_OPENSSL_INCLUDES)
+  AC_SUBST(SVN_OPENSSL_LIBS)
+])

Property changes on: build/ac-macros/openssl.m4
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: build.conf
===================================================================
--- build.conf  (revision 1501587)
+++ build.conf  (working copy)
@@ -202,7 +202,7 @@ manpages = subversion/svnmucc/svnmucc.1
 description = Subversion Authentication Credentials Management Tool
 type = exe
 path = subversion/svnauth
-libs = libsvn_subr apriconv apr
+libs = libsvn_subr apriconv apr openssl
 install = bin
 manpages = subversion/svnauth/svnauth.1
 
@@ -1193,6 +1193,10 @@ external-lib = $(SVN_KWALLET_LIBS)
 type = lib
 external-lib = $(SVN_MAGIC_LIBS)
 
+[openssl]
+type = lib
+external-lib = $(SVN_OPENSSL_LIBS)
+
 [sasl]
 type = lib
 external-lib = $(SVN_SASL_LIBS)
Index: configure.ac
===================================================================
--- configure.ac        (revision 1501587)
+++ configure.ac        (working copy)
@@ -482,6 +482,14 @@ if test "$svn_lib_sasl" = "yes"; then
             [Defined if Cyrus SASL v2 is present on the system])
 fi
 
+SVN_LIB_OPENSSL
+
+if test "$svn_lib_openssl" = "yes"; then
+  AC_DEFINE(SVN_HAVE_OPENSSL, 1,
+            [Defined if OpenSSL is present on the system])
+fi
+
+
 dnl Mac OS specific features -------------------
 
 SVN_LIB_MACHO_ITERATE
Index: subversion/svnauth/svnauth.c
===================================================================
--- subversion/svnauth/svnauth.c        (revision 1501587)
+++ subversion/svnauth/svnauth.c        (working copy)
@@ -27,6 +27,13 @@
 #include <apr_getopt.h>
 #include <apr_tables.h>
 
+#include "svn_private_config.h"
+
+#ifdef SVN_HAVE_OPENSSL
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+#endif
+
 #include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_opt.h"
@@ -39,7 +46,6 @@
 
 #include "private/svn_cmdline_private.h"
 
-#include "svn_private_config.h"
 
 /* Baton for passing option/argument state to a subcommand function. */
 struct svnauth_opt_state
@@ -157,6 +163,145 @@ subcommand_help(apr_getopt_t *os, void *baton, apr
 #define SEP_STRING \
   "------------------------------------------------------------------------\n"
 
+/* ### from libsvn_subr/ssl_server_trust_providers.c */
+#define AUTHN_ASCII_CERT_KEY            "ascii_cert"
+
+#ifdef SVN_HAVE_OPENSSL
+static apr_hash_t *
+get_cert_info_from_x509_name(X509_NAME *name,
+                             apr_pool_t *result_pool)
+{
+  char buf[1024];
+  apr_hash_t *cert_info = apr_hash_make(result_pool);
+
+  if (X509_NAME_get_text_by_NID(name, NID_commonName, buf, 1024) != -1)
+    apr_hash_set(cert_info, _("Common Name"), APR_HASH_KEY_STRING,
+                 apr_pstrdup(result_pool, buf));
+
+  if (X509_NAME_get_text_by_NID(name, NID_pkcs9_emailAddress, buf, 1024) != -1)
+    apr_hash_set(cert_info, _("Email Address"), APR_HASH_KEY_STRING,
+                 apr_pstrdup(result_pool, buf));
+    
+  if (X509_NAME_get_text_by_NID(name, NID_organizationName, buf, 1024) != -1)
+    apr_hash_set(cert_info, _("Organization"), APR_HASH_KEY_STRING,
+                 apr_pstrdup(result_pool, buf));
+
+  if (X509_NAME_get_text_by_NID(name, NID_localityName, buf, 1024) != -1)
+    apr_hash_set(cert_info, _("Locality"), APR_HASH_KEY_STRING,
+                 apr_pstrdup(result_pool, buf));
+
+  if (X509_NAME_get_text_by_NID(name, NID_stateOrProvinceName, buf, 1024) != 
-1)
+    apr_hash_set(cert_info, _("State or Province"), APR_HASH_KEY_STRING,
+                 apr_pstrdup(result_pool, buf));
+
+  if (X509_NAME_get_text_by_NID(name, NID_countryName, buf, 1024) != -1)
+    apr_hash_set(cert_info, _("Country"), APR_HASH_KEY_STRING,
+                 apr_pstrdup(result_pool, buf));
+
+  return cert_info;
+}
+
+static svn_error_t *
+show_cert_info(apr_hash_t *cert_info,
+               apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *sorted_cert_info;
+  int i;
+
+  sorted_cert_info = svn_sort__hash(cert_info,
+                                    svn_sort_compare_items_lexically,
+                                    scratch_pool);
+  for (i = 0; i < sorted_cert_info->nelts; i++)
+    {
+      svn_sort__item_t item;
+      const char *key;
+      const char *value;
+      
+      item = APR_ARRAY_IDX(sorted_cert_info, i, svn_sort__item_t);
+      key = item.key;
+      value = item.value;
+
+      SVN_ERR(svn_cmdline_printf(scratch_pool, "  %s: %s\n", key, value));
+    }
+
+  return SVN_NO_ERROR;
+}
+#endif /* SVN_HAVE_OPENSSL */
+
+static svn_error_t *
+show_ascii_cert(const char *ascii_cert,
+                apr_pool_t *scratch_pool)
+{
+#ifdef SVN_HAVE_OPENSSL
+  BIO *bmem;
+  BIO *b64;
+  X509 *cert;
+  X509_NAME *name;
+  apr_hash_t *cert_info;
+  unsigned char checksum[EVP_MAX_MD_SIZE];
+  unsigned int checksum_len;
+  unsigned int i;
+
+  /* Construct a BIO chain to decode the base64-encoded ASCII_CERT. */
+  bmem = BIO_new_mem_buf((void*)ascii_cert, -1);
+  b64 = BIO_new(BIO_f_base64());
+  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+  b64 = BIO_push(b64, bmem);
+
+  /* Parse the decoded X509 certificate. */
+  cert = d2i_X509_bio(b64, NULL);
+  if (cert == NULL)
+    {
+      BIO_free_all(b64);
+      SVN_ERR(svn_cmdline_printf(scratch_pool, "%s: %s\n",
+                                 AUTHN_ASCII_CERT_KEY, ascii_cert));
+      return SVN_NO_ERROR;
+    }
+
+  /* Show issuer information. */
+  name = X509_get_issuer_name(cert);
+  if (name)
+    {
+      cert_info = get_cert_info_from_x509_name(name, scratch_pool);
+      if (cert_info && apr_hash_count(cert_info) > 0)
+        {
+          SVN_ERR(svn_cmdline_printf(scratch_pool, _("Certificate 
Issuer:\n")));
+          SVN_ERR(show_cert_info(cert_info, scratch_pool));
+        }
+    }
+
+  /* Show subject information. */
+  name = X509_get_subject_name(cert);
+  if (name)
+    {
+      cert_info = get_cert_info_from_x509_name(name, scratch_pool);
+      if (cert_info && apr_hash_count(cert_info) > 0)
+        {
+          SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                     _("Certificate Subject:\n")));
+          SVN_ERR(show_cert_info(cert_info, scratch_pool));
+      }
+    }
+
+  /* Display SHA1 checksum of certificate. */
+  if (X509_digest(cert, EVP_sha1(), checksum, &checksum_len))
+    {
+      SVN_ERR(svn_cmdline_printf(scratch_pool, _("SHA1 Checksum: ")));
+      for (i = 0; i < checksum_len; i++)
+        SVN_ERR(svn_cmdline_printf(scratch_pool, "%02X%c", checksum[i],
+                                   i < (checksum_len - 1) ? ':' : '\n'));
+    }
+
+  X509_free(cert);
+  BIO_free_all(b64);
+#else
+  SVN_ERR(svn_cmdline_printf(scratch_pool, "%s: %s\n",
+                             AUTHN_ASCII_CERT_KEY, ascii_cert));
+#endif /* SVN_HAVE_OPENSSL */
+
+  return SVN_NO_ERROR;
+}
+                
 /* This implements `svn_config_auth_walk_func_t` */
 static svn_error_t *
 list_credentials(svn_boolean_t *delete_cred,
@@ -193,6 +338,8 @@ list_credentials(svn_boolean_t *delete_cred,
         SVN_ERR(svn_cmdline_printf(scratch_pool, _("%s: [not shown]\n"), key));
       else if (strcmp(value->data, realmstring) == 0)
         continue; /* realm string was already shown above */
+      else if (strcmp(key, AUTHN_ASCII_CERT_KEY) == 0)
+        SVN_ERR(show_ascii_cert(value->data, scratch_pool));
       else
         SVN_ERR(svn_cmdline_printf(scratch_pool, "%s: %s\n", key, 
value->data));
     }

Reply via email to