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