Skip to content

Commit

Permalink
Move HOTP/TOTP code to oath.c
Browse files Browse the repository at this point in the history
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Aug 13, 2014
1 parent ce4041a commit 6f0ee16
Show file tree
Hide file tree
Showing 6 changed files with 459 additions and 417 deletions.
6 changes: 5 additions & 1 deletion Makefile.am
Expand Up @@ -26,11 +26,15 @@ lib_srcs_win32 = tun-win32.c sspi.c
lib_srcs_posix = tun.c
lib_srcs_gssapi = gssapi.c
lib_srcs_iconv = iconv.c
lib_srcs_oath = oath.c

POTFILES = $(openconnect_SOURCES) $(lib_srcs_openssl) $(lib_srcs_gnutls) \
$(library_srcs) $(lib_srcs_win32) $(lib_srcs_posix) $(lib_srcs_gssapi) \
$(lib_srcs_iconv) openconnect-internal.h
$(lib_srcs_iconv) $(lib_srcs_oath) openconnect-internal.h

if OPENCONNECT_OATH
library_srcs += $(lib_srcs_oath)
endif
if OPENCONNECT_GSSAPI
library_srcs += $(lib_srcs_gssapi)
endif
Expand Down
215 changes: 0 additions & 215 deletions auth.c
Expand Up @@ -1315,61 +1315,6 @@ static int do_gen_stoken_code(struct openconnect_info *vpninfo,

#endif

#ifdef HAVE_LIBOATH
/* Return value:
* < 0, if unable to generate a tokencode
* = 0, on success
*/
static int can_gen_totp_code(struct openconnect_info *vpninfo,
struct oc_auth_form *form,
struct oc_form_opt *opt)
{
if ((strcmp(opt->name, "secondary_password") != 0) ||
vpninfo->token_bypassed)
return -EINVAL;
if (vpninfo->token_tries == 0) {
vpn_progress(vpninfo, PRG_DEBUG,
_("OK to generate INITIAL tokencode\n"));
vpninfo->token_time = 0;
} else if (vpninfo->token_tries == 1) {
vpn_progress(vpninfo, PRG_DEBUG,
_("OK to generate NEXT tokencode\n"));
vpninfo->token_time += OATH_TOTP_DEFAULT_TIME_STEP_SIZE;
} else {
/* limit the number of retries, to avoid account lockouts */
vpn_progress(vpninfo, PRG_INFO,
_("Server is rejecting the soft token; switching to manual entry\n"));
return -ENOENT;
}
return 0;
}

/* Return value:
* < 0, if unable to generate a tokencode
* = 0, on success
*/
static int can_gen_hotp_code(struct openconnect_info *vpninfo,
struct oc_auth_form *form,
struct oc_form_opt *opt)
{
if ((strcmp(opt->name, "secondary_password") != 0) ||
vpninfo->token_bypassed)
return -EINVAL;
if (vpninfo->token_tries == 0) {
vpn_progress(vpninfo, PRG_DEBUG,
_("OK to generate INITIAL tokencode\n"));
} else if (vpninfo->token_tries == 1) {
vpn_progress(vpninfo, PRG_DEBUG,
_("OK to generate NEXT tokencode\n"));
} else {
/* limit the number of retries, to avoid account lockouts */
vpn_progress(vpninfo, PRG_INFO,
_("Server is rejecting the soft token; switching to manual entry\n"));
return -ENOENT;
}
return 0;
}
#endif
/* Return value:
* < 0, if unable to generate a tokencode
* = 0, on success
Expand All @@ -1394,166 +1339,6 @@ static int can_gen_tokencode(struct openconnect_info *vpninfo,
}
}

#ifdef HAVE_LIBOATH
static int do_gen_totp_code(struct openconnect_info *vpninfo,
struct oc_auth_form *form,
struct oc_form_opt *opt)
{
int oath_err;
char tokencode[7];

if (!vpninfo->token_time)
vpninfo->token_time = time(NULL);

vpn_progress(vpninfo, PRG_INFO, _("Generating OATH TOTP token code\n"));

oath_err = oath_totp_generate(vpninfo->oath_secret,
vpninfo->oath_secret_len,
vpninfo->token_time,
OATH_TOTP_DEFAULT_TIME_STEP_SIZE,
OATH_TOTP_DEFAULT_START_TIME,
6, tokencode);
if (oath_err != OATH_OK) {
vpn_progress(vpninfo, PRG_ERR,
_("Unable to generate OATH TOTP token code: %s\n"),
oath_strerror(oath_err));
return -EIO;
}

vpninfo->token_tries++;
opt->value = strdup(tokencode);
return opt->value ? 0 : -ENOMEM;
}

static void buf_append_base32(struct oc_text_buf *buf, void *data, int len)
{
size_t b32_len;
char *b32 = NULL;

if (oath_base32_encode(data, len, &b32, &b32_len)) {
buf->error = ENOMEM;
return;
}
buf_append_bytes(buf, b32, b32_len);
free(b32);
}

static char *regen_hotp_secret(struct openconnect_info *vpninfo)
{
char *new_secret = NULL;
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",
(unsigned char)vpninfo->oath_secret[i]);
break;

case HOTP_SECRET_RAW:
buf = buf_alloc();
buf_append_bytes(buf, vpninfo->oath_secret,
vpninfo->oath_secret_len);
break;

case HOTP_SECRET_PSKC:
#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;
}

buf_append(buf,",%ld", (long)vpninfo->token_time);
if (!buf_error(buf)) {
new_secret = buf->data;
buf->data = NULL;
}
buf_free(buf);
return new_secret;
}

static int do_gen_hotp_code(struct openconnect_info *vpninfo,
struct oc_auth_form *form,
struct oc_form_opt *opt)
{
int oath_err;
char tokencode[7];
int ret;

vpn_progress(vpninfo, PRG_INFO, _("Generating OATH HOTP token code\n"));

if (vpninfo->lock_token) {
/* This may call openconnect_set_token_mode() again to update
* the token if it's changed. */
ret = vpninfo->lock_token(vpninfo->tok_cbdata);
if (ret)
return ret;
}

oath_err = oath_hotp_generate(vpninfo->oath_secret,
vpninfo->oath_secret_len,
vpninfo->token_time,
6, false, OATH_HOTP_DYNAMIC_TRUNCATION,
tokencode);
if (oath_err != OATH_OK) {
vpn_progress(vpninfo, PRG_ERR,
_("Unable to generate OATH HOTP token code: %s\n"),
oath_strerror(oath_err));
if (vpninfo->unlock_token)
vpninfo->unlock_token(vpninfo->tok_cbdata, NULL);
return -EIO;
}
vpninfo->token_time++;
vpninfo->token_tries++;
opt->value = strdup(tokencode);
if (vpninfo->unlock_token) {
char *new_tok = regen_hotp_secret(vpninfo);
vpninfo->unlock_token(vpninfo->tok_cbdata, new_tok);
free(new_tok);
}
return opt->value ? 0 : -ENOMEM;
}
#endif /* HAVE_LIBOATH */

/* Return value:
* < 0, if unable to generate a tokencode
* = 0, on success
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Expand Up @@ -630,6 +630,7 @@ AS_IF([test "x$with_liboath" != "xno"], [
libpskc_pkg=no)
fi
])
AM_CONDITIONAL(OPENCONNECT_OATH, [test "$liboath_pkg" = "yes"])

linked_gssapi=no
AC_ARG_WITH([gssapi],
Expand Down

0 comments on commit 6f0ee16

Please sign in to comment.