You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by sv...@apache.org on 2014/02/05 05:05:22 UTC

svn commit: r1564623 - in /subversion/branches/1.8.x: ./ STATUS subversion/include/private/svn_auth_private.h subversion/libsvn_ra_serf/util.c subversion/libsvn_subr/auth.c subversion/libsvn_subr/cmdline.c subversion/libsvn_subr/win32_crypto.c

Author: svn-role
Date: Wed Feb  5 04:05:22 2014
New Revision: 1564623

URL: http://svn.apache.org/r1564623
Log:
Merge the r1534149 group from trunk:

 * r1534149, r1535676
   In the windows CryptoAPI ssl certificate verification, properly handle
   certificates that are only trusted via intermediate authorities.
   Justification:
      While not strictly a bug, intermediate authorities are getting more
      common since recent Certificate Authority incidents.
   Notes:
      rhuijben: This introduces a new credential type as private API.
      Not sure about our strict ABI guarantees here, but this affects
      usability of users migrating to cloud platforms, etc.
   Votes:
     +1: rhuijben, steveking, breser

Modified:
    subversion/branches/1.8.x/   (props changed)
    subversion/branches/1.8.x/STATUS
    subversion/branches/1.8.x/subversion/include/private/svn_auth_private.h
    subversion/branches/1.8.x/subversion/libsvn_ra_serf/util.c
    subversion/branches/1.8.x/subversion/libsvn_subr/auth.c
    subversion/branches/1.8.x/subversion/libsvn_subr/cmdline.c
    subversion/branches/1.8.x/subversion/libsvn_subr/win32_crypto.c

Propchange: subversion/branches/1.8.x/
------------------------------------------------------------------------------
  Merged /subversion/trunk:r1534149,1535676

Modified: subversion/branches/1.8.x/STATUS
URL: http://svn.apache.org/viewvc/subversion/branches/1.8.x/STATUS?rev=1564623&r1=1564622&r2=1564623&view=diff
==============================================================================
--- subversion/branches/1.8.x/STATUS (original)
+++ subversion/branches/1.8.x/STATUS Wed Feb  5 04:05:22 2014
@@ -249,16 +249,3 @@ Veto-blocked changes:
 
 Approved changes:
 =================
-
- * r1534149, r1535676
-   In the windows CryptoAPI ssl certificate verification, properly handle
-   certificates that are only trusted via intermediate authorities.
-   Justification:
-      While not strictly a bug, intermediate authorities are getting more
-      common since recent Certificate Authority incidents.
-   Notes:
-      rhuijben: This introduces a new credential type as private API.
-      Not sure about our strict ABI guarantees here, but this affects
-      usability of users migrating to cloud platforms, etc.
-   Votes:
-     +1: rhuijben, steveking, breser

Modified: subversion/branches/1.8.x/subversion/include/private/svn_auth_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.8.x/subversion/include/private/svn_auth_private.h?rev=1564623&r1=1564622&r2=1564623&view=diff
==============================================================================
--- subversion/branches/1.8.x/subversion/include/private/svn_auth_private.h (original)
+++ subversion/branches/1.8.x/subversion/include/private/svn_auth_private.h Wed Feb  5 04:05:22 2014
@@ -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/branches/1.8.x/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.8.x/subversion/libsvn_ra_serf/util.c?rev=1564623&r1=1564622&r2=1564623&view=diff
==============================================================================
--- subversion/branches/1.8.x/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/1.8.x/subversion/libsvn_ra_serf/util.c Wed Feb  5 04:05:22 2014
@@ -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"
 
@@ -269,26 +270,70 @@ ssl_server_cert(void *baton, int failure
   svn_auth_iterstate_t *state;
   const char *realmstring;
   apr_uint32_t svn_failures;
-  apr_hash_t *issuer, *subject, *serf_cert;
-  apr_array_header_t *san;
+  apr_hash_t *issuer;
+  apr_hash_t *subject = NULL;
+  apr_hash_t *serf_cert = NULL;
   void *creds;
   int found_matching_hostname = 0;
 
-  /* Implicitly approve any non-server certs. */
-  if (serf_ssl_cert_depth(cert) > 0)
+  svn_failures = (ssl_convert_serf_failures(failures)
+      | conn->server_cert_failures);
+
+  if (serf_ssl_cert_depth(cert) == 0)
     {
-      if (failures)
-        conn->server_cert_failures |= ssl_convert_serf_failures(failures);
-      return APR_SUCCESS;
+      /* If the depth is 0, the hostname must match the certificate.
+
+      ### This should really be handled by serf, which should pass an error
+          for this case, but that has backwards compatibility issues. */
+      apr_array_header_t *san;
+
+      serf_cert = serf_ssl_cert_certificate(cert, scratch_pool);
+
+      san = svn_hash_gets(serf_cert, "subjectAltName");
+      /* Try to find matching server name via subjectAltName first... */
+      if (san) {
+          int i;
+          for (i = 0; i < san->nelts; i++) {
+              const char *s = APR_ARRAY_IDX(san, i, const char*);
+              if (apr_fnmatch(s, conn->session->session_url.hostname,
+                  APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_SUCCESS)
+              {
+                  found_matching_hostname = 1;
+                  break;
+              }
+          }
+      }
+
+      /* Match server certificate CN with the hostname of the server */
+      if (!found_matching_hostname)
+        {
+          const char *hostname = NULL;
+
+          subject = serf_ssl_cert_subject(cert, scratch_pool);
+
+          if (subject)
+            hostname = svn_hash_gets(subject, "CN");
+
+          if (!hostname
+              || apr_fnmatch(hostname, conn->session->session_url.hostname,
+                             APR_FNM_PERIOD | APR_FNM_CASE_BLIND) != APR_SUCCESS)
+          {
+              svn_failures |= SVN_AUTH_SSL_CNMISMATCH;
+          }
+      }
     }
 
+  if (!svn_failures)
+    return SVN_NO_ERROR;
+
   /* Extract the info from the certificate */
-  subject = serf_ssl_cert_subject(cert, scratch_pool);
+  if (! subject)
+    subject = serf_ssl_cert_subject(cert, scratch_pool);
   issuer = serf_ssl_cert_issuer(cert, scratch_pool);
-  serf_cert = serf_ssl_cert_certificate(cert, scratch_pool);
+  if (! serf_cert)
+    serf_cert = serf_ssl_cert_certificate(cert, scratch_pool);
 
   cert_info.hostname = svn_hash_gets(subject, "CN");
-  san = svn_hash_gets(serf_cert, "subjectAltName");
   cert_info.fingerprint = svn_hash_gets(serf_cert, "sha1");
   if (! cert_info.fingerprint)
     cert_info.fingerprint = apr_pstrdup(scratch_pool, "<unknown>");
@@ -301,32 +346,56 @@ ssl_server_cert(void *baton, int failure
   cert_info.issuer_dname = convert_organisation_to_str(issuer, scratch_pool);
   cert_info.ascii_cert = serf_ssl_cert_export(cert, scratch_pool);
 
-  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;
 
-  /* Try to find matching server name via subjectAltName first... */
-  if (san) {
-      int i;
-      for (i = 0; i < san->nelts; i++) {
-          char *s = APR_ARRAY_IDX(san, i, char*);
-          if (apr_fnmatch(s, conn->session->session_url.hostname,
-                          APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_SUCCESS)
-            {
-              found_matching_hostname = 1;
-              cert_info.hostname = s;
-              break;
-            }
-      }
-  }
+      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);
 
-  /* Match server certificate CN with the hostname of the server */
-  if (!found_matching_hostname && cert_info.hostname)
-    {
-      if (apr_fnmatch(cert_info.hostname, conn->session->session_url.hostname,
-                      APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_FNM_NOMATCH)
+      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)
         {
-          svn_failures |= SVN_AUTH_SSL_CNMISMATCH;
+          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;
     }
 
   svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,

Modified: subversion/branches/1.8.x/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.8.x/subversion/libsvn_subr/auth.c?rev=1564623&r1=1564622&r2=1564623&view=diff
==============================================================================
--- subversion/branches/1.8.x/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/1.8.x/subversion/libsvn_subr/auth.c Wed Feb  5 04:05:22 2014
@@ -35,6 +35,7 @@
 #include "svn_private_config.h"
 #include "svn_dso.h"
 #include "svn_version.h"
+#include "private/svn_auth_private.h"
 #include "private/svn_dep_compat.h"
 #include "private/svn_subr_private.h"
 
@@ -540,6 +541,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/branches/1.8.x/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.8.x/subversion/libsvn_subr/cmdline.c?rev=1564623&r1=1564622&r2=1564623&view=diff
==============================================================================
--- subversion/branches/1.8.x/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/1.8.x/subversion/libsvn_subr/cmdline.c Wed Feb  5 04:05:22 2014
@@ -505,7 +505,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",
@@ -514,6 +514,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/branches/1.8.x/subversion/libsvn_subr/win32_crypto.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.8.x/subversion/libsvn_subr/win32_crypto.c?rev=1564623&r1=1564622&r2=1564623&view=diff
==============================================================================
--- subversion/branches/1.8.x/subversion/libsvn_subr/win32_crypto.c (original)
+++ subversion/branches/1.8.x/subversion/libsvn_subr/win32_crypto.c Wed Feb  5 04:05:22 2014
@@ -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 */