Commit bac41dfa authored by David Woodhouse's avatar David Woodhouse

Avoid keeping the real Yubikey PIN around

Just keep the PBKDF2 hashed version around instead.
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent a23f11ad
......@@ -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
......@@ -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 */
......
......@@ -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)
......
......@@ -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;
......
......@@ -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)
......
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