Skip to content

Commit

Permalink
Use p11-kit for directing PIN request to process_auth_form()
Browse files Browse the repository at this point in the history
Set a 'pin-source' attribute which identifies the vpninfo structure, and
register a handler which converts it to an auth form for the GUI to process.

If the URI we are given already contains a pin_source then theoretically
we don't override it; we assume the caller knew what they were doing. In
practice, p11_kit_get_pin_source() seems to be returning NULL even when
the attribute *is* set, so we always override it.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Jun 8, 2012
1 parent f23d25f commit e513fcf
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 5 deletions.
4 changes: 2 additions & 2 deletions Makefile.am
Expand Up @@ -19,8 +19,8 @@ openconnect_LDADD = libopenconnect.la $(SSL_LIBS) $(LIBXML2_LIBS) $(LIBPROXY_LIB

library_srcs = ssl.c http.c auth.c library.c compat.c @SSL_LIBRARY@.c
libopenconnect_la_SOURCES = version.c $(library_srcs)
libopenconnect_la_CFLAGS = $(SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS)
libopenconnect_la_LIBADD = $(SSL_LIBS) $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(LIBINTL)
libopenconnect_la_CFLAGS = $(SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS) $(P11KIT_CFLAGS)
libopenconnect_la_LIBADD = $(SSL_LIBS) $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(LIBINTL) $(P11KIT_LIBS)
libopenconnect_la_LDFLAGS = -version-number @APIMAJOR@:@APIMINOR@
noinst_HEADERS = openconnect-internal.h openconnect.h
include_HEADERS = openconnect.h
Expand Down
3 changes: 3 additions & 0 deletions configure.ac
Expand Up @@ -203,6 +203,9 @@ if test "$with_gnutls" = "yes" || test "$with_gnutls" = "shibboleet"; then
[AC_DEFINE(HAVE_GNUTLS_PKCS12_SIMPLE_PARSE, 1)], [])
AC_CHECK_FUNC(gnutls_session_set_premaster,
[AC_DEFINE(HAVE_GNUTLS_SESSION_SET_PREMASTER, 1)], [])
AC_CHECK_FUNC(gnutls_pkcs11_add_provider,
[PKG_CHECK_MODULES(P11KIT, p11-kit-1, [AC_DEFINE(HAVE_P11KIT)
AC_SUBST(P11KIT_PC, p11-kit-1)], [:])], [])
LIBS="$oldLIBS"
elif test "$with_gnutls" != "" && test "$with_gnutls" != "no"; then
AC_MSG_ERROR([Values other than 'yes' or 'no' for --with-gnutls are not supported])
Expand Down
114 changes: 112 additions & 2 deletions gnutls.c
Expand Up @@ -42,6 +42,16 @@
#include <gnutls/crypto.h>
#include <gnutls/pkcs12.h>

#ifdef HAVE_P11KIT
#include <p11-kit/p11-kit.h>
#include <p11-kit/pin.h>

static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri,
const char *pin_description,
P11KitPinFlags flags,
void *_vpninfo);
#endif

#include "openconnect-internal.h"

/* Helper functions for reading/writing lines over SSL.
Expand Down Expand Up @@ -418,13 +428,51 @@ static int load_certificate(struct openconnect_info *vpninfo)
}

if (!strncmp(vpninfo->cert, "pkcs11:", 7)) {
char *cert_url = (char *)vpninfo->cert;
char *key_url = (char *)vpninfo->sslkey;
#ifdef HAVE_P11KIT
char pin_source[40];
P11KitUri *uri;

sprintf(pin_source, "openconnect:%p", vpninfo);

uri = p11_kit_uri_new();
if (p11_kit_uri_parse(vpninfo->cert, P11_KIT_URI_FOR_OBJECT, uri) != P11_KIT_URI_OK) {
vpn_progress(vpninfo, PRG_ERR, _("Failed to parse PKCS#11 URL '%s'\n"),
vpninfo->cert);
p11_kit_uri_free(uri);
return -EINVAL;
}
if (!p11_kit_uri_get_pin_source(uri)) {
p11_kit_uri_set_pin_source(uri, pin_source);
p11_kit_uri_format(uri, P11_KIT_URI_FOR_OBJECT, &cert_url);
}

if (p11_kit_uri_parse(vpninfo->sslkey, P11_KIT_URI_FOR_OBJECT, uri) != P11_KIT_URI_OK) {
vpn_progress(vpninfo, PRG_ERR, _("Failed to parse PKCS#11 URL '%s'\n"),
vpninfo->sslkey);
p11_kit_uri_free(uri);
free(cert_url);
return -EINVAL;
}
if (!p11_kit_uri_get_pin_source(uri)) {
p11_kit_uri_set_pin_source(uri, pin_source);
p11_kit_uri_format(uri, P11_KIT_URI_FOR_OBJECT, &key_url);
}
p11_kit_uri_free(uri);
p11_kit_pin_register_callback(pin_source, pin_callback, vpninfo, NULL);
#endif
vpn_progress(vpninfo, PRG_TRACE,
_("Using PKCS#11 certificate %s\n"), vpninfo->cert);

err = gnutls_certificate_set_x509_key_file(vpninfo->https_cred,
vpninfo->cert,
vpninfo->sslkey,
cert_url, key_url,
GNUTLS_X509_FMT_PEM);
if (cert_url != vpninfo->cert)
free(cert_url);
if (key_url != vpninfo->sslkey)
free(key_url);

if (err) {
vpn_progress(vpninfo, PRG_ERR,
_("Error loading PKCS#11 certificate: %s\n"),
Expand Down Expand Up @@ -980,6 +1028,15 @@ int openconnect_open_https(struct openconnect_info *vpninfo)

void openconnect_close_https(struct openconnect_info *vpninfo)
{
#ifdef HAVE_P11KIT
if (!strncmp(vpninfo->cert, "pkcs11:", 7)) {
char pin_source[40];

sprintf(pin_source, "openconnect:%p", vpninfo);
p11_kit_pin_unregister_callback(pin_source, pin_callback, vpninfo);
}
#endif

if (vpninfo->peer_cert) {
gnutls_x509_crt_deinit(vpninfo->peer_cert);
vpninfo->peer_cert = NULL;
Expand Down Expand Up @@ -1040,3 +1097,56 @@ int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
return 0;
}

#ifdef HAVE_P11KIT
static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri,
const char *pin_description,
P11KitPinFlags flags,
void *_vpninfo)
{
struct openconnect_info *vpninfo = _vpninfo;
struct oc_auth_form f;
struct oc_form_opt o;
char message[1024];
P11KitPin *pin;
int ret;

if (!vpninfo || !vpninfo->process_auth_form)
return NULL;

memset(&f, 0, sizeof(f));
f.auth_id = (char *)"pkcs11_pin";
f.opts = &o;

message[sizeof(message)-1] = 0;
snprintf(message, sizeof(message) - 1, _("PIN required for %s"), pin_description);
f.message = message;

/*
* p11-kit flags are *odd*.
* RETRY is 0xa, FINAL_TRY is 0x14 and MANY_TRIES is 0x28.
* So don't treat it like a sane bitmask.
*/
if ((flags & P11_KIT_PIN_FLAGS_RETRY) == P11_KIT_PIN_FLAGS_RETRY)
f.error = _("Wrong PIN");

if ((flags & P11_KIT_PIN_FLAGS_FINAL_TRY) == P11_KIT_PIN_FLAGS_FINAL_TRY)
f.banner = _("This is the final try before locking!");
else if ((flags & P11_KIT_PIN_FLAGS_MANY_TRIES) == P11_KIT_PIN_FLAGS_MANY_TRIES)
f.banner = _("Only a few tries left before locking!");

o.next = NULL;
o.type = OC_FORM_OPT_PASSWORD;
o.name = (char *)"pkcs11_pin";
o.label = _("Enter PIN:");
o.value = NULL;

ret = vpninfo->process_auth_form(vpninfo, &f);
if (ret || !o.value)
return NULL;

pin = p11_kit_pin_new_for_string(o.value);
free(o.value);

return pin;
}
#endif
2 changes: 1 addition & 1 deletion openconnect.pc.in
Expand Up @@ -7,7 +7,7 @@ includedir=@includedir@
Name: openconnect
Description: OpenConnect VPN client
Version: @VERSION@
Requires: @LIBPROXY_PC@ zlib @SSL_LIBRARY@ libxml-2.0
Requires: @LIBPROXY_PC@ zlib @SSL_LIBRARY@ @P11KIT_PC@ libxml-2.0
Libs: -L${libdir} -lopenconnect
Libs.private: @LIBINTL@
Cflags: -I${includedir} @SSL_DEFINE@

0 comments on commit e513fcf

Please sign in to comment.