Commit 7236d82b authored by David Woodhouse's avatar David Woodhouse

Add PSKC support

Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent f85299e7
......@@ -15,7 +15,7 @@ AM_CFLAGS = @WFLAGS@
AM_CPPFLAGS = -DLOCALEDIR="\"$(localedir)\""
openconnect_SOURCES = xml.c main.c
openconnect_CFLAGS = $(AM_CFLAGS) $(SSL_CFLAGS) $(DTLS_SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS) $(ZLIB_CFLAGS) $(LIBSTOKEN_CFLAGS) $(LIBOATH_CFLAGS) $(GSSAPI_CFLAGS)
openconnect_CFLAGS = $(AM_CFLAGS) $(SSL_CFLAGS) $(DTLS_SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS) $(ZLIB_CFLAGS) $(LIBSTOKEN_CFLAGS) $(LIBOATH_CFLAGS) $(LIBPSKC_CFLAGS) $(GSSAPI_CFLAGS)
openconnect_LDADD = libopenconnect.la $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(LIBINTL) $(LIBICONV)
library_srcs = ssl.c http.c auth.c library.c compat.c dtls.c cstp.c \
......@@ -50,8 +50,8 @@ library_srcs += $(lib_srcs_posix)
endif
libopenconnect_la_SOURCES = version.c $(library_srcs)
libopenconnect_la_CFLAGS = $(AM_CFLAGS) $(SSL_CFLAGS) $(DTLS_SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS) $(ZLIB_CFLAGS) $(P11KIT_CFLAGS) $(TSS_CFLAGS) $(LIBSTOKEN_CFLAGS) $(LIBOATH_CFLAGS) $(GSSAPI_CFLAGS)
libopenconnect_la_LIBADD = $(SSL_LIBS) $(DTLS_SSL_LIBS) $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(ZLIB_LIBS) $(LIBINTL) $(P11KIT_LIBS) $(TSS_LIBS) $(LIBSTOKEN_LIBS) $(LIBOATH_LIBS) $(GSSAPI_LIBS) $(LIBICONV)
libopenconnect_la_CFLAGS = $(AM_CFLAGS) $(SSL_CFLAGS) $(DTLS_SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS) $(ZLIB_CFLAGS) $(P11KIT_CFLAGS) $(TSS_CFLAGS) $(LIBSTOKEN_CFLAGS) $(LIBOATH_CFLAGS) $(LIBPSKC_CFLAGS) $(GSSAPI_CFLAGS)
libopenconnect_la_LIBADD = $(SSL_LIBS) $(DTLS_SSL_LIBS) $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(ZLIB_LIBS) $(LIBINTL) $(P11KIT_LIBS) $(TSS_LIBS) $(LIBSTOKEN_LIBS) $(LIBOATH_LIBS) $(LIBPSKC_LIBS) $(GSSAPI_LIBS) $(LIBICONV)
if OPENBSD_LIBTOOL
# OpenBSD's libtool doesn't have -version-number, but its -version-info arg
# does what GNU libtool's -version-number does. Which arguably is what the
......
......@@ -1452,17 +1452,19 @@ static void buf_append_base32(struct oc_text_buf *buf, void *data, int len)
static char *regen_hotp_secret(struct openconnect_info *vpninfo)
{
char *new_secret = NULL;
struct oc_text_buf *buf = buf_alloc();
struct oc_text_buf *buf;
int i;
switch (vpninfo->hotp_secret_format) {
case HOTP_SECRET_BASE32:
buf = buf_alloc();
buf_append(buf, "base32:");
buf_append_base32(buf, vpninfo->oath_secret,
vpninfo->oath_secret_len);
break;
case HOTP_SECRET_HEX:
buf = buf_alloc();
buf_append(buf, "0x");
for (i=0; i < vpninfo->oath_secret_len; i++)
buf_append(buf, "%02x",
......@@ -1470,12 +1472,44 @@ static char *regen_hotp_secret(struct openconnect_info *vpninfo)
break;
case HOTP_SECRET_RAW:
buf = buf_alloc();
buf_append_bytes(buf, vpninfo->oath_secret,
vpninfo->oath_secret_len);
break;
case HOTP_SECRET_PSKC:
/* Not implemented yet */
#ifdef HAVE_LIBPSKC
{
size_t len;
if (!vpninfo->pskc_key || !vpninfo->pskc)
return NULL;
pskc_set_key_data_counter(vpninfo->pskc_key, vpninfo->token_time);
pskc_build_xml(vpninfo->pskc, &new_secret, &len);
/* FFS #1: libpskc craps all over itself on pskc_build_xml().
https://bugzilla.redhat.com/show_bug.cgi?id=1129491
Hopefully this will be fixed by 2.4.2 but make it
unconditional for now... */
if (1 || !pskc_check_version("2.4.2")) {
pskc_done(vpninfo->pskc);
vpninfo->pskc = NULL;
vpninfo->pskc_key = NULL;
if (pskc_init(&vpninfo->pskc) ||
pskc_parse_from_memory(vpninfo->pskc, len, new_secret)) {
pskc_done(vpninfo->pskc);
vpninfo->pskc = NULL;
} else {
vpninfo->pskc_key = pskc_get_keypackage(vpninfo->pskc, 0);
vpninfo->oath_secret = (char *)pskc_get_key_data_secret(vpninfo->pskc_key, NULL);
}
}
/* FFS #2: No terminating NUL byte */
realloc_inplace(new_secret, len + 1);
if (new_secret)
new_secret[len] = 0;
return new_secret;
}
#endif
default:
return NULL;
}
......
......@@ -622,6 +622,13 @@ AS_IF([test "x$with_liboath" != "xno"], [
AC_DEFINE([HAVE_LIBOATH], 1, [Have liboath])
liboath_pkg=yes],
liboath_pkg=no)
if test "$liboath_pkg" = "yes"; then
PKG_CHECK_MODULES(LIBPSKC, [libpskc >= 2.2.0],
[AC_SUBST(LIBPSKC_PC, libpskc)
AC_DEFINE([HAVE_LIBPSKC], 1, [Have libpskc])
libpskc_pkg=yes],
libpskc_pkg=no)
fi
])
linked_gssapi=no
......
......@@ -229,9 +229,16 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
stoken_destroy(vpninfo->stoken_ctx);
#endif
#ifdef HAVE_LIBOATH
if (vpninfo->oath_secret)
if (vpninfo->oath_secret) {
#ifdef HAVE_LIBPSKC
if (vpninfo->pskc)
pskc_done(vpninfo->pskc);
else
#endif /* HAVE_LIBPSKC */
free(vpninfo->oath_secret);
oath_done();
#endif
}
#endif /* HAVE_LIBOATH */
/* These check strm->state so they are safe to call multiple times */
inflateEnd(&vpninfo->inflate_strm);
......@@ -561,6 +568,62 @@ static char *parse_hex(const char *tok, int len)
}
#endif
#ifdef HAVE_LIBOATH
static int pskc_decode(struct openconnect_info *vpninfo, const char *token_str,
int toklen, int mode)
{
#ifdef HAVE_LIBPSKC
pskc_t *container;
pskc_key_t *key;
const char *key_algo;
const char *want_algo;
size_t klen;
if (pskc_global_init())
return -EIO;
if (pskc_init(&container))
return -ENOMEM;
if (pskc_parse_from_memory(container, toklen, token_str))
return -EINVAL;
key = pskc_get_keypackage(container, 0);
if (!key) {
pskc_done(container);
return -EINVAL;
}
if (mode == OC_TOKEN_MODE_HOTP)
want_algo = "urn:ietf:params:xml:ns:keyprov:pskc:hotp";
else
want_algo = "urn:ietf:params:xml:ns:keyprov:pskc:totp";
key_algo = pskc_get_key_algorithm(key);
if (!key_algo || strcmp(key_algo, want_algo)) {
pskc_done(container);
return -EINVAL;
}
vpninfo->oath_secret = (char *)pskc_get_key_data_secret(key, &klen);
vpninfo->oath_secret_len = klen;
if (!vpninfo->oath_secret) {
pskc_done(container);
return -EINVAL;
}
vpninfo->token_time = pskc_get_key_data_counter(key, NULL);
vpninfo->pskc = container;
vpninfo->pskc_key = key;
return 0;
#else /* !HAVE_LIBPSKC */
vpn_progress(vpninfo, PRG_ERR,
_("This version of OpenConnect was built without PSKC support\n"));
return -EINVAL;
#endif /* HAVE_LIBPSKC */
}
#endif /* HAVE_LIBOATH */
static int set_totp_mode(struct openconnect_info *vpninfo,
const char *token_str)
{
......@@ -578,7 +641,12 @@ static int set_totp_mode(struct openconnect_info *vpninfo,
while (toklen && isspace((int)(unsigned char)token_str[toklen-1]))
toklen--;
if (strncasecmp(token_str, "base32:", strlen("base32:")) == 0) {
if (strncmp(token_str, "<?xml", 5) == 0) {
vpninfo->hotp_secret_format = HOTP_SECRET_PSKC;
ret = pskc_decode(vpninfo, token_str, toklen, OC_TOKEN_MODE_TOTP);
if (ret)
return -EINVAL;
} else if (strncasecmp(token_str, "base32:", strlen("base32:")) == 0) {
ret = oath_base32_decode(token_str + strlen("base32:"),
toklen - strlen("base32:"),
&vpninfo->oath_secret,
......@@ -617,6 +685,15 @@ static int set_hotp_mode(struct openconnect_info *vpninfo,
return -EINVAL;
toklen = strlen(token_str);
if (strncmp(token_str, "<?xml", 5) == 0) {
vpninfo->hotp_secret_format = HOTP_SECRET_PSKC;
ret = pskc_decode(vpninfo, token_str, toklen, OC_TOKEN_MODE_HOTP);
if (ret)
return -EINVAL;
vpninfo->token_mode = OC_TOKEN_MODE_HOTP;
return 0;
}
p = strrchr(token_str, ',');
if (p) {
long counter;
......
......@@ -85,6 +85,10 @@
#include GSSAPI_HDR
#endif
#ifdef HAVE_LIBPSKC
#include <pskc/pskc.h>
#endif
#ifdef ENABLE_NLS
#include <libintl.h>
#define _(s) dgettext("openconnect", s)
......@@ -265,6 +269,10 @@ struct openconnect_info {
int stoken_concat_pin;
int stoken_interval;
#endif
#ifdef HAVE_LIBPSKC
pskc_t *pskc;
pskc_key_t *pskc_key;
#endif
#ifdef HAVE_LIBOATH
char *oath_secret;
size_t oath_secret_len;
......
......@@ -7,7 +7,7 @@ includedir=@includedir@
Name: openconnect
Description: OpenConnect VPN client
Version: @VERSION@
Requires.private: @LIBPROXY_PC@ @ZLIB_PC@ @SSL_DTLS_PC@ @P11KIT_PC@ @LIBSTOKEN_PC@ @LIBOATH_PC@ libxml-2.0
Requires.private: @LIBPROXY_PC@ @ZLIB_PC@ @SSL_DTLS_PC@ @P11KIT_PC@ @LIBSTOKEN_PC@ @LIBOATH_PC@ @LIBPSKC_PC@ libxml-2.0
Libs: -L${libdir} -lopenconnect
Libs.private: @LIBINTL@
Cflags: -I${includedir}
......@@ -15,6 +15,7 @@
<ul>
<li><b>OpenConnect HEAD</b>
<ul>
<li>Support using PSKC <i>(<a href="http://tools.ietf.org/html/rfc6030">RFC6030</a>)</i> token files for HOTP/TOTP tokens.</li>
<li>Support for updating HOTP token storage when token is used.</li>
<li>Support for reading OTP token data from a file.</li>
<li>Add full <a href="charset.html">character set handling</a> for legacy non-UTF8 systems <i>(including Windows)</i>.</li>
......@@ -44,7 +45,7 @@
<li><b><a href="ftp://ftp.infradead.org/pub/openconnect/openconnect-5.99.tar.gz">OpenConnect v5.99</a></b>
<i>(<a href="ftp://ftp.infradead.org/pub/openconnect/openconnect-5.99.tar.gz.asc">PGP signature</a>)</i> &#8212; 2014-03-05
<ul>
<li>Add RFC4226 HOTP token support.</li>
<li>Add <a href="http://tools.ietf.org/html/rfc4226">RFC4226</a> HOTP token support.</li>
<li>Tolerate servers closing connection uncleanly after HTTP/1.0 response <a href="https://bugs.launchpad.net/bugs/1225276"><i>(Ubuntu #1225276)</i></a>.</li>
<li>Add support for IPv6 split tunnel configuration.</li>
<li>Add Windows support with MinGW <i>(tested with both IPv6 and Legacy IP with latest <a href="http://git.infradead.org/users/dwmw2/vpnc-scripts.git/blob_plain/HEAD:/vpnc-script-win.js">vpnc-script-win.js</a>)</i></li>
......@@ -106,7 +107,7 @@
<li>Fix compatibility issues with XML POST authentication.</li>
<li>Fix memory leaks on <tt>realloc()</tt> failure.</li>
<li>Fix certificate validation problem caused by hostname canonicalisation.</li>
<li>Add RFC6238 TOTP token support using <a href="http://www.nongnu.org/oath-toolkit/">liboath</a>.</li>
<li>Add <a href="http://tools.ietf.org/html/rfc6238">RFC6238</a> TOTP token support using <a href="http://www.nongnu.org/oath-toolkit/">liboath</a>.</li>
<li>Replace <tt>--stoken</tt> option with more generic <tt>--token-mode</tt> and <tt>--token-secret</tt> options.</li>
</ul><br/>
</li>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment