You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2013/10/21 15:37:15 UTC

svn commit: r1534149 - in /subversion/trunk/subversion: include/private/svn_auth_private.h libsvn_ra_serf/util.c libsvn_subr/auth.c libsvn_subr/cmdline.c libsvn_subr/win32_crypto.c

Author: rhuijben
Date: Mon Oct 21 13:37:14 2013
New Revision: 1534149

URL: http://svn.apache.org/r1534149
Log:
Extend the Windows CRYPTOAPI based ssl certificate verification to properly
handle intermediate authorities, like how webbrowsers handle this.

When I originally implemented the ssl server certificate verification, most
certificates were directly signed by the root authority while since then
most certificates moved to using short lived intermediate authorities.

This re-enables common cases like
$ svn info https://svn.apache.org/repos/asf/
to work directly on Windows, without an initial prompt for accepting a
certificate from an unknown authority, just like it worked a few years ago.

* subversion/include/private/svn_auth_private.h
  (SVN_AUTH_CRED_SSL_SERVER_AUTHORITY): Declare new credential type.
  (svn_auth__get_windows_ssl_server_authority_provider): New function.

* subversion/libsvn_ra_serf/util.c
  (includes): Add svn_auth_private.h.
  (ssl_server_cert): Instead of just recording authority failures call a
    new (optional) provider to allow

* subversion/libsvn_subr/auth.c
  (includes): Add svn_auth_private.h.
  (svn_auth_get_platform_specific_provider): Allow loading new provider.

* subversion/libsvn_subr/cmdline.c
  (svn_cmdline_create_auth_baton): Hook new provider in the same place as
    where we hook the server certificate provider.

* subversion/libsvn_subr/win32_crypto.c
  (windows_ssl_server_trust_first_credentials): Fix an old bug, where instead
    of properly accepting a failure, we removed the failure where it was
    originally stored. (This happened to work in serf an neon for years)

  (windows_server_authority_provider): New variable.
  (svn_auth__get_windows_ssl_server_authority_provider): New function.

Modified:
    subversion/trunk/subversion/include/private/svn_auth_private.h
    subversion/trunk/subversion/libsvn_ra_serf/util.c
    subversion/trunk/subversion/libsvn_subr/auth.c
    subversion/trunk/subversion/libsvn_subr/cmdline.c
    subversion/trunk/subversion/libsvn_subr/win32_crypto.c

Modified: subversion/trunk/subversion/include/private/svn_auth_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_auth_private.h?rev=1534149&r1=1534148&r2=1534149&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_auth_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_auth_private.h Mon Oct 21 13:37:14 2013
@@ -37,6 +37,24 @@
 extern "C" {
 #endif /* __cplusplus */
 
+/** SSL server authority verification credential type.
+ *
+ * The followin auth parameters are available to the providers:
+ *
+ * - @c SVN_AUTH_PARAM_SSL_SERVER_FAILURES (@c apr_uint32_t*)
+ * - @c SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO
+ *      (@c svn_auth_ssl_server_cert_info_t*)
+ *
+ * The following optional auth parameters are relevant to the providers:
+ *
+ * - @c SVN_AUTH_PARAM_NO_AUTH_CACHE (@c void*)
+ *
+ * @since New in 1.9.
+ */
+#define SVN_AUTH_CRED_SSL_SERVER_AUTHORITY "svn.ssl.server.authority"
+
+
+
 /* If you add a password type for a provider which stores
  * passwords on disk in encrypted form, remember to update
  * svn_auth__simple_save_creds_helper. Otherwise it will be
@@ -213,6 +231,25 @@ svn_auth__ssl_client_cert_pw_set(svn_boo
                                  svn_boolean_t non_interactive,
                                  apr_pool_t *pool);
 
+#if (defined(WIN32) && !defined(__MINGW32__)) || defined(DOXYGEN)
+/**
+ * Set @a *provider to an authentication provider that implements
+ * ssl authority verification via the Windows CryptoApi.
+ *
+ * This provider automatically validates authority certificates with
+ * the CryptoApi, like Internet Explorer and the Windows network API do.
+ * This allows the rollout of root certificates via Windows Domain
+ * policies, instead of Subversion specific configuration.
+ *
+ * @note This function is only available on Windows.
+ */
+void
+svn_auth__get_windows_ssl_server_authority_provider(
+                            svn_auth_provider_object_t **provider,
+                            apr_pool_t *pool);
+#endif
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/trunk/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/util.c?rev=1534149&r1=1534148&r2=1534149&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/util.c Mon Oct 21 13:37:14 2013
@@ -48,6 +48,7 @@
 #include "private/svn_dep_compat.h"
 #include "private/svn_fspath.h"
 #include "private/svn_subr_private.h"
+#include "private/svn_auth_private.h"
 
 #include "ra_serf.h"
 
@@ -275,13 +276,8 @@ ssl_server_cert(void *baton, int failure
   void *creds;
   int found_matching_hostname = 0;
 
-  /* Implicitly approve any non-server certs. */
-  if (serf_ssl_cert_depth(cert) > 0)
-    {
-      if (failures)
-        conn->server_cert_failures |= ssl_convert_serf_failures(failures);
-      return APR_SUCCESS;
-    }
+  if (!failures && ! conn->server_cert_failures)
+    return SVN_NO_ERROR;
 
   /* Extract the info from the certificate */
   subject = serf_ssl_cert_subject(cert, scratch_pool);
@@ -305,6 +301,58 @@ ssl_server_cert(void *baton, int failure
   svn_failures = (ssl_convert_serf_failures(failures)
                   | conn->server_cert_failures);
 
+  /* Handle any non-server certs. */
+  if (serf_ssl_cert_depth(cert) > 0)
+    {
+      svn_error_t *err;
+
+      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+                             SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO,
+                             &cert_info);
+
+      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+                             SVN_AUTH_PARAM_SSL_SERVER_FAILURES,
+                             &svn_failures);
+
+      realmstring = apr_psprintf(scratch_pool, "AUTHORITY:%s",
+                                 cert_info.fingerprint);
+
+      err = svn_auth_first_credentials(&creds, &state,
+                                       SVN_AUTH_CRED_SSL_SERVER_AUTHORITY,
+                                       realmstring,
+                                       conn->session->wc_callbacks->auth_baton,
+                                       scratch_pool);
+
+      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+                             SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
+
+      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+                             SVN_AUTH_PARAM_SSL_SERVER_FAILURES, NULL);
+
+      if (err)
+        {
+          if (err->apr_err != SVN_ERR_AUTHN_NO_PROVIDER)
+            return svn_error_trace(err);
+
+          /* No provider registered that handles server authorities */
+          svn_error_clear(err);
+          creds = NULL;
+        }
+
+      if (creds)
+        {
+          server_creds = creds;
+          SVN_ERR(svn_auth_save_credentials(state, scratch_pool));
+
+          svn_failures &= ~server_creds->accepted_failures;
+        }
+
+      if (svn_failures)
+        conn->server_cert_failures |= svn_failures;
+
+      return APR_SUCCESS;
+    }
+
   /* Try to find matching server name via subjectAltName first... */
   if (san) {
       int i;

Modified: subversion/trunk/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/auth.c?rev=1534149&r1=1534148&r2=1534149&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/auth.c (original)
+++ subversion/trunk/subversion/libsvn_subr/auth.c Mon Oct 21 13:37:14 2013
@@ -35,6 +35,7 @@
 #include "svn_config.h"
 #include "svn_dso.h"
 #include "svn_version.h"
+#include "private/svn_auth_private.h"
 #include "private/svn_dep_compat.h"
 
 #include "auth.h"
@@ -542,6 +543,11 @@ svn_auth_get_platform_specific_provider(
         {
           svn_auth_get_windows_ssl_server_trust_provider(provider, pool);
         }
+      else if (strcmp(provider_name, "windows") == 0 &&
+          strcmp(provider_type, "ssl_server_authority") == 0)
+        {
+          svn_auth__get_windows_ssl_server_authority_provider(provider, pool);
+        }
 #endif
     }
 

Modified: subversion/trunk/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/cmdline.c?rev=1534149&r1=1534148&r2=1534149&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/trunk/subversion/libsvn_subr/cmdline.c Mon Oct 21 13:37:14 2013
@@ -591,7 +591,7 @@ svn_cmdline_create_auth_baton(svn_auth_b
   svn_auth_get_username_provider(&provider, pool);
   APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
 
-  /* The server-cert, client-cert, and client-cert-password providers. */
+  /* The windows ssl server certificate CRYPTOAPI provider. */
   SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
                                                   "windows",
                                                   "ssl_server_trust",
@@ -600,6 +600,15 @@ svn_cmdline_create_auth_baton(svn_auth_b
   if (provider)
     APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
 
+  /* The windows ssl authority certificate CRYPTOAPI provider. */
+  SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
+                                                  "windows",
+                                                  "ssl_server_authority",
+                                                  pool));
+
+  if (provider)
+    APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
+
   svn_auth_get_ssl_server_trust_file_provider(&provider, pool);
   APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
   svn_auth_get_ssl_client_cert_file_provider(&provider, pool);

Modified: subversion/trunk/subversion/libsvn_subr/win32_crypto.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/win32_crypto.c?rev=1534149&r1=1534148&r2=1534149&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/win32_crypto.c (original)
+++ subversion/trunk/subversion/libsvn_subr/win32_crypto.c Mon Oct 21 13:37:14 2013
@@ -436,8 +436,9 @@ windows_ssl_server_trust_first_credentia
                                            const char *realmstring,
                                            apr_pool_t *pool)
 {
-  apr_uint32_t *failures = svn_hash_gets(parameters,
-                                         SVN_AUTH_PARAM_SSL_SERVER_FAILURES);
+  apr_uint32_t *failure_ptr = svn_hash_gets(parameters,
+                                            SVN_AUTH_PARAM_SSL_SERVER_FAILURES);
+  apr_uint32_t failures = *failure_ptr;
   const svn_auth_ssl_server_cert_info_t *cert_info =
     svn_hash_gets(parameters, SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO);
 
@@ -445,7 +446,7 @@ windows_ssl_server_trust_first_credentia
   *iter_baton = NULL;
 
   /* We can accept only unknown certificate authority. */
-  if (*failures & SVN_AUTH_SSL_UNKNOWNCA)
+  if (failures & SVN_AUTH_SSL_UNKNOWNCA)
     {
       svn_boolean_t ok;
 
@@ -455,15 +456,16 @@ windows_ssl_server_trust_first_credentia
       if (ok)
         {
           /* Clear failure flag. */
-          *failures &= ~SVN_AUTH_SSL_UNKNOWNCA;
+          failures &= ~SVN_AUTH_SSL_UNKNOWNCA;
         }
     }
 
   /* If all failures are cleared now, we return the creds */
-  if (! *failures)
+  if (! failures)
     {
       svn_auth_cred_ssl_server_trust_t *creds =
         apr_pcalloc(pool, sizeof(*creds));
+      creds->accepted_failures = *failure_ptr & ~failures;
       creds->may_save = FALSE; /* No need to save it. */
       *credentials = creds;
     }
@@ -489,4 +491,24 @@ svn_auth_get_windows_ssl_server_trust_pr
   *provider = po;
 }
 
+static const svn_auth_provider_t windows_server_authority_provider = {
+    SVN_AUTH_CRED_SSL_SERVER_AUTHORITY,
+    windows_ssl_server_trust_first_credentials,
+    NULL,
+    NULL,
+};
+
+/* Public API */
+void
+svn_auth__get_windows_ssl_server_authority_provider(
+                            svn_auth_provider_object_t **provider,
+                            apr_pool_t *pool)
+{
+    svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
+
+    po->vtable = &windows_server_authority_provider;
+    *provider = po;
+}
+
+
 #endif /* WIN32 */