From 929d35ed08eebd8ca8bcd884ceb26b3faf23f73c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 30 Jan 2015 20:16:34 +0000 Subject: [PATCH] Support SHA256/SHA512 for OATH Signed-off-by: David Woodhouse --- gnutls.c | 20 ++++++++++++++++++-- oath.c | 30 +++++++++++++++++++++++++++++- openconnect-internal.h | 5 +++++ openssl.c | 18 +++++++++++++++++- www/building.xml | 2 +- www/changelog.xml | 2 ++ www/features.xml | 2 +- www/token.xml | 29 ++++++++++++++++++++++------- 8 files changed, 95 insertions(+), 13 deletions(-) diff --git a/gnutls.c b/gnutls.c index 32159fd5..e97789c4 100644 --- a/gnutls.c +++ b/gnutls.c @@ -2597,10 +2597,26 @@ int hotp_hmac(struct openconnect_info *vpninfo, const void *challenge) int ret; int hpos; unsigned char hash[64]; /* Enough for a SHA256 */ + gnutls_mac_algorithm_t alg; + + switch(vpninfo->oath_hmac_alg) { + case OATH_ALG_HMAC_SHA1: + alg = GNUTLS_MAC_SHA1; + break; + case OATH_ALG_HMAC_SHA256: + alg = GNUTLS_MAC_SHA256; + break; + case OATH_ALG_HMAC_SHA512: + alg = GNUTLS_MAC_SHA512; + break; + default: + vpn_progress(vpninfo, PRG_ERR, + _("Unsupported OATH HMAC algorithm\n")); + return -EINVAL; + } hpos = 19; - ret = gnutls_hmac_fast(GNUTLS_MAC_SHA1, - vpninfo->oath_secret, + ret = gnutls_hmac_fast(alg, vpninfo->oath_secret, vpninfo->oath_secret_len, challenge, 8, hash); if (ret) { diff --git a/oath.c b/oath.c index 39f16ad7..7015ba4a 100644 --- a/oath.c +++ b/oath.c @@ -226,7 +226,22 @@ int set_totp_mode(struct openconnect_info *vpninfo, const char *token_str) ret = pskc_decode(vpninfo, token_str, toklen, OC_TOKEN_MODE_TOTP); if (ret) return -EINVAL; - } else if (strncasecmp(token_str, "base32:", strlen("base32:")) == 0) { + vpninfo->token_mode = OC_TOKEN_MODE_TOTP; + return 0; + } + if (!strncasecmp(token_str, "sha1:", 5)) { + token_str += 5; + vpninfo->oath_hmac_alg = OATH_ALG_HMAC_SHA1; + } else if (!strncasecmp(token_str, "sha256:", 7)) { + token_str += 7; + vpninfo->oath_hmac_alg = OATH_ALG_HMAC_SHA256; + } else if (!strncasecmp(token_str, "sha512:", 7)) { + token_str += 7; + vpninfo->oath_hmac_alg = OATH_ALG_HMAC_SHA256; + } else + vpninfo->oath_hmac_alg = OATH_ALG_HMAC_SHA1; + + if (strncasecmp(token_str, "base32:", strlen("base32:")) == 0) { ret = decode_base32(vpninfo, token_str + strlen("base32:"), toklen - strlen("base32:")); if (ret) @@ -263,6 +278,19 @@ int set_hotp_mode(struct openconnect_info *vpninfo, const char *token_str) vpninfo->token_mode = OC_TOKEN_MODE_HOTP; return 0; } + + if (!strncasecmp(token_str, "sha1:", 5)) { + token_str += 5; + vpninfo->oath_hmac_alg = OATH_ALG_HMAC_SHA1; + } else if (!strncasecmp(token_str, "sha256:", 7)) { + token_str += 7; + vpninfo->oath_hmac_alg = OATH_ALG_HMAC_SHA256; + } else if (!strncasecmp(token_str, "sha512:", 7)) { + token_str += 7; + vpninfo->oath_hmac_alg = OATH_ALG_HMAC_SHA256; + } else + vpninfo->oath_hmac_alg = OATH_ALG_HMAC_SHA1; + p = strrchr(token_str, ','); if (p) { long counter; diff --git a/openconnect-internal.h b/openconnect-internal.h index 558bc432..9603290f 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -406,6 +406,11 @@ struct openconnect_info { #endif char *oath_secret; size_t oath_secret_len; + enum { + OATH_ALG_HMAC_SHA1 = 0, + OATH_ALG_HMAC_SHA256, + OATH_ALG_HMAC_SHA512, + } oath_hmac_alg; enum { HOTP_SECRET_BASE32 = 1, HOTP_SECRET_RAW, diff --git a/openssl.c b/openssl.c index 47a4005c..0434e783 100644 --- a/openssl.c +++ b/openssl.c @@ -1672,8 +1672,24 @@ int hotp_hmac(struct openconnect_info *vpninfo, const void *challenge) { unsigned char hash[64]; /* Enough for a SHA256 */ unsigned int hashlen = sizeof(hash); + const EVP_MD *alg; - if (!HMAC(EVP_sha1(), vpninfo->oath_secret, vpninfo->oath_secret_len, + switch(vpninfo->oath_hmac_alg) { + case OATH_ALG_HMAC_SHA1: + alg = EVP_sha1(); + break; + case OATH_ALG_HMAC_SHA256: + alg = EVP_sha256(); + break; + case OATH_ALG_HMAC_SHA512: + alg = EVP_sha512(); + break; + default: + vpn_progress(vpninfo, PRG_ERR, + _("Unsupported OATH HMAC algorithm\n")); + return -EINVAL; + } + if (!HMAC(alg, vpninfo->oath_secret, vpninfo->oath_secret_len, challenge, 8, hash, &hashlen)) { vpninfo->progress(vpninfo, PRG_ERR, _("Failed to calculate OATH HMAC\n")); diff --git a/www/building.xml b/www/building.xml index a08b97fc..bcee63b9 100644 --- a/www/building.xml +++ b/www/building.xml @@ -33,7 +33,7 @@ And optionally also:
  • libproxy
  • trousers (for TPM support if using GnuTLS)
  • libstoken (for SecurID software token support)
  • -
  • liboath (for software HOTP/TOTP support)
  • +
  • libpskc (for RFC6030 PSKC file storage of HOTP/TOTP keys)
  • libpcsclite (for Yubikey hardware HOTP/HOTP support)
  • OpenConnect supports the use of HTTP and SOCKS proxies to connect to the diff --git a/www/changelog.xml b/www/changelog.xml index 909f6f8f..8ca51506 100644 --- a/www/changelog.xml +++ b/www/changelog.xml @@ -15,6 +15,8 @@