[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] ra_neon: enable PKCS#11 support for neon 0.28

From: Joe Orton <jorton_at_redhat.com>
Date: Fri, 8 Feb 2008 21:51:00 +0000

To go along with the neon 0.28 patch posted separately; this hooks up
the new interfaces to allow users to configure a PKCS#11 provider from
which an SSL client cert will be drawn, if the server requests one.

This overloads the client_cert_pw auth provider to enter the smartcard
PIN if necessary, which is arguably a bit of a hack since PINs and
passwords are slightly different. I haven't worked out how to hook up
the cmdline libsvn_subr provider implementation to use the new
pin-low/final-pin hints either.

To try this out add "ssl-pkcs11-provider = BLAH" to
~/.subversion/servers, with neon 0.28 built against pakchois
(http://www.manyfish.co.uk/pakchois/), and pakchois configured to look
in the appropriate directories for PKCS#11 provider DSOs.

I've tested with a gen-u-ine hardware smartcard, using
"ssl-pkcs11-provider = opensc", and the gnome-keyring software token,
using "ssl-pkcs11-provider = gnome-keyring".

[[[
Enable support for neon 0.28 PKCS#11 (smartcard) interfaces:

* subversion/libsvn_ra_neon/session.c [SVN_NEON_0_28]: Include
  ne_pkcs11.h
  (cleanup_p11provider, client_ssl_pkcs11_pin_entry): New functions.
  (get_server_settings): Add and handle the pk11_provider parameter.
  (svn_ra_neon__open): Fetch the PKCS#11 provider from the config
  file, if specified; initialize and set up the provider for both
  sessions, along with the cleanup. Set up the PIN callback.

* subversion/libsvn_ra_neon/ra_neon.h: Add p11pin_iterstate field to
  svn_ra_neon__session_t structure.

* subversion/include/svn_auth.h: Add SVN_AUTH_PARAM_LOW_PIN_COUNT and
  SVN_AUTH_PARAM_FINAL_PIN_TRY constants, indicate optional use with
  client-cert-pw providers.

* subversion/include/svn_config.h: Add ssl-pkcs11-provider option.

* subversion/libsvn_subr/config_file.c (svn_config_ensure): Document
  new ssl-pkcs11-provider config option.
]]]

Index: subversion/include/svn_config.h
===================================================================
--- subversion/include/svn_config.h (revision 29238)
+++ subversion/include/svn_config.h (working copy)
@@ -72,6 +72,7 @@
 #define SVN_CONFIG_OPTION_SSL_TRUST_DEFAULT_CA "ssl-trust-default-ca"
 #define SVN_CONFIG_OPTION_SSL_CLIENT_CERT_FILE "ssl-client-cert-file"
 #define SVN_CONFIG_OPTION_SSL_CLIENT_CERT_PASSWORD "ssl-client-cert-password"
+#define SVN_CONFIG_OPTION_SSL_PKCS11_PROVIDER "ssl-pkcs11-provider"
 #define SVN_CONFIG_OPTION_HTTP_LIBRARY "http-library"
 
 #define SVN_CONFIG_CATEGORY_CONFIG "config"
Index: subversion/include/svn_auth.h
===================================================================
--- subversion/include/svn_auth.h (revision 29238)
+++ subversion/include/svn_auth.h (working copy)
@@ -243,6 +243,8 @@
  * The following optional auth parameters are relevant to the providers:
  *
  * - @c SVN_AUTH_PARAM_NO_AUTH_CACHE (@c void*)
+ * - @c SVN_AUTH_PARAM_FINAL_PIN_TRY (@c void*)
+ * - @c SVN_AUTH_PARAM_LOW_PIN_COUNT (@c void*)
  */
 #define SVN_AUTH_CRED_SSL_CLIENT_CERT_PW "svn.ssl.client-passphrase"
 
@@ -550,7 +552,14 @@
  * ~/.subversion. */
 #define SVN_AUTH_PARAM_CONFIG_DIR SVN_AUTH_PARAM_PREFIX "config-dir"
 
+/** @brief The following property is for SSL client cert password
+ * providers. If set, it indicates the PIN entry count is low. */
+#define SVN_AUTH_PARAM_LOW_PIN_COUNT SVN_AUTH_PARAM_PREFIX "low-pin-count"
 
+/** @brief The following property is for SSL client cert password
+ * providers. If set, it indicates the last attempt at PIN entry. */
+#define SVN_AUTH_PARAM_FINAL_PIN_TRY SVN_AUTH_PARAM_PREFIX "final-pin-try"
+
 /** Get an initial set of credentials.
  *
  * Ask @a auth_baton to set @a *credentials to a set of credentials
Index: subversion/libsvn_subr/config_file.c
===================================================================
--- subversion/libsvn_subr/config_file.c (revision 29238)
+++ subversion/libsvn_subr/config_file.c (working copy)
@@ -789,6 +789,7 @@
         "### ssl-client-cert-file PKCS#12 format client certificate file"
                                                                              NL
         "### ssl-client-cert-password Client Key password, if needed." NL
+ "### ssl-pkcs11-provider Name of PKCS#11 provider to use." NL
         "### http-library Which library to use for http/https"
                                                                              NL
         "### connections (neon or serf)" NL
Index: subversion/libsvn_ra_neon/session.c
===================================================================
--- subversion/libsvn_ra_neon/session.c (revision 29238)
+++ subversion/libsvn_ra_neon/session.c (working copy)
@@ -40,6 +40,10 @@
 #include "svn_xml.h"
 #include "svn_private_config.h"
 
+#ifdef SVN_NEON_0_28
+#include <ne_pkcs11.h>
+#endif
+
 #include "ra_neon.h"
 
 #define DEFAULT_HTTP_TIMEOUT 3600
@@ -61,6 +65,17 @@
   return APR_SUCCESS;
 }
 
+#ifdef SVN_NEON_0_28
+/* a cleanup routine attached to the pool that contains the PKCS#11
+ provider object. */
+static apr_status_t cleanup_p11provider(void *provider)
+{
+ ne_ssl_pkcs11_provider *prov = provider;
+ ne_ssl_pkcs11_provider_destroy(prov);
+ return APR_SUCCESS;
+}
+#endif
+
 /* A neon-session callback to 'pull' authentication data when
    challenged. In turn, this routine 'pulls' the data from the client
    callbacks if needed. */
@@ -286,7 +301,71 @@
   return ok;
 }
 
+#ifdef SVN_NEON_0_28
+/* Callback invoked to enter PKCS#11 PIN code. */
+static svn_boolean_t
+client_ssl_pkcs11_pin_entry(void *userdata,
+ int attempt,
+ const char *slot_descr,
+ const char *token_label,
+ unsigned int flags,
+ char *pin)
+{
+ svn_ra_neon__session_t *ras = userdata;
+ svn_error_t *err;
+ apr_pool_t *pool;
+ svn_boolean_t ok = FALSE;
+ void *creds;
+ svn_auth_cred_ssl_client_cert_pw_t *pw_creds;
 
+ /* Set or clear the final-try/low-count parameters. */
+ svn_auth_set_parameter
+ (ras->callbacks->auth_baton, SVN_AUTH_PARAM_FINAL_PIN_TRY,
+ (flags & NE_SSL_P11PIN_FINAL_TRY) ? "" : NULL);
+
+ svn_auth_set_parameter
+ (ras->callbacks->auth_baton, SVN_AUTH_PARAM_LOW_PIN_COUNT,
+ (flags & NE_SSL_P11PIN_COUNT_LOW) ? "" : NULL);
+
+ /* Always prevent PIN caching; caching may override security policy
+ of the provider or token. */
+ svn_auth_set_parameter
+ (ras->callbacks->auth_baton, SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
+
+ if (attempt == 0)
+ {
+ const char *realmstring;
+
+ realmstring = apr_psprintf(ras->pool,
+ _("PIN for token \"%s\" in slot \"%s\""),
+ token_label, slot_descr);
+
+ err = svn_auth_first_credentials(&creds,
+ &(ras->auth_iterstate),
+ SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
+ realmstring,
+ ras->callbacks->auth_baton,
+ ras->pool);
+ }
+ else
+ err = svn_auth_next_credentials(&creds,
+ ras->auth_iterstate,
+ ras->pool);
+
+ if (err || ! creds)
+ {
+ svn_error_clear(err);
+ return -1;
+ }
+
+ pw_creds = creds;
+
+ apr_cpystrn(pin, pw_creds->password, NE_SSL_P11PINLEN);
+
+ return 0;
+}
+#endif
+
 static void
 client_ssl_callback(void *userdata, ne_session *sess,
                     const ne_ssl_dname *const *dnames,
@@ -366,6 +445,7 @@
                                         int *neon_debug,
                                         svn_boolean_t *compression,
                                         unsigned int *neon_auth_types,
+ const char **pk11_provider,
                                         svn_config_t *cfg,
                                         const char *requested_host,
                                         apr_pool_t *pool)
@@ -373,6 +453,7 @@
   const char *exceptions, *port_str, *timeout_str, *server_group;
   const char *debug_str, *http_auth_types;
   svn_boolean_t is_exception = FALSE;
+
   /* If we find nothing, default to nulls. */
   *proxy_host = NULL;
   *proxy_port = (unsigned int) -1;
@@ -382,6 +463,7 @@
   timeout_str = NULL;
   debug_str = NULL;
   http_auth_types = NULL;
+ *pk11_provider = NULL;
 
   /* If there are defaults, use them, but only if the requested host
      is not one of the exceptions to the defaults. */
@@ -412,6 +494,8 @@
       svn_config_get(cfg, &http_auth_types, SVN_CONFIG_SECTION_GLOBAL,
                      SVN_CONFIG_OPTION_HTTP_AUTH_TYPES, NULL);
 #endif
+ svn_config_get(cfg, pk11_provider, SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_SSL_PKCS11_PROVIDER, NULL);
     }
 
   if (cfg)
@@ -441,6 +525,8 @@
       svn_config_get(cfg, &http_auth_types, SVN_CONFIG_SECTION_GLOBAL,
                      SVN_CONFIG_OPTION_HTTP_AUTH_TYPES, NULL);
 #endif
+ svn_config_get(cfg, pk11_provider, SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_SSL_PKCS11_PROVIDER, *pk11_provider);
     }
 
   /* Special case: convert the port value, if any. */
@@ -830,6 +916,7 @@
   const char *server_group;
   char *itr;
   unsigned int neon_auth_types = 0;
+ const char *pkcs11_provider;
   neonprogress_baton_t *neonprogress_baton =
     apr_pcalloc(pool, sizeof(*neonprogress_baton));
   const char *useragent = NULL;
@@ -908,6 +995,7 @@
                                 &debug,
                                 &compression,
                                 &neon_auth_types,
+ &pkcs11_provider,
                                 cfg,
                                 uri->host,
                                 pool));
@@ -1037,9 +1125,42 @@
       /* For client connections, we register a callback for if the server
          wants to authenticate the client via client certificate. */
 
- ne_ssl_provide_clicert(sess, client_ssl_callback, ras);
- ne_ssl_provide_clicert(sess2, client_ssl_callback, ras);
+#ifdef SVN_NEON_0_28
+ if (pkcs11_provider)
+ {
+ ne_ssl_pkcs11_provider *provider;
+ int rv;
+
+ /* Initialize the PKCS#11 provider. */
+ rv = ne_ssl_pkcs11_provider_init(&provider, pkcs11_provider);
+ if (rv != NE_PK11_OK)
+ {
+ return svn_error_createf
+ (SVN_ERR_RA_DAV_INVALID_CONFIG_VALUE, NULL,
+ _("Invalid config: unable to load PKCS#11 provider '%s'"),
+ pkcs11_provider);
+ }
+
+ /* Share the provider between the two sessions. */
+ ne_ssl_set_pkcs11_provider(sess, provider);
+ ne_ssl_set_pkcs11_provider(sess2, provider);
+
+ ne_ssl_pkcs11_provider_pin(provider, client_ssl_pkcs11_pin_entry,
+ ras);
 
+ apr_pool_cleanup_register(pool, provider, cleanup_p11provider,
+ apr_pool_cleanup_null);
+ }
+ /* Note the "else"; if a PKCS#11 provider is set up, a client
+ cert callback is already configured, so don't displace it
+ with the normal one here. */
+ else
+#endif
+ {
+ ne_ssl_provide_clicert(sess, client_ssl_callback, ras);
+ ne_ssl_provide_clicert(sess2, client_ssl_callback, ras);
+ }
+
       /* See if the user wants us to trust "default" openssl CAs. */
       trust_default_ca = svn_config_get_server_setting(
                cfg, server_group,
Index: subversion/libsvn_ra_neon/ra_neon.h
===================================================================
--- subversion/libsvn_ra_neon/ra_neon.h (revision 29238)
+++ subversion/libsvn_ra_neon/ra_neon.h (working copy)
@@ -95,6 +95,8 @@
   svn_auth_iterstate_t *auth_iterstate; /* state of authentication retries */
   const char *auth_username; /* last authenticated username used */
 
+ svn_auth_iterstate_t *p11pin_iterstate; /* state of PKCS#11 pin retries */
+
   svn_boolean_t compression; /* should we use http compression? */
   const char *uuid; /* repository UUID */
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe_at_subversion.tigris.org
For additional commands, e-mail: dev-help_at_subversion.tigris.org
Received on 2008-02-08 22:51:14 CET

This is an archived mail posted to the Subversion Dev mailing list.