diff --git a/bin/otpkey/otpkey.c b/bin/otpkey/otpkey.c index a4fb71a..248958c 100644 --- a/bin/otpkey/otpkey.c +++ b/bin/otpkey/otpkey.c @@ -45,6 +45,7 @@ #include #include +#include #include #define MAX_KEYURI_SIZE 4096 @@ -267,7 +268,7 @@ otpkey_verify(int argc, char *argv[]) { oath_key key; unsigned long counter; - unsigned int response; + unsigned long response; char *end; int match, ret; @@ -278,27 +279,18 @@ otpkey_verify(int argc, char *argv[]) response = strtoul(*argv, &end, 10); if (end == *argv || *end != '\0') response = UINT_MAX; /* never valid */ - switch (key.mode) { - case om_hotp: + if (key.mode == om_hotp) counter = key.counter; - match = oath_hotp_match(&key, response, HOTP_WINDOW); - if (verbose && match > 0 && key.counter > counter + 1) - warnx("skipped %lu codes", key.counter - counter - 1); - break; - case om_totp: - match = oath_totp_match(&key, response, TOTP_WINDOW); - break; - default: - match = -1; - } - /* oath_*_match() return -1 on error, 0 on failure, 1 on success */ + match = otp_verify(&key, response); if (match < 0) { warnx("OATH error"); match = 0; } - if (verbose) - warnx("response: %u %s", response, - match ? "matched" : "did not match"); + if (verbose) { + warnx("response %s", match ? "matched" : "did not match"); + if (key.mode == om_hotp && key.counter > counter + 1) + warnx("skipped %lu codes", key.counter - counter - 1); + } ret = match ? readonly ? RET_SUCCESS : otpkey_save(&key) : RET_FAILURE; oath_key_destroy(&key); return (ret); @@ -365,7 +357,7 @@ otpkey_resync(int argc, char *argv[]) { oath_key key; unsigned long counter; - unsigned int response[3]; + unsigned long response[3]; char *end; int i, match, n, ret, w; @@ -381,31 +373,18 @@ otpkey_resync(int argc, char *argv[]) w -= n; if ((ret = otpkey_load(&key)) != RET_SUCCESS) return (ret); - switch (key.mode) { - case om_hotp: - /* this should be a library function */ + if (key.mode == om_hotp) counter = key.counter; - match = 0; - while (key.counter < counter + w && match == 0) { - match = oath_hotp_match(&key, response[0], - counter + w - key.counter - 1); - if (match <= 0) - break; - for (i = 1; i < n && match > 0; ++i) - match = oath_hotp_match(&key, response[i], 0); - } - if (verbose && match > 0) - warnx("skipped %lu codes", key.counter - counter); - break; - default: - match = -1; - } + match = otp_resync(&key, response, n); if (match < 0) { warnx("OATH error"); match = 0; } - if (verbose) + if (verbose) { warnx("resynchronization %s", match ? "succeeded" : "failed"); + if (counter > key.counter + 1) + warnx("skipped %lu codes", key.counter - counter); + } ret = match ? readonly ? RET_SUCCESS : otpkey_save(&key) : RET_FAILURE; oath_key_destroy(&key); return (ret); diff --git a/include/cryb/otp.h b/include/cryb/otp.h index 1c6640d..c01d35f 100644 --- a/include/cryb/otp.h +++ b/include/cryb/otp.h @@ -38,6 +38,12 @@ CRYB_BEGIN const char *cryb_otp_version(void); +#define otp_verify cryb_otp_verify +#define otp_resync cryb_otp_resync + +int otp_verify(oath_key *, unsigned long); +int otp_resync(oath_key *, unsigned long *, unsigned int); + CRYB_END #endif diff --git a/lib/otp/Makefile.am b/lib/otp/Makefile.am index 5071656..4c96426 100644 --- a/lib/otp/Makefile.am +++ b/lib/otp/Makefile.am @@ -3,6 +3,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/include lib_LTLIBRARIES = libcryb-otp.la libcryb_otp_la_SOURCES = \ + cryb_otp_resync.c \ + cryb_otp_verify.c \ \ cryb_otp.c diff --git a/lib/otp/cryb_otp.c b/lib/otp/cryb_otp.c index bbf491a..7182120 100644 --- a/lib/otp/cryb_otp.c +++ b/lib/otp/cryb_otp.c @@ -29,9 +29,10 @@ #include "cryb/impl.h" +#include #include -#include +#include #include static const char *cryb_otp_version_string = PACKAGE_VERSION; diff --git a/lib/otp/cryb_otp_impl.h b/lib/otp/cryb_otp_impl.h new file mode 100644 index 0000000..9459bd6 --- /dev/null +++ b/lib/otp/cryb_otp_impl.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2018 The University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CRYB_OTP_IMPL_H_INCLUDED +#define CRYB_OTP_IMPL_H_INCLUDED + +/* XXX hardcoded windows */ +#define HOTP_WINDOW 9 +#define TOTP_WINDOW 2 + +struct otp_store { +}; + +#endif diff --git a/lib/otp/cryb_otp_resync.c b/lib/otp/cryb_otp_resync.c new file mode 100644 index 0000000..8d95c19 --- /dev/null +++ b/lib/otp/cryb_otp_resync.c @@ -0,0 +1,96 @@ +/*- + * Copyright (c) 2013-2018 The University of Oslo + * Copyright (c) 2016-2018 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cryb/impl.h" + +#include +#include + +#include +#include +#include + +#include "cryb_otp_impl.h" + +/* + * Resynchronize a desynchronized event-mode key. + * + * XXX review carefully for off-by-one errors, and write unit tests + */ + +static int +otp_resync_recursive(oath_key *key, unsigned long *response, + unsigned int n, unsigned int w) +{ + uint64_t first, prev, last; + int ret; + + first = key->counter; + last = first + w; + while (w > 0) { + prev = key->counter; + ret = oath_hotp_match(key, response[0], last - key->counter); + if (ret < 1) + return (ret); + assertf(key->counter > prev, "counter did not advance"); + w -= key->counter - prev; + if (n == 1) + return (key->counter - prev); + prev = key->counter; + ret = otp_resync_recursive(key, response + 1, n - 1, w); + if (ret > 0) + return (ret); + key->counter = prev; + } + return (0); +} + +int +otp_resync(oath_key *key, unsigned long *response, unsigned int n) +{ + unsigned int i, w; + int ret; + + /* only applicable to RFC 4226 HOTP for now */ + /* note: n == 1 is identical to otp_verify() */ + if (key->mode != om_hotp || n < 1) + return (-1); + + /* compute window size based on number of responses */ + for (i = 0, w = 1; i < n; ++i) + w = w * (HOTP_WINDOW + 1); + + /* recursive search within window */ + ret = otp_resync_recursive(key, response, n, w); + + /* ... */ + + return (ret); +} diff --git a/lib/otp/cryb_otp_verify.c b/lib/otp/cryb_otp_verify.c new file mode 100644 index 0000000..de1e1c3 --- /dev/null +++ b/lib/otp/cryb_otp_verify.c @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 2013-2018 The University of Oslo + * Copyright (c) 2016-2018 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cryb/impl.h" + +#include +#include + +#include +#include +#include + +#include "cryb_otp_impl.h" + +/* + * Check whether a given response is correct for the given keyfile. + */ +int +otp_verify(oath_key *key, unsigned long response) +{ + uint64_t prev; + int ret; + + switch (key->mode) { + case om_hotp: + prev = key->counter; + ret = oath_hotp_match(key, response, HOTP_WINDOW); + assertf(key->counter >= prev, "counter went backwads"); + if (ret > 0) { + assertf(key->counter > prev, "counter did not advance"); + ret = key->counter - prev - 1; + } + break; + case om_totp: + prev = key->lastused; + ret = oath_totp_match(key, response, TOTP_WINDOW); + assertf(key->lastused >= prev, "lastused went backwards"); + if (ret > 0) { + assertf(key->lastused > prev, "lastused did not advance"); + ret = key->lastused - prev / key->timestep; + } + break; + default: + ret = -1; + } + /* oath_*_ret() return -1 on error, 0 on failure, 1 on success */ + return (ret); +} diff --git a/libexec/login_otp/login_otp.c b/libexec/login_otp/login_otp.c index 4de4b5a..bbc38b8 100644 --- a/libexec/login_otp/login_otp.c +++ b/libexec/login_otp/login_otp.c @@ -33,6 +33,7 @@ #include #include +#include #include static void diff --git a/pam/pam_otp/pam_otp.c b/pam/pam_otp/pam_otp.c index 3597fbc..147f776 100644 --- a/pam/pam_otp/pam_otp.c +++ b/pam/pam_otp/pam_otp.c @@ -36,6 +36,7 @@ #include #include +#include #include int diff --git a/sbin/otpradiusd/otpradiusd.c b/sbin/otpradiusd/otpradiusd.c index 491ec3c..ace58c8 100644 --- a/sbin/otpradiusd/otpradiusd.c +++ b/sbin/otpradiusd/otpradiusd.c @@ -33,6 +33,7 @@ #include #include +#include #include static void