From bac41dfa93a26752d8c5be0aa0b3419d3e98a9b9 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 14 Nov 2014 14:32:40 +0000 Subject: [PATCH] Avoid keeping the real Yubikey PIN around Just keep the PBKDF2 hashed version around instead. Signed-off-by: David Woodhouse --- gnutls.c | 25 ++++++++++++++++--------- library.c | 2 +- openconnect-internal.h | 9 ++++++--- openssl.c | 18 ++++++++++++------ yubikey.c | 18 +++++++++++------- 5 files changed, 46 insertions(+), 26 deletions(-) diff --git a/gnutls.c b/gnutls.c index cc680d95..b68a5a0d 100644 --- a/gnutls.c +++ b/gnutls.c @@ -2351,10 +2351,10 @@ static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri, #endif #ifdef HAVE_LIBPCSCLITE -int openconnect_yubikey_challenge(const char *password, const void *ident, int id_len, - const void *challenge, int chall_len, void *result) +int openconnect_hash_yubikey_password(struct openconnect_info *vpninfo, + const char *password, const void *ident, int id_len) { - unsigned char U[SHA1_SIZE], T[SHA1_SIZE]; + unsigned char U[SHA1_SIZE]; gnutls_hmac_hd_t dgst; int ret = -EIO; int i, j; @@ -2371,23 +2371,30 @@ int openconnect_yubikey_challenge(const char *password, const void *ident, int i goto out; gnutls_hmac_output(dgst, U); - memcpy(T, U, SHA1_SIZE); + memcpy(vpninfo->yubikey_pwhash, U, 16); + for (i = 1; i < 1000; i++) { if (gnutls_hmac(dgst, U, SHA1_SIZE)) goto out; gnutls_hmac_output(dgst, U); - for (j = 0; j < SHA1_SIZE; j++) - T[j] ^= U[j]; + for (j = 0; j < 16; j++) + vpninfo->yubikey_pwhash[j] ^= U[j]; } - if (gnutls_hmac_fast(GNUTLS_MAC_SHA1, T, 16, challenge, chall_len, result)) - goto out; - ret = 0; out: gnutls_hmac_deinit(dgst, NULL); return ret; } + +int openconnect_yubikey_chalresp(struct openconnect_info *vpninfo, + const void *challenge, int chall_len, void *result) +{ + if (gnutls_hmac_fast(GNUTLS_MAC_SHA1, vpninfo->yubikey_pwhash, 16, challenge, chall_len, result)) + return -EIO; + + return 0; +} #endif diff --git a/library.c b/library.c index d12824c7..8552bd54 100644 --- a/library.c +++ b/library.c @@ -263,7 +263,7 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo) SCardDisconnect(vpninfo->pcsc_card, SCARD_LEAVE_CARD); SCardReleaseContext(vpninfo->pcsc_ctx); } - free(vpninfo->yubikey_password); + memset(vpninfo->yubikey_pwhash, 0, sizeof(vpninfo->yubikey_pwhash)); free(vpninfo->yubikey_objname); #endif /* These check strm->state so they are safe to call multiple times */ diff --git a/openconnect-internal.h b/openconnect-internal.h index 0f17746b..3027b50d 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -290,7 +290,8 @@ struct openconnect_info { #ifdef HAVE_LIBPCSCLITE SCARDHANDLE pcsc_ctx, pcsc_card; char *yubikey_objname; - char *yubikey_password; + unsigned char yubikey_pwhash[16]; + int yubikey_pw_set; int yubikey_mode; #endif openconnect_lock_token_vfn lock_token; @@ -646,8 +647,10 @@ int openconnect_md5(unsigned char *result, void *data, int len); int openconnect_random(void *bytes, int len); int openconnect_local_cert_md5(struct openconnect_info *vpninfo, char *buf); -int openconnect_yubikey_challenge(const char *password, const void *ident, int id_len, - const void *challenge, int chall_len, void *result); +int openconnect_yubikey_chalresp(struct openconnect_info *vpninfo, + const void *challenge, int chall_len, void *result); +int openconnect_hash_yubikey_password(struct openconnect_info *vpninfo, + const char *password, const void *ident, int id_len); #if defined(OPENCONNECT_OPENSSL) #define openconnect_https_connected(_v) ((_v)->https_ssl) #elif defined (OPENCONNECT_GNUTLS) diff --git a/openssl.c b/openssl.c index ee704d90..92924897 100644 --- a/openssl.c +++ b/openssl.c @@ -1615,16 +1615,22 @@ int openconnect_local_cert_md5(struct openconnect_info *vpninfo, } #ifdef HAVE_LIBPCSCLITE -int openconnect_yubikey_challenge(const char *password, const void *ident, int id_len, +int openconnect_hash_yubikey_password(struct openconnect_info *vpninfo, + const char *password, const void *ident, int id_len) +{ + if (!PKCS5_PBKDF2_HMAC_SHA1(password, strlen(password), ident, id_len, 1000, 16, + vpninfo->yubikey_pwhash)) + return -EIO; + + return 0; +} + +int openconnect_yubikey_chalresp(struct openconnect_info *vpninfo, const void *challenge, int chall_len, void *result) { - unsigned char T[20]; unsigned int mdlen = SHA1_SIZE; - if (!PKCS5_PBKDF2_HMAC_SHA1(password, strlen(password), ident, id_len, 1000, 16, T)) - return -EIO; - - if (!HMAC(EVP_sha1(), T, 16, challenge, chall_len, result, &mdlen)) + if (!HMAC(EVP_sha1(), vpninfo->yubikey_pwhash, 16, challenge, chall_len, result, &mdlen)) return -EIO; return 0; diff --git a/yubikey.c b/yubikey.c index 81ec2ae6..2b71e353 100644 --- a/yubikey.c +++ b/yubikey.c @@ -196,7 +196,7 @@ static int select_yubioath_applet(struct openconnect_info *vpninfo, chall_len = tlvlen; retry: - if (!vpninfo->yubikey_password) { + if (!vpninfo->yubikey_pw_set) { struct oc_auth_form f; struct oc_form_opt o; @@ -217,11 +217,15 @@ static int select_yubioath_applet(struct openconnect_info *vpninfo, if (!o._value) return -EPERM; - vpninfo->yubikey_password = o._value; + ret = openconnect_hash_yubikey_password(vpninfo, o._value, applet_id, id_len); + if (ret) + return ret; + + vpninfo->yubikey_pw_set = 1; + memset(o._value, 0, strlen(o._value)); + free(o._value); } - if (openconnect_yubikey_challenge(vpninfo->yubikey_password, - applet_id, id_len, - &challenge, chall_len, + if (openconnect_yubikey_chalresp(vpninfo, &challenge, chall_len, chalresp + 7)) { vpn_progress(vpninfo, PRG_ERR, _("Failed to calculate Yubikey unlock response\n")); @@ -243,8 +247,8 @@ static int select_yubioath_applet(struct openconnect_info *vpninfo, ret = yubikey_cmd(vpninfo, pcsc_card, PRG_ERR, _("unlock command"), chalresp, sizeof(chalresp), buf); if (ret == -EINVAL) { - free(vpninfo->yubikey_password); - vpninfo->yubikey_password = NULL; + memset(vpninfo->yubikey_pwhash, 0, sizeof(vpninfo->yubikey_pwhash)); + vpninfo->yubikey_pw_set = 0; goto retry; } if (ret)