Create a nooath branch as a copy of trunk@713 with the OATH code removed.
git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/branches/nooath@714 185d5e19-27fe-0310-9dcf-9bff6b9f3609
This commit is contained in:
parent
bcafac75c2
commit
efcf4a9ec6
3
HISTORY
3
HISTORY
|
@ -1,8 +1,5 @@
|
|||
OpenPAM ?????????? 2013-??-??
|
||||
|
||||
- FEATURE: Add a pam_oath module that implements RFC 4226 (HOTP) and
|
||||
RFC 6238 (TOTP).
|
||||
|
||||
- ENHANCE: Rewrite the dynamic loader to improve readability and
|
||||
reliability. Modules can now be listed without the ".so" suffix in
|
||||
the policy file; OpenPAM will automatically add it, just like it
|
||||
|
|
5
RELNOTES
5
RELNOTES
|
@ -17,11 +17,6 @@ The distribution consists of the following components:
|
|||
- A test application (pamtest) which can be used to test policies and
|
||||
modules.
|
||||
|
||||
- A library which implements the OATH one-time password algorithms,
|
||||
with complete API documentation.
|
||||
|
||||
- A PAM module which implements OATH-based authentication.
|
||||
|
||||
- Unit tests for limited portions of the libraries.
|
||||
|
||||
Please direct bug reports and inquiries to <des@des.no>.
|
||||
|
|
5
TODO
5
TODO
|
@ -1,8 +1,5 @@
|
|||
Before the next release:
|
||||
|
||||
- Add oath_alloc_secure() which allocates memory using mmap() +
|
||||
mlock() and oath_free_secure() which wipes and frees it.
|
||||
|
||||
- Rewrite openpam_ttyconv(3).
|
||||
- mostly done, needs review.
|
||||
|
||||
|
@ -10,8 +7,6 @@ Before the next release:
|
|||
documentation are slightly incorrect, OpenPAM's pam_unix(8) is
|
||||
incorrect, all FreeBSD modules are broken)
|
||||
|
||||
- Finish pam_oath(8) and oathkey(1).
|
||||
|
||||
- Add loop detection to openpam_load_chain().
|
||||
|
||||
$Id$
|
||||
|
|
|
@ -11,7 +11,6 @@ set -ex
|
|||
export CONFIG_SHELL=/bin/sh
|
||||
|
||||
./configure \
|
||||
--with-oath \
|
||||
--with-doc \
|
||||
--with-pam-unix \
|
||||
--with-pamtest \
|
||||
|
|
10
configure.ac
10
configure.ac
|
@ -2,7 +2,7 @@ dnl $Id$
|
|||
|
||||
AC_PREREQ([2.62])
|
||||
AC_REVISION([$Id$])
|
||||
AC_INIT([OpenPAM], [trunk], [des@des.no], [openpam], [http://www.openpam.org/])
|
||||
AC_INIT([OpenPAM], [nooath], [des@des.no], [openpam], [http://www.openpam.org/])
|
||||
AC_CONFIG_SRCDIR([lib/libpam/pam_start.c])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
|
@ -67,12 +67,6 @@ AC_ARG_WITH([pam-unix],
|
|||
[with_pam_unix=no])
|
||||
AM_CONDITIONAL([WITH_PAM_UNIX], [test x"$with_pam_unix" = x"yes"])
|
||||
|
||||
AC_ARG_WITH([oath],
|
||||
AC_HELP_STRING([--with-oath], [compile OATH library, module and utility]),
|
||||
[],
|
||||
[with_oath=no])
|
||||
AM_CONDITIONAL([WITH_OATH], [test x"$with_oath" = x"yes"])
|
||||
|
||||
AC_ARG_WITH(pamtest,
|
||||
AC_HELP_STRING([--with-pamtest], [compile test application]),
|
||||
[],
|
||||
|
@ -135,13 +129,11 @@ AC_CONFIG_FILES([
|
|||
include/Makefile
|
||||
include/security/Makefile
|
||||
lib/Makefile
|
||||
lib/liboath/Makefile
|
||||
lib/libpam/Makefile
|
||||
modules/Makefile
|
||||
modules/pam_deny/Makefile
|
||||
modules/pam_permit/Makefile
|
||||
modules/pam_unix/Makefile
|
||||
modules/pam_oath/Makefile
|
||||
t/Makefile
|
||||
])
|
||||
AC_CONFIG_FILES([pamgdb],[chmod +x pamgdb])
|
||||
|
|
1179
doc/rfc/rfc1321.txt
1179
doc/rfc/rfc1321.txt
File diff suppressed because it is too large
Load Diff
|
@ -1,619 +0,0 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group H. Krawczyk
|
||||
Request for Comments: 2104 IBM
|
||||
Category: Informational M. Bellare
|
||||
UCSD
|
||||
R. Canetti
|
||||
IBM
|
||||
February 1997
|
||||
|
||||
|
||||
HMAC: Keyed-Hashing for Message Authentication
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This memo provides information for the Internet community. This memo
|
||||
does not specify an Internet standard of any kind. Distribution of
|
||||
this memo is unlimited.
|
||||
|
||||
Abstract
|
||||
|
||||
This document describes HMAC, a mechanism for message authentication
|
||||
using cryptographic hash functions. HMAC can be used with any
|
||||
iterative cryptographic hash function, e.g., MD5, SHA-1, in
|
||||
combination with a secret shared key. The cryptographic strength of
|
||||
HMAC depends on the properties of the underlying hash function.
|
||||
|
||||
1. Introduction
|
||||
|
||||
Providing a way to check the integrity of information transmitted
|
||||
over or stored in an unreliable medium is a prime necessity in the
|
||||
world of open computing and communications. Mechanisms that provide
|
||||
such integrity check based on a secret key are usually called
|
||||
"message authentication codes" (MAC). Typically, message
|
||||
authentication codes are used between two parties that share a secret
|
||||
key in order to validate information transmitted between these
|
||||
parties. In this document we present such a MAC mechanism based on
|
||||
cryptographic hash functions. This mechanism, called HMAC, is based
|
||||
on work by the authors [BCK1] where the construction is presented and
|
||||
cryptographically analyzed. We refer to that work for the details on
|
||||
the rationale and security analysis of HMAC, and its comparison to
|
||||
other keyed-hash methods.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 1]
|
||||
|
||||
RFC 2104 HMAC February 1997
|
||||
|
||||
|
||||
HMAC can be used in combination with any iterated cryptographic hash
|
||||
function. MD5 and SHA-1 are examples of such hash functions. HMAC
|
||||
also uses a secret key for calculation and verification of the
|
||||
message authentication values. The main goals behind this
|
||||
construction are
|
||||
|
||||
* To use, without modifications, available hash functions.
|
||||
In particular, hash functions that perform well in software,
|
||||
and for which code is freely and widely available.
|
||||
|
||||
* To preserve the original performance of the hash function without
|
||||
incurring a significant degradation.
|
||||
|
||||
* To use and handle keys in a simple way.
|
||||
|
||||
* To have a well understood cryptographic analysis of the strength of
|
||||
the authentication mechanism based on reasonable assumptions on the
|
||||
underlying hash function.
|
||||
|
||||
* To allow for easy replaceability of the underlying hash function in
|
||||
case that faster or more secure hash functions are found or
|
||||
required.
|
||||
|
||||
This document specifies HMAC using a generic cryptographic hash
|
||||
function (denoted by H). Specific instantiations of HMAC need to
|
||||
define a particular hash function. Current candidates for such hash
|
||||
functions include SHA-1 [SHA], MD5 [MD5], RIPEMD-128/160 [RIPEMD].
|
||||
These different realizations of HMAC will be denoted by HMAC-SHA1,
|
||||
HMAC-MD5, HMAC-RIPEMD, etc.
|
||||
|
||||
Note: To the date of writing of this document MD5 and SHA-1 are the
|
||||
most widely used cryptographic hash functions. MD5 has been recently
|
||||
shown to be vulnerable to collision search attacks [Dobb]. This
|
||||
attack and other currently known weaknesses of MD5 do not compromise
|
||||
the use of MD5 within HMAC as specified in this document (see
|
||||
[Dobb]); however, SHA-1 appears to be a cryptographically stronger
|
||||
function. To this date, MD5 can be considered for use in HMAC for
|
||||
applications where the superior performance of MD5 is critical. In
|
||||
any case, implementers and users need to be aware of possible
|
||||
cryptanalytic developments regarding any of these cryptographic hash
|
||||
functions, and the eventual need to replace the underlying hash
|
||||
function. (See section 6 for more information on the security of
|
||||
HMAC.)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 2]
|
||||
|
||||
RFC 2104 HMAC February 1997
|
||||
|
||||
|
||||
2. Definition of HMAC
|
||||
|
||||
The definition of HMAC requires a cryptographic hash function, which
|
||||
we denote by H, and a secret key K. We assume H to be a cryptographic
|
||||
hash function where data is hashed by iterating a basic compression
|
||||
function on blocks of data. We denote by B the byte-length of such
|
||||
blocks (B=64 for all the above mentioned examples of hash functions),
|
||||
and by L the byte-length of hash outputs (L=16 for MD5, L=20 for
|
||||
SHA-1). The authentication key K can be of any length up to B, the
|
||||
block length of the hash function. Applications that use keys longer
|
||||
than B bytes will first hash the key using H and then use the
|
||||
resultant L byte string as the actual key to HMAC. In any case the
|
||||
minimal recommended length for K is L bytes (as the hash output
|
||||
length). See section 3 for more information on keys.
|
||||
|
||||
We define two fixed and different strings ipad and opad as follows
|
||||
(the 'i' and 'o' are mnemonics for inner and outer):
|
||||
|
||||
ipad = the byte 0x36 repeated B times
|
||||
opad = the byte 0x5C repeated B times.
|
||||
|
||||
To compute HMAC over the data `text' we perform
|
||||
|
||||
H(K XOR opad, H(K XOR ipad, text))
|
||||
|
||||
Namely,
|
||||
|
||||
(1) append zeros to the end of K to create a B byte string
|
||||
(e.g., if K is of length 20 bytes and B=64, then K will be
|
||||
appended with 44 zero bytes 0x00)
|
||||
(2) XOR (bitwise exclusive-OR) the B byte string computed in step
|
||||
(1) with ipad
|
||||
(3) append the stream of data 'text' to the B byte string resulting
|
||||
from step (2)
|
||||
(4) apply H to the stream generated in step (3)
|
||||
(5) XOR (bitwise exclusive-OR) the B byte string computed in
|
||||
step (1) with opad
|
||||
(6) append the H result from step (4) to the B byte string
|
||||
resulting from step (5)
|
||||
(7) apply H to the stream generated in step (6) and output
|
||||
the result
|
||||
|
||||
For illustration purposes, sample code based on MD5 is provided as an
|
||||
appendix.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 3]
|
||||
|
||||
RFC 2104 HMAC February 1997
|
||||
|
||||
|
||||
3. Keys
|
||||
|
||||
The key for HMAC can be of any length (keys longer than B bytes are
|
||||
first hashed using H). However, less than L bytes is strongly
|
||||
discouraged as it would decrease the security strength of the
|
||||
function. Keys longer than L bytes are acceptable but the extra
|
||||
length would not significantly increase the function strength. (A
|
||||
longer key may be advisable if the randomness of the key is
|
||||
considered weak.)
|
||||
|
||||
Keys need to be chosen at random (or using a cryptographically strong
|
||||
pseudo-random generator seeded with a random seed), and periodically
|
||||
refreshed. (Current attacks do not indicate a specific recommended
|
||||
frequency for key changes as these attacks are practically
|
||||
infeasible. However, periodic key refreshment is a fundamental
|
||||
security practice that helps against potential weaknesses of the
|
||||
function and keys, and limits the damage of an exposed key.)
|
||||
|
||||
4. Implementation Note
|
||||
|
||||
HMAC is defined in such a way that the underlying hash function H can
|
||||
be used with no modification to its code. In particular, it uses the
|
||||
function H with the pre-defined initial value IV (a fixed value
|
||||
specified by each iterative hash function to initialize its
|
||||
compression function). However, if desired, a performance
|
||||
improvement can be achieved at the cost of (possibly) modifying the
|
||||
code of H to support variable IVs.
|
||||
|
||||
The idea is that the intermediate results of the compression function
|
||||
on the B-byte blocks (K XOR ipad) and (K XOR opad) can be precomputed
|
||||
only once at the time of generation of the key K, or before its first
|
||||
use. These intermediate results are stored and then used to
|
||||
initialize the IV of H each time that a message needs to be
|
||||
authenticated. This method saves, for each authenticated message,
|
||||
the application of the compression function of H on two B-byte blocks
|
||||
(i.e., on (K XOR ipad) and (K XOR opad)). Such a savings may be
|
||||
significant when authenticating short streams of data. We stress
|
||||
that the stored intermediate values need to be treated and protected
|
||||
the same as secret keys.
|
||||
|
||||
Choosing to implement HMAC in the above way is a decision of the
|
||||
local implementation and has no effect on inter-operability.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 4]
|
||||
|
||||
RFC 2104 HMAC February 1997
|
||||
|
||||
|
||||
5. Truncated output
|
||||
|
||||
A well-known practice with message authentication codes is to
|
||||
truncate the output of the MAC and output only part of the bits
|
||||
(e.g., [MM, ANSI]). Preneel and van Oorschot [PV] show some
|
||||
analytical advantages of truncating the output of hash-based MAC
|
||||
functions. The results in this area are not absolute as for the
|
||||
overall security advantages of truncation. It has advantages (less
|
||||
information on the hash result available to an attacker) and
|
||||
disadvantages (less bits to predict for the attacker). Applications
|
||||
of HMAC can choose to truncate the output of HMAC by outputting the t
|
||||
leftmost bits of the HMAC computation for some parameter t (namely,
|
||||
the computation is carried in the normal way as defined in section 2
|
||||
above but the end result is truncated to t bits). We recommend that
|
||||
the output length t be not less than half the length of the hash
|
||||
output (to match the birthday attack bound) and not less than 80 bits
|
||||
(a suitable lower bound on the number of bits that need to be
|
||||
predicted by an attacker). We propose denoting a realization of HMAC
|
||||
that uses a hash function H with t bits of output as HMAC-H-t. For
|
||||
example, HMAC-SHA1-80 denotes HMAC computed using the SHA-1 function
|
||||
and with the output truncated to 80 bits. (If the parameter t is not
|
||||
specified, e.g. HMAC-MD5, then it is assumed that all the bits of the
|
||||
hash are output.)
|
||||
|
||||
6. Security
|
||||
|
||||
The security of the message authentication mechanism presented here
|
||||
depends on cryptographic properties of the hash function H: the
|
||||
resistance to collision finding (limited to the case where the
|
||||
initial value is secret and random, and where the output of the
|
||||
function is not explicitly available to the attacker), and the
|
||||
message authentication property of the compression function of H when
|
||||
applied to single blocks (in HMAC these blocks are partially unknown
|
||||
to an attacker as they contain the result of the inner H computation
|
||||
and, in particular, cannot be fully chosen by the attacker).
|
||||
|
||||
These properties, and actually stronger ones, are commonly assumed
|
||||
for hash functions of the kind used with HMAC. In particular, a hash
|
||||
function for which the above properties do not hold would become
|
||||
unsuitable for most (probably, all) cryptographic applications,
|
||||
including alternative message authentication schemes based on such
|
||||
functions. (For a complete analysis and rationale of the HMAC
|
||||
function the reader is referred to [BCK1].)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 5]
|
||||
|
||||
RFC 2104 HMAC February 1997
|
||||
|
||||
|
||||
Given the limited confidence gained so far as for the cryptographic
|
||||
strength of candidate hash functions, it is important to observe the
|
||||
following two properties of the HMAC construction and its secure use
|
||||
for message authentication:
|
||||
|
||||
1. The construction is independent of the details of the particular
|
||||
hash function H in use and then the latter can be replaced by any
|
||||
other secure (iterative) cryptographic hash function.
|
||||
|
||||
2. Message authentication, as opposed to encryption, has a
|
||||
"transient" effect. A published breaking of a message authentication
|
||||
scheme would lead to the replacement of that scheme, but would have
|
||||
no adversarial effect on information authenticated in the past. This
|
||||
is in sharp contrast with encryption, where information encrypted
|
||||
today may suffer from exposure in the future if, and when, the
|
||||
encryption algorithm is broken.
|
||||
|
||||
The strongest attack known against HMAC is based on the frequency of
|
||||
collisions for the hash function H ("birthday attack") [PV,BCK2], and
|
||||
is totally impractical for minimally reasonable hash functions.
|
||||
|
||||
As an example, if we consider a hash function like MD5 where the
|
||||
output length equals L=16 bytes (128 bits) the attacker needs to
|
||||
acquire the correct message authentication tags computed (with the
|
||||
_same_ secret key K!) on about 2**64 known plaintexts. This would
|
||||
require the processing of at least 2**64 blocks under H, an
|
||||
impossible task in any realistic scenario (for a block length of 64
|
||||
bytes this would take 250,000 years in a continuous 1Gbps link, and
|
||||
without changing the secret key K during all this time). This attack
|
||||
could become realistic only if serious flaws in the collision
|
||||
behavior of the function H are discovered (e.g. collisions found
|
||||
after 2**30 messages). Such a discovery would determine the immediate
|
||||
replacement of the function H (the effects of such failure would be
|
||||
far more severe for the traditional uses of H in the context of
|
||||
digital signatures, public key certificates, etc.).
|
||||
|
||||
Note: this attack needs to be strongly contrasted with regular
|
||||
collision attacks on cryptographic hash functions where no secret key
|
||||
is involved and where 2**64 off-line parallelizable (!) operations
|
||||
suffice to find collisions. The latter attack is approaching
|
||||
feasibility [VW] while the birthday attack on HMAC is totally
|
||||
impractical. (In the above examples, if one uses a hash function
|
||||
with, say, 160 bit of output then 2**64 should be replaced by 2**80.)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 6]
|
||||
|
||||
RFC 2104 HMAC February 1997
|
||||
|
||||
|
||||
A correct implementation of the above construction, the choice of
|
||||
random (or cryptographically pseudorandom) keys, a secure key
|
||||
exchange mechanism, frequent key refreshments, and good secrecy
|
||||
protection of keys are all essential ingredients for the security of
|
||||
the integrity verification mechanism provided by HMAC.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 7]
|
||||
|
||||
RFC 2104 HMAC February 1997
|
||||
|
||||
|
||||
Appendix -- Sample Code
|
||||
|
||||
For the sake of illustration we provide the following sample code for
|
||||
the implementation of HMAC-MD5 as well as some corresponding test
|
||||
vectors (the code is based on MD5 code as described in [MD5]).
|
||||
|
||||
/*
|
||||
** Function: hmac_md5
|
||||
*/
|
||||
|
||||
void
|
||||
hmac_md5(text, text_len, key, key_len, digest)
|
||||
unsigned char* text; /* pointer to data stream */
|
||||
int text_len; /* length of data stream */
|
||||
unsigned char* key; /* pointer to authentication key */
|
||||
int key_len; /* length of authentication key */
|
||||
caddr_t digest; /* caller digest to be filled in */
|
||||
|
||||
{
|
||||
MD5_CTX context;
|
||||
unsigned char k_ipad[65]; /* inner padding -
|
||||
* key XORd with ipad
|
||||
*/
|
||||
unsigned char k_opad[65]; /* outer padding -
|
||||
* key XORd with opad
|
||||
*/
|
||||
unsigned char tk[16];
|
||||
int i;
|
||||
/* if key is longer than 64 bytes reset it to key=MD5(key) */
|
||||
if (key_len > 64) {
|
||||
|
||||
MD5_CTX tctx;
|
||||
|
||||
MD5Init(&tctx);
|
||||
MD5Update(&tctx, key, key_len);
|
||||
MD5Final(tk, &tctx);
|
||||
|
||||
key = tk;
|
||||
key_len = 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* the HMAC_MD5 transform looks like:
|
||||
*
|
||||
* MD5(K XOR opad, MD5(K XOR ipad, text))
|
||||
*
|
||||
* where K is an n byte key
|
||||
* ipad is the byte 0x36 repeated 64 times
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 8]
|
||||
|
||||
RFC 2104 HMAC February 1997
|
||||
|
||||
|
||||
* opad is the byte 0x5c repeated 64 times
|
||||
* and text is the data being protected
|
||||
*/
|
||||
|
||||
/* start out by storing key in pads */
|
||||
bzero( k_ipad, sizeof k_ipad);
|
||||
bzero( k_opad, sizeof k_opad);
|
||||
bcopy( key, k_ipad, key_len);
|
||||
bcopy( key, k_opad, key_len);
|
||||
|
||||
/* XOR key with ipad and opad values */
|
||||
for (i=0; i<64; i++) {
|
||||
k_ipad[i] ^= 0x36;
|
||||
k_opad[i] ^= 0x5c;
|
||||
}
|
||||
/*
|
||||
* perform inner MD5
|
||||
*/
|
||||
MD5Init(&context); /* init context for 1st
|
||||
* pass */
|
||||
MD5Update(&context, k_ipad, 64) /* start with inner pad */
|
||||
MD5Update(&context, text, text_len); /* then text of datagram */
|
||||
MD5Final(digest, &context); /* finish up 1st pass */
|
||||
/*
|
||||
* perform outer MD5
|
||||
*/
|
||||
MD5Init(&context); /* init context for 2nd
|
||||
* pass */
|
||||
MD5Update(&context, k_opad, 64); /* start with outer pad */
|
||||
MD5Update(&context, digest, 16); /* then results of 1st
|
||||
* hash */
|
||||
MD5Final(digest, &context); /* finish up 2nd pass */
|
||||
}
|
||||
|
||||
Test Vectors (Trailing '\0' of a character string not included in test):
|
||||
|
||||
key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
|
||||
key_len = 16 bytes
|
||||
data = "Hi There"
|
||||
data_len = 8 bytes
|
||||
digest = 0x9294727a3638bb1c13f48ef8158bfc9d
|
||||
|
||||
key = "Jefe"
|
||||
data = "what do ya want for nothing?"
|
||||
data_len = 28 bytes
|
||||
digest = 0x750c783e6ab0b503eaa86e310a5db738
|
||||
|
||||
key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 9]
|
||||
|
||||
RFC 2104 HMAC February 1997
|
||||
|
||||
|
||||
key_len 16 bytes
|
||||
data = 0xDDDDDDDDDDDDDDDDDDDD...
|
||||
..DDDDDDDDDDDDDDDDDDDD...
|
||||
..DDDDDDDDDDDDDDDDDDDD...
|
||||
..DDDDDDDDDDDDDDDDDDDD...
|
||||
..DDDDDDDDDDDDDDDDDDDD
|
||||
data_len = 50 bytes
|
||||
digest = 0x56be34521d144c88dbb8c733f0e8b3f6
|
||||
|
||||
Acknowledgments
|
||||
|
||||
Pau-Chen Cheng, Jeff Kraemer, and Michael Oehler, have provided
|
||||
useful comments on early drafts, and ran the first interoperability
|
||||
tests of this specification. Jeff and Pau-Chen kindly provided the
|
||||
sample code and test vectors that appear in the appendix. Burt
|
||||
Kaliski, Bart Preneel, Matt Robshaw, Adi Shamir, and Paul van
|
||||
Oorschot have provided useful comments and suggestions during the
|
||||
investigation of the HMAC construction.
|
||||
|
||||
References
|
||||
|
||||
[ANSI] ANSI X9.9, "American National Standard for Financial
|
||||
Institution Message Authentication (Wholesale)," American
|
||||
Bankers Association, 1981. Revised 1986.
|
||||
|
||||
[Atk] Atkinson, R., "IP Authentication Header", RFC 1826, August
|
||||
1995.
|
||||
|
||||
[BCK1] M. Bellare, R. Canetti, and H. Krawczyk,
|
||||
"Keyed Hash Functions and Message Authentication",
|
||||
Proceedings of Crypto'96, LNCS 1109, pp. 1-15.
|
||||
(http://www.research.ibm.com/security/keyed-md5.html)
|
||||
|
||||
[BCK2] M. Bellare, R. Canetti, and H. Krawczyk,
|
||||
"Pseudorandom Functions Revisited: The Cascade Construction",
|
||||
Proceedings of FOCS'96.
|
||||
|
||||
[Dobb] H. Dobbertin, "The Status of MD5 After a Recent Attack",
|
||||
RSA Labs' CryptoBytes, Vol. 2 No. 2, Summer 1996.
|
||||
http://www.rsa.com/rsalabs/pubs/cryptobytes.html
|
||||
|
||||
[PV] B. Preneel and P. van Oorschot, "Building fast MACs from hash
|
||||
functions", Advances in Cryptology -- CRYPTO'95 Proceedings,
|
||||
Lecture Notes in Computer Science, Springer-Verlag Vol.963,
|
||||
1995, pp. 1-14.
|
||||
|
||||
[MD5] Rivest, R., "The MD5 Message-Digest Algorithm",
|
||||
RFC 1321, April 1992.
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 10]
|
||||
|
||||
RFC 2104 HMAC February 1997
|
||||
|
||||
|
||||
[MM] Meyer, S. and Matyas, S.M., Cryptography, New York Wiley,
|
||||
1982.
|
||||
|
||||
[RIPEMD] H. Dobbertin, A. Bosselaers, and B. Preneel, "RIPEMD-160: A
|
||||
strengthened version of RIPEMD", Fast Software Encryption,
|
||||
LNCS Vol 1039, pp. 71-82.
|
||||
ftp://ftp.esat.kuleuven.ac.be/pub/COSIC/bosselae/ripemd/.
|
||||
|
||||
[SHA] NIST, FIPS PUB 180-1: Secure Hash Standard, April 1995.
|
||||
|
||||
[Tsu] G. Tsudik, "Message authentication with one-way hash
|
||||
functions", In Proceedings of Infocom'92, May 1992.
|
||||
(Also in "Access Control and Policy Enforcement in
|
||||
Internetworks", Ph.D. Dissertation, Computer Science
|
||||
Department, University of Southern California, April 1991.)
|
||||
|
||||
[VW] P. van Oorschot and M. Wiener, "Parallel Collision
|
||||
Search with Applications to Hash Functions and Discrete
|
||||
Logarithms", Proceedings of the 2nd ACM Conf. Computer and
|
||||
Communications Security, Fairfax, VA, November 1994.
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
Hugo Krawczyk
|
||||
IBM T.J. Watson Research Center
|
||||
P.O.Box 704
|
||||
Yorktown Heights, NY 10598
|
||||
|
||||
EMail: hugo@watson.ibm.com
|
||||
|
||||
Mihir Bellare
|
||||
Dept of Computer Science and Engineering
|
||||
Mail Code 0114
|
||||
University of California at San Diego
|
||||
9500 Gilman Drive
|
||||
La Jolla, CA 92093
|
||||
|
||||
EMail: mihir@cs.ucsd.edu
|
||||
|
||||
Ran Canetti
|
||||
IBM T.J. Watson Research Center
|
||||
P.O.Box 704
|
||||
Yorktown Heights, NY 10598
|
||||
|
||||
EMail: canetti@watson.ibm.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Krawczyk, et. al. Informational [Page 11]
|
||||
|
2075
doc/rfc/rfc4226.txt
2075
doc/rfc/rfc4226.txt
File diff suppressed because it is too large
Load Diff
1011
doc/rfc/rfc4648.txt
1011
doc/rfc/rfc4648.txt
File diff suppressed because it is too large
Load Diff
7115
doc/rfc/rfc6234.txt
7115
doc/rfc/rfc6234.txt
File diff suppressed because it is too large
Load Diff
|
@ -1,899 +0,0 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Internet Engineering Task Force (IETF) D. M'Raihi
|
||||
Request for Comments: 6238 Verisign, Inc.
|
||||
Category: Informational S. Machani
|
||||
ISSN: 2070-1721 Diversinet Corp.
|
||||
M. Pei
|
||||
Symantec
|
||||
J. Rydell
|
||||
Portwise, Inc.
|
||||
May 2011
|
||||
|
||||
|
||||
TOTP: Time-Based One-Time Password Algorithm
|
||||
|
||||
Abstract
|
||||
|
||||
This document describes an extension of the One-Time Password (OTP)
|
||||
algorithm, namely the HMAC-based One-Time Password (HOTP) algorithm,
|
||||
as defined in RFC 4226, to support the time-based moving factor. The
|
||||
HOTP algorithm specifies an event-based OTP algorithm, where the
|
||||
moving factor is an event counter. The present work bases the moving
|
||||
factor on a time value. A time-based variant of the OTP algorithm
|
||||
provides short-lived OTP values, which are desirable for enhanced
|
||||
security.
|
||||
|
||||
The proposed algorithm can be used across a wide range of network
|
||||
applications, from remote Virtual Private Network (VPN) access and
|
||||
Wi-Fi network logon to transaction-oriented Web applications. The
|
||||
authors believe that a common and shared algorithm will facilitate
|
||||
adoption of two-factor authentication on the Internet by enabling
|
||||
interoperability across commercial and open-source implementations.
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This document is not an Internet Standards Track specification; it is
|
||||
published for informational purposes.
|
||||
|
||||
This document is a product of the Internet Engineering Task Force
|
||||
(IETF). It represents the consensus of the IETF community. It has
|
||||
received public review and has been approved for publication by the
|
||||
Internet Engineering Steering Group (IESG). Not all documents
|
||||
approved by the IESG are a candidate for any level of Internet
|
||||
Standard; see Section 2 of RFC 5741.
|
||||
|
||||
Information about the current status of this document, any errata,
|
||||
and how to provide feedback on it may be obtained at
|
||||
http://www.rfc-editor.org/info/rfc6238.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 1]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (c) 2011 IETF Trust and the persons identified as the
|
||||
document authors. All rights reserved.
|
||||
|
||||
This document is subject to BCP 78 and the IETF Trust's Legal
|
||||
Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info) in effect on the date of
|
||||
publication of this document. Please review these documents
|
||||
carefully, as they describe your rights and restrictions with respect
|
||||
to this document. Code Components extracted from this document must
|
||||
include Simplified BSD License text as described in Section 4.e of
|
||||
the Trust Legal Provisions and are provided without warranty as
|
||||
described in the Simplified BSD License.
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction ....................................................2
|
||||
1.1. Scope ......................................................2
|
||||
1.2. Background .................................................3
|
||||
2. Notation and Terminology ........................................3
|
||||
3. Algorithm Requirements ..........................................3
|
||||
4. TOTP Algorithm ..................................................4
|
||||
4.1. Notations ..................................................4
|
||||
4.2. Description ................................................4
|
||||
5. Security Considerations .........................................5
|
||||
5.1. General ....................................................5
|
||||
5.2. Validation and Time-Step Size ..............................6
|
||||
6. Resynchronization ...............................................7
|
||||
7. Acknowledgements ................................................7
|
||||
8. References ......................................................8
|
||||
8.1. Normative References .......................................8
|
||||
8.2. Informative References .....................................8
|
||||
Appendix A. TOTP Algorithm: Reference Implementation ...............9
|
||||
Appendix B. Test Vectors ..........................................14
|
||||
|
||||
1. Introduction
|
||||
|
||||
1.1. Scope
|
||||
|
||||
This document describes an extension of the One-Time Password (OTP)
|
||||
algorithm, namely the HMAC-based One-Time Password (HOTP) algorithm,
|
||||
as defined in [RFC4226], to support the time-based moving factor.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 2]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
1.2. Background
|
||||
|
||||
As defined in [RFC4226], the HOTP algorithm is based on the
|
||||
HMAC-SHA-1 algorithm (as specified in [RFC2104]) and applied to an
|
||||
increasing counter value representing the message in the HMAC
|
||||
computation.
|
||||
|
||||
Basically, the output of the HMAC-SHA-1 calculation is truncated to
|
||||
obtain user-friendly values:
|
||||
|
||||
HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))
|
||||
|
||||
where Truncate represents the function that can convert an HMAC-SHA-1
|
||||
value into an HOTP value. K and C represent the shared secret and
|
||||
counter value; see [RFC4226] for detailed definitions.
|
||||
|
||||
TOTP is the time-based variant of this algorithm, where a value T,
|
||||
derived from a time reference and a time step, replaces the counter C
|
||||
in the HOTP computation.
|
||||
|
||||
TOTP implementations MAY use HMAC-SHA-256 or HMAC-SHA-512 functions,
|
||||
based on SHA-256 or SHA-512 [SHA2] hash functions, instead of the
|
||||
HMAC-SHA-1 function that has been specified for the HOTP computation
|
||||
in [RFC4226].
|
||||
|
||||
2. Notation and Terminology
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in [RFC2119].
|
||||
|
||||
3. Algorithm Requirements
|
||||
|
||||
This section summarizes the requirements taken into account for
|
||||
designing the TOTP algorithm.
|
||||
|
||||
R1: The prover (e.g., token, soft token) and verifier (authentication
|
||||
or validation server) MUST know or be able to derive the current
|
||||
Unix time (i.e., the number of seconds elapsed since midnight UTC
|
||||
of January 1, 1970) for OTP generation. See [UT] for a more
|
||||
detailed definition of the commonly known "Unix time". The
|
||||
precision of the time used by the prover affects how often the
|
||||
clock synchronization should be done; see Section 6.
|
||||
|
||||
R2: The prover and verifier MUST either share the same secret or the
|
||||
knowledge of a secret transformation to generate a shared secret.
|
||||
|
||||
R3: The algorithm MUST use HOTP [RFC4226] as a key building block.
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 3]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
R4: The prover and verifier MUST use the same time-step value X.
|
||||
|
||||
R5: There MUST be a unique secret (key) for each prover.
|
||||
|
||||
R6: The keys SHOULD be randomly generated or derived using key
|
||||
derivation algorithms.
|
||||
|
||||
R7: The keys MAY be stored in a tamper-resistant device and SHOULD be
|
||||
protected against unauthorized access and usage.
|
||||
|
||||
4. TOTP Algorithm
|
||||
|
||||
This variant of the HOTP algorithm specifies the calculation of a
|
||||
one-time password value, based on a representation of the counter as
|
||||
a time factor.
|
||||
|
||||
4.1. Notations
|
||||
|
||||
o X represents the time step in seconds (default value X =
|
||||
30 seconds) and is a system parameter.
|
||||
|
||||
o T0 is the Unix time to start counting time steps (default value is
|
||||
0, i.e., the Unix epoch) and is also a system parameter.
|
||||
|
||||
4.2. Description
|
||||
|
||||
Basically, we define TOTP as TOTP = HOTP(K, T), where T is an integer
|
||||
and represents the number of time steps between the initial counter
|
||||
time T0 and the current Unix time.
|
||||
|
||||
More specifically, T = (Current Unix time - T0) / X, where the
|
||||
default floor function is used in the computation.
|
||||
|
||||
For example, with T0 = 0 and Time Step X = 30, T = 1 if the current
|
||||
Unix time is 59 seconds, and T = 2 if the current Unix time is
|
||||
60 seconds.
|
||||
|
||||
The implementation of this algorithm MUST support a time value T
|
||||
larger than a 32-bit integer when it is beyond the year 2038. The
|
||||
value of the system parameters X and T0 are pre-established during
|
||||
the provisioning process and communicated between a prover and
|
||||
verifier as part of the provisioning step. The provisioning flow is
|
||||
out of scope of this document; refer to [RFC6030] for such
|
||||
provisioning container specifications.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 4]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
5. Security Considerations
|
||||
|
||||
5.1. General
|
||||
|
||||
The security and strength of this algorithm depend on the properties
|
||||
of the underlying building block HOTP, which is a construction based
|
||||
on HMAC [RFC2104] using SHA-1 as the hash function.
|
||||
|
||||
The conclusion of the security analysis detailed in [RFC4226] is
|
||||
that, for all practical purposes, the outputs of the dynamic
|
||||
truncation on distinct inputs are uniformly and independently
|
||||
distributed strings.
|
||||
|
||||
The analysis demonstrates that the best possible attack against the
|
||||
HOTP function is the brute force attack.
|
||||
|
||||
As indicated in the algorithm requirement section, keys SHOULD be
|
||||
chosen at random or using a cryptographically strong pseudorandom
|
||||
generator properly seeded with a random value.
|
||||
|
||||
Keys SHOULD be of the length of the HMAC output to facilitate
|
||||
interoperability.
|
||||
|
||||
We RECOMMEND following the recommendations in [RFC4086] for all
|
||||
pseudorandom and random number generations. The pseudorandom numbers
|
||||
used for generating the keys SHOULD successfully pass the randomness
|
||||
test specified in [CN], or a similar well-recognized test.
|
||||
|
||||
All the communications SHOULD take place over a secure channel, e.g.,
|
||||
Secure Socket Layer/Transport Layer Security (SSL/TLS) [RFC5246] or
|
||||
IPsec connections [RFC4301].
|
||||
|
||||
We also RECOMMEND storing the keys securely in the validation system,
|
||||
and, more specifically, encrypting them using tamper-resistant
|
||||
hardware encryption and exposing them only when required: for
|
||||
example, the key is decrypted when needed to verify an OTP value, and
|
||||
re-encrypted immediately to limit exposure in the RAM to a short
|
||||
period of time.
|
||||
|
||||
The key store MUST be in a secure area, to avoid, as much as
|
||||
possible, direct attack on the validation system and secrets
|
||||
database. Particularly, access to the key material should be limited
|
||||
to programs and processes required by the validation system only.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 5]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
5.2. Validation and Time-Step Size
|
||||
|
||||
An OTP generated within the same time step will be the same. When an
|
||||
OTP is received at a validation system, it doesn't know a client's
|
||||
exact timestamp when an OTP was generated. The validation system may
|
||||
typically use the timestamp when an OTP is received for OTP
|
||||
comparison. Due to network latency, the gap (as measured by T, that
|
||||
is, the number of time steps since T0) between the time that the OTP
|
||||
was generated and the time that the OTP arrives at the receiving
|
||||
system may be large. The receiving time at the validation system and
|
||||
the actual OTP generation may not fall within the same time-step
|
||||
window that produced the same OTP. When an OTP is generated at the
|
||||
end of a time-step window, the receiving time most likely falls into
|
||||
the next time-step window. A validation system SHOULD typically set
|
||||
a policy for an acceptable OTP transmission delay window for
|
||||
validation. The validation system should compare OTPs not only with
|
||||
the receiving timestamp but also the past timestamps that are within
|
||||
the transmission delay. A larger acceptable delay window would
|
||||
expose a larger window for attacks. We RECOMMEND that at most one
|
||||
time step is allowed as the network delay.
|
||||
|
||||
The time-step size has an impact on both security and usability. A
|
||||
larger time-step size means a larger validity window for an OTP to be
|
||||
accepted by a validation system. There are implications for using a
|
||||
larger time-step size, as follows:
|
||||
|
||||
First, a larger time-step size exposes a larger window to attack.
|
||||
When an OTP is generated and exposed to a third party before it is
|
||||
consumed, the third party can consume the OTP within the time-step
|
||||
window.
|
||||
|
||||
We RECOMMEND a default time-step size of 30 seconds. This default
|
||||
value of 30 seconds is selected as a balance between security and
|
||||
usability.
|
||||
|
||||
Second, the next different OTP must be generated in the next time-
|
||||
step window. A user must wait until the clock moves to the next
|
||||
time-step window from the last submission. The waiting time may not
|
||||
be exactly the length of the time step, depending on when the last
|
||||
OTP was generated. For example, if the last OTP was generated at the
|
||||
halfway point in a time-step window, the waiting time for the next
|
||||
OTP is half the length of the time step. In general, a larger time-
|
||||
step window means a longer waiting time for a user to get the next
|
||||
valid OTP after the last successful OTP validation. A too-large
|
||||
window (for example, 10 minutes) most probably won't be suitable for
|
||||
typical Internet login use cases; a user may not be able to get the
|
||||
next OTP within 10 minutes and therefore will have to re-login to the
|
||||
same site in 10 minutes.
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 6]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
Note that a prover may send the same OTP inside a given time-step
|
||||
window multiple times to a verifier. The verifier MUST NOT accept
|
||||
the second attempt of the OTP after the successful validation has
|
||||
been issued for the first OTP, which ensures one-time only use of an
|
||||
OTP.
|
||||
|
||||
6. Resynchronization
|
||||
|
||||
Because of possible clock drifts between a client and a validation
|
||||
server, we RECOMMEND that the validator be set with a specific limit
|
||||
to the number of time steps a prover can be "out of synch" before
|
||||
being rejected.
|
||||
|
||||
This limit can be set both forward and backward from the calculated
|
||||
time step on receipt of the OTP value. If the time step is
|
||||
30 seconds as recommended, and the validator is set to only accept
|
||||
two time steps backward, then the maximum elapsed time drift would be
|
||||
around 89 seconds, i.e., 29 seconds in the calculated time step and
|
||||
60 seconds for two backward time steps.
|
||||
|
||||
This would mean the validator could perform a validation against the
|
||||
current time and then two further validations for each backward step
|
||||
(for a total of 3 validations). Upon successful validation, the
|
||||
validation server can record the detected clock drift for the token
|
||||
in terms of the number of time steps. When a new OTP is received
|
||||
after this step, the validator can validate the OTP with the current
|
||||
timestamp adjusted with the recorded number of time-step clock drifts
|
||||
for the token.
|
||||
|
||||
Also, it is important to note that the longer a prover has not sent
|
||||
an OTP to a validation system, the longer (potentially) the
|
||||
accumulated clock drift between the prover and the verifier. In such
|
||||
cases, the automatic resynchronization described above may not work
|
||||
if the drift exceeds the allowed threshold. Additional
|
||||
authentication measures should be used to safely authenticate the
|
||||
prover and explicitly resynchronize the clock drift between the
|
||||
prover and the validator.
|
||||
|
||||
7. Acknowledgements
|
||||
|
||||
The authors of this document would like to thank the following people
|
||||
for their contributions and support to make this a better
|
||||
specification: Hannes Tschofenig, Jonathan Tuliani, David Dix,
|
||||
Siddharth Bajaj, Stu Veath, Shuh Chang, Oanh Hoang, John Huang, and
|
||||
Siddhartha Mohapatra.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 7]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
8. References
|
||||
|
||||
8.1. Normative References
|
||||
|
||||
[RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
|
||||
Hashing for Message Authentication", RFC 2104,
|
||||
February 1997.
|
||||
|
||||
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119, March 1997.
|
||||
|
||||
[RFC4086] Eastlake 3rd, D., Schiller, J., and S. Crocker,
|
||||
"Randomness Recommendations for Security", BCP 106,
|
||||
RFC 4086, June 2005.
|
||||
|
||||
[RFC4226] M'Raihi, D., Bellare, M., Hoornaert, F., Naccache, D., and
|
||||
O. Ranen, "HOTP: An HMAC-Based One-Time Password
|
||||
Algorithm", RFC 4226, December 2005.
|
||||
|
||||
[SHA2] NIST, "FIPS PUB 180-3: Secure Hash Standard (SHS)",
|
||||
October 2008, <http://csrc.nist.gov/publications/fips/
|
||||
fips180-3/fips180-3_final.pdf>.
|
||||
|
||||
8.2. Informative References
|
||||
|
||||
[CN] Coron, J. and D. Naccache, "An Accurate Evaluation of
|
||||
Maurer's Universal Test", LNCS 1556, February 1999,
|
||||
<http://www.gemplus.com/smart/rd/publications/pdf/
|
||||
CN99maur.pdf>.
|
||||
|
||||
[RFC4301] Kent, S. and K. Seo, "Security Architecture for the
|
||||
Internet Protocol", RFC 4301, December 2005.
|
||||
|
||||
[RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security
|
||||
(TLS) Protocol Version 1.2", RFC 5246, August 2008.
|
||||
|
||||
[RFC6030] Hoyer, P., Pei, M., and S. Machani, "Portable Symmetric
|
||||
Key Container (PSKC)", RFC 6030, October 2010.
|
||||
|
||||
[UT] Wikipedia, "Unix time", February 2011,
|
||||
<http://en.wikipedia.org/wiki/Unix_time>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 8]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
Appendix A. TOTP Algorithm: Reference Implementation
|
||||
|
||||
<CODE BEGINS>
|
||||
|
||||
/**
|
||||
Copyright (c) 2011 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, is permitted pursuant to, and subject to the license
|
||||
terms contained in, the Simplified BSD License set forth in Section
|
||||
4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
*/
|
||||
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.math.BigInteger;
|
||||
import java.util.TimeZone;
|
||||
|
||||
|
||||
/**
|
||||
* This is an example implementation of the OATH
|
||||
* TOTP algorithm.
|
||||
* Visit www.openauthentication.org for more information.
|
||||
*
|
||||
* @author Johan Rydell, PortWise, Inc.
|
||||
*/
|
||||
|
||||
public class TOTP {
|
||||
|
||||
private TOTP() {}
|
||||
|
||||
/**
|
||||
* This method uses the JCE to provide the crypto algorithm.
|
||||
* HMAC computes a Hashed Message Authentication Code with the
|
||||
* crypto hash algorithm as a parameter.
|
||||
*
|
||||
* @param crypto: the crypto algorithm (HmacSHA1, HmacSHA256,
|
||||
* HmacSHA512)
|
||||
* @param keyBytes: the bytes to use for the HMAC key
|
||||
* @param text: the message or text to be authenticated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 9]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
private static byte[] hmac_sha(String crypto, byte[] keyBytes,
|
||||
byte[] text){
|
||||
try {
|
||||
Mac hmac;
|
||||
hmac = Mac.getInstance(crypto);
|
||||
SecretKeySpec macKey =
|
||||
new SecretKeySpec(keyBytes, "RAW");
|
||||
hmac.init(macKey);
|
||||
return hmac.doFinal(text);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new UndeclaredThrowableException(gse);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method converts a HEX string to Byte[]
|
||||
*
|
||||
* @param hex: the HEX string
|
||||
*
|
||||
* @return: a byte array
|
||||
*/
|
||||
|
||||
private static byte[] hexStr2Bytes(String hex){
|
||||
// Adding one byte to get the right conversion
|
||||
// Values starting with "0" can be converted
|
||||
byte[] bArray = new BigInteger("10" + hex,16).toByteArray();
|
||||
|
||||
// Copy all the REAL bytes, not the "first"
|
||||
byte[] ret = new byte[bArray.length - 1];
|
||||
for (int i = 0; i < ret.length; i++)
|
||||
ret[i] = bArray[i+1];
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static final int[] DIGITS_POWER
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
= {1,10,100,1000,10000,100000,1000000,10000000,100000000 };
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 10]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
/**
|
||||
* This method generates a TOTP value for the given
|
||||
* set of parameters.
|
||||
*
|
||||
* @param key: the shared secret, HEX encoded
|
||||
* @param time: a value that reflects a time
|
||||
* @param returnDigits: number of digits to return
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes
|
||||
* {@link truncationDigits} digits
|
||||
*/
|
||||
|
||||
public static String generateTOTP(String key,
|
||||
String time,
|
||||
String returnDigits){
|
||||
return generateTOTP(key, time, returnDigits, "HmacSHA1");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method generates a TOTP value for the given
|
||||
* set of parameters.
|
||||
*
|
||||
* @param key: the shared secret, HEX encoded
|
||||
* @param time: a value that reflects a time
|
||||
* @param returnDigits: number of digits to return
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes
|
||||
* {@link truncationDigits} digits
|
||||
*/
|
||||
|
||||
public static String generateTOTP256(String key,
|
||||
String time,
|
||||
String returnDigits){
|
||||
return generateTOTP(key, time, returnDigits, "HmacSHA256");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 11]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
/**
|
||||
* This method generates a TOTP value for the given
|
||||
* set of parameters.
|
||||
*
|
||||
* @param key: the shared secret, HEX encoded
|
||||
* @param time: a value that reflects a time
|
||||
* @param returnDigits: number of digits to return
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes
|
||||
* {@link truncationDigits} digits
|
||||
*/
|
||||
|
||||
public static String generateTOTP512(String key,
|
||||
String time,
|
||||
String returnDigits){
|
||||
return generateTOTP(key, time, returnDigits, "HmacSHA512");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method generates a TOTP value for the given
|
||||
* set of parameters.
|
||||
*
|
||||
* @param key: the shared secret, HEX encoded
|
||||
* @param time: a value that reflects a time
|
||||
* @param returnDigits: number of digits to return
|
||||
* @param crypto: the crypto function to use
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes
|
||||
* {@link truncationDigits} digits
|
||||
*/
|
||||
|
||||
public static String generateTOTP(String key,
|
||||
String time,
|
||||
String returnDigits,
|
||||
String crypto){
|
||||
int codeDigits = Integer.decode(returnDigits).intValue();
|
||||
String result = null;
|
||||
|
||||
// Using the counter
|
||||
// First 8 bytes are for the movingFactor
|
||||
// Compliant with base RFC 4226 (HOTP)
|
||||
while (time.length() < 16 )
|
||||
time = "0" + time;
|
||||
|
||||
// Get the HEX in a Byte[]
|
||||
byte[] msg = hexStr2Bytes(time);
|
||||
byte[] k = hexStr2Bytes(key);
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 12]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
byte[] hash = hmac_sha(crypto, k, msg);
|
||||
|
||||
// put selected bytes into result int
|
||||
int offset = hash[hash.length - 1] & 0xf;
|
||||
|
||||
int binary =
|
||||
((hash[offset] & 0x7f) << 24) |
|
||||
((hash[offset + 1] & 0xff) << 16) |
|
||||
((hash[offset + 2] & 0xff) << 8) |
|
||||
(hash[offset + 3] & 0xff);
|
||||
|
||||
int otp = binary % DIGITS_POWER[codeDigits];
|
||||
|
||||
result = Integer.toString(otp);
|
||||
while (result.length() < codeDigits) {
|
||||
result = "0" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Seed for HMAC-SHA1 - 20 bytes
|
||||
String seed = "3132333435363738393031323334353637383930";
|
||||
// Seed for HMAC-SHA256 - 32 bytes
|
||||
String seed32 = "3132333435363738393031323334353637383930" +
|
||||
"313233343536373839303132";
|
||||
// Seed for HMAC-SHA512 - 64 bytes
|
||||
String seed64 = "3132333435363738393031323334353637383930" +
|
||||
"3132333435363738393031323334353637383930" +
|
||||
"3132333435363738393031323334353637383930" +
|
||||
"31323334";
|
||||
long T0 = 0;
|
||||
long X = 30;
|
||||
long testTime[] = {59L, 1111111109L, 1111111111L,
|
||||
1234567890L, 2000000000L, 20000000000L};
|
||||
|
||||
String steps = "0";
|
||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
df.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 13]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
try {
|
||||
System.out.println(
|
||||
"+---------------+-----------------------+" +
|
||||
"------------------+--------+--------+");
|
||||
System.out.println(
|
||||
"| Time(sec) | Time (UTC format) " +
|
||||
"| Value of T(Hex) | TOTP | Mode |");
|
||||
System.out.println(
|
||||
"+---------------+-----------------------+" +
|
||||
"------------------+--------+--------+");
|
||||
|
||||
for (int i=0; i<testTime.length; i++) {
|
||||
long T = (testTime[i] - T0)/X;
|
||||
steps = Long.toHexString(T).toUpperCase();
|
||||
while (steps.length() < 16) steps = "0" + steps;
|
||||
String fmtTime = String.format("%1$-11s", testTime[i]);
|
||||
String utcTime = df.format(new Date(testTime[i]*1000));
|
||||
System.out.print("| " + fmtTime + " | " + utcTime +
|
||||
" | " + steps + " |");
|
||||
System.out.println(generateTOTP(seed, steps, "8",
|
||||
"HmacSHA1") + "| SHA1 |");
|
||||
System.out.print("| " + fmtTime + " | " + utcTime +
|
||||
" | " + steps + " |");
|
||||
System.out.println(generateTOTP(seed32, steps, "8",
|
||||
"HmacSHA256") + "| SHA256 |");
|
||||
System.out.print("| " + fmtTime + " | " + utcTime +
|
||||
" | " + steps + " |");
|
||||
System.out.println(generateTOTP(seed64, steps, "8",
|
||||
"HmacSHA512") + "| SHA512 |");
|
||||
|
||||
System.out.println(
|
||||
"+---------------+-----------------------+" +
|
||||
"------------------+--------+--------+");
|
||||
}
|
||||
}catch (final Exception e){
|
||||
System.out.println("Error : " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<CODE ENDS>
|
||||
|
||||
Appendix B. Test Vectors
|
||||
|
||||
This section provides test values that can be used for the HOTP time-
|
||||
based variant algorithm interoperability test.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 14]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
The test token shared secret uses the ASCII string value
|
||||
"12345678901234567890". With Time Step X = 30, and the Unix epoch as
|
||||
the initial value to count time steps, where T0 = 0, the TOTP
|
||||
algorithm will display the following values for specified modes and
|
||||
timestamps.
|
||||
|
||||
+-------------+--------------+------------------+----------+--------+
|
||||
| Time (sec) | UTC Time | Value of T (hex) | TOTP | Mode |
|
||||
+-------------+--------------+------------------+----------+--------+
|
||||
| 59 | 1970-01-01 | 0000000000000001 | 94287082 | SHA1 |
|
||||
| | 00:00:59 | | | |
|
||||
| 59 | 1970-01-01 | 0000000000000001 | 46119246 | SHA256 |
|
||||
| | 00:00:59 | | | |
|
||||
| 59 | 1970-01-01 | 0000000000000001 | 90693936 | SHA512 |
|
||||
| | 00:00:59 | | | |
|
||||
| 1111111109 | 2005-03-18 | 00000000023523EC | 07081804 | SHA1 |
|
||||
| | 01:58:29 | | | |
|
||||
| 1111111109 | 2005-03-18 | 00000000023523EC | 68084774 | SHA256 |
|
||||
| | 01:58:29 | | | |
|
||||
| 1111111109 | 2005-03-18 | 00000000023523EC | 25091201 | SHA512 |
|
||||
| | 01:58:29 | | | |
|
||||
| 1111111111 | 2005-03-18 | 00000000023523ED | 14050471 | SHA1 |
|
||||
| | 01:58:31 | | | |
|
||||
| 1111111111 | 2005-03-18 | 00000000023523ED | 67062674 | SHA256 |
|
||||
| | 01:58:31 | | | |
|
||||
| 1111111111 | 2005-03-18 | 00000000023523ED | 99943326 | SHA512 |
|
||||
| | 01:58:31 | | | |
|
||||
| 1234567890 | 2009-02-13 | 000000000273EF07 | 89005924 | SHA1 |
|
||||
| | 23:31:30 | | | |
|
||||
| 1234567890 | 2009-02-13 | 000000000273EF07 | 91819424 | SHA256 |
|
||||
| | 23:31:30 | | | |
|
||||
| 1234567890 | 2009-02-13 | 000000000273EF07 | 93441116 | SHA512 |
|
||||
| | 23:31:30 | | | |
|
||||
| 2000000000 | 2033-05-18 | 0000000003F940AA | 69279037 | SHA1 |
|
||||
| | 03:33:20 | | | |
|
||||
| 2000000000 | 2033-05-18 | 0000000003F940AA | 90698825 | SHA256 |
|
||||
| | 03:33:20 | | | |
|
||||
| 2000000000 | 2033-05-18 | 0000000003F940AA | 38618901 | SHA512 |
|
||||
| | 03:33:20 | | | |
|
||||
| 20000000000 | 2603-10-11 | 0000000027BC86AA | 65353130 | SHA1 |
|
||||
| | 11:33:20 | | | |
|
||||
| 20000000000 | 2603-10-11 | 0000000027BC86AA | 77737706 | SHA256 |
|
||||
| | 11:33:20 | | | |
|
||||
| 20000000000 | 2603-10-11 | 0000000027BC86AA | 47863826 | SHA512 |
|
||||
| | 11:33:20 | | | |
|
||||
+-------------+--------------+------------------+----------+--------+
|
||||
|
||||
Table 1: TOTP Table
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 15]
|
||||
|
||||
RFC 6238 HOTPTimeBased May 2011
|
||||
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
David M'Raihi
|
||||
Verisign, Inc.
|
||||
685 E. Middlefield Road
|
||||
Mountain View, CA 94043
|
||||
USA
|
||||
|
||||
EMail: davidietf@gmail.com
|
||||
|
||||
|
||||
Salah Machani
|
||||
Diversinet Corp.
|
||||
2225 Sheppard Avenue East, Suite 1801
|
||||
Toronto, Ontario M2J 5C2
|
||||
Canada
|
||||
|
||||
EMail: smachani@diversinet.com
|
||||
|
||||
|
||||
Mingliang Pei
|
||||
Symantec
|
||||
510 E. Middlefield Road
|
||||
Mountain View, CA 94043
|
||||
USA
|
||||
|
||||
EMail: Mingliang_Pei@symantec.com
|
||||
|
||||
|
||||
Johan Rydell
|
||||
Portwise, Inc.
|
||||
275 Hawthorne Ave., Suite 119
|
||||
Palo Alto, CA 94301
|
||||
USA
|
||||
|
||||
EMail: johanietf@gmail.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M'Raihi, et al. Informational [Page 16]
|
||||
|
|
@ -10,11 +10,3 @@ security_HEADERS = \
|
|||
pam_constants.h \
|
||||
pam_modules.h \
|
||||
pam_types.h
|
||||
|
||||
if WITH_OATH
|
||||
security_HEADERS += \
|
||||
oath.h \
|
||||
oath_constants.h \
|
||||
oath_rfc4648.h \
|
||||
oath_types.h
|
||||
endif
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2012-2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef OATH_H_INCLUDED
|
||||
#define OATH_H_INCLUDED
|
||||
|
||||
#include <security/oath_constants.h>
|
||||
#include <security/oath_types.h>
|
||||
#include <security/oath_rfc4648.h>
|
||||
|
||||
struct oath_key *oath_key_alloc(void);
|
||||
void oath_key_free(struct oath_key *);
|
||||
struct oath_key *oath_key_from_uri(const char *);
|
||||
struct oath_key *oath_key_from_file(const char *);
|
||||
char *oath_key_to_uri(const struct oath_key *);
|
||||
|
||||
struct oath_key *oath_key_dummy(enum oath_mode, enum oath_hash, unsigned int);
|
||||
|
||||
unsigned int oath_hotp(const uint8_t *, size_t, uint64_t, unsigned int);
|
||||
unsigned int oath_hotp_current(struct oath_key *);
|
||||
int oath_hotp_match(struct oath_key *, unsigned int, int);
|
||||
|
||||
unsigned int oath_totp(const uint8_t *, size_t, unsigned int);
|
||||
unsigned int oath_totp_current(const struct oath_key *);
|
||||
int oath_totp_match(struct oath_key *, unsigned int, int);
|
||||
|
||||
#endif
|
|
@ -1,84 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2012-2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef OATH_CONSTANTS_H_INCLUDED
|
||||
#define OATH_CONSTANTS_H_INCLUDED
|
||||
|
||||
/*
|
||||
* OATH modes
|
||||
*/
|
||||
enum oath_mode {
|
||||
om_undef, /* not set / default */
|
||||
om_hotp, /* RFC 4226 HOTP */
|
||||
om_totp, /* RFC 6238 TOTP */
|
||||
om_max
|
||||
};
|
||||
|
||||
/*
|
||||
* Hash functions
|
||||
*/
|
||||
enum oath_hash {
|
||||
oh_undef, /* not set / default */
|
||||
oh_md5, /* RFC 1321 MD5 */
|
||||
oh_sha1, /* FIPS 180 SHA-1 */
|
||||
oh_sha256, /* FIPS 180 SHA-256 */
|
||||
oh_sha512, /* FIPS 180 SHA-512 */
|
||||
oh_max
|
||||
};
|
||||
|
||||
/*
|
||||
* Default time step for TOTP: 30 seconds.
|
||||
*/
|
||||
#define OATH_DEF_TIMESTEP 30
|
||||
|
||||
/*
|
||||
* Maximum time step for TOTP: 10 minutes, which RFC 6238 cites as an
|
||||
* example of an unreasonably large time step.
|
||||
*/
|
||||
#define OATH_MAX_TIMESTEP 600
|
||||
|
||||
/*
|
||||
* Maximum key length in bytes. HMAC has a 64-byte block size; if the key
|
||||
* K is longer than that, HMAC derives a new key K' = H(K).
|
||||
*/
|
||||
#define OATH_MAX_KEYLEN 64
|
||||
|
||||
/*
|
||||
* Maximum label length in characters, including terminating NUL.
|
||||
*/
|
||||
#define OATH_MAX_LABELLEN 64
|
||||
|
||||
/*
|
||||
* Label to use for dummy keys
|
||||
*/
|
||||
#define OATH_DUMMY_LABEL "oath-dummy-key"
|
||||
|
||||
#endif
|
|
@ -1,51 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2012-2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef OATH_RFC4648_H_INCLUDED
|
||||
#define OATH_RFC4648_H_INCLUDED
|
||||
|
||||
/* estimate of output length for base32 encoding / decoding */
|
||||
#define base32_enclen(l) (size_t)(((l + 4) / 5) * 8)
|
||||
#define base32_declen(l) (size_t)(((l + 7) / 8) * 5)
|
||||
|
||||
/* base32 encoding / decoding */
|
||||
int base32_enc(const uint8_t *, size_t, char *, size_t *);
|
||||
int base32_dec(const char *, size_t, uint8_t *, size_t *);
|
||||
|
||||
/* estimate of output length for base64 encoding / decoding */
|
||||
#define base64_enclen(l) (size_t)(((l + 2) / 3) * 4)
|
||||
#define base64_declen(l) (size_t)(((l + 3) / 4) * 3)
|
||||
|
||||
/* base64 encoding / decoding */
|
||||
int base64_enc(const uint8_t *, size_t, char *, size_t *);
|
||||
int base64_dec(const char *, size_t, uint8_t *, size_t *);
|
||||
|
||||
#endif
|
|
@ -1,62 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2012-2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef OATH_TYPES_H_INCLUDED
|
||||
#define OATH_TYPES_H_INCLUDED
|
||||
|
||||
/*
|
||||
* OATH key and associated parameters
|
||||
*/
|
||||
struct oath_key {
|
||||
/* mode and parameters */
|
||||
enum oath_mode mode;
|
||||
unsigned int digits;
|
||||
uint64_t counter;
|
||||
unsigned int timestep; /* in seconds */
|
||||
uint64_t lastuse;
|
||||
|
||||
/* housekeeping */
|
||||
unsigned int mapped:1;
|
||||
unsigned int locked:1;
|
||||
|
||||
/* hash algorithm */
|
||||
enum oath_hash hash;
|
||||
|
||||
/* label */
|
||||
size_t labellen; /* bytes incl. NUL */
|
||||
char label[OATH_MAX_LABELLEN];
|
||||
|
||||
/* key */
|
||||
size_t keylen; /* bytes */
|
||||
uint8_t key[OATH_MAX_KEYLEN];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,7 +1,3 @@
|
|||
# $Id$
|
||||
|
||||
SUBDIRS = libpam
|
||||
|
||||
if WITH_OATH
|
||||
SUBDIRS += liboath
|
||||
endif
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
# $Id$
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/lib/libpam
|
||||
|
||||
lib_LTLIBRARIES = liboath.la
|
||||
|
||||
liboath_la_SOURCES = \
|
||||
oath_base32.c \
|
||||
oath_base64.c \
|
||||
oath_hotp.c \
|
||||
oath_totp.c \
|
||||
oath_key_alloc.c \
|
||||
oath_key_dummy.c \
|
||||
oath_key_free.c \
|
||||
oath_key.c
|
||||
|
||||
liboath_la_LDFLAGS = -no-undefined -version-info @LIB_MAJ@
|
||||
liboath_la_LIBADD = $(top_builddir)/lib/libpam/libpam.la @CRYPTO_LIBS@
|
|
@ -1,164 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <security/oath.h>
|
||||
|
||||
static const char b32[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
/*
|
||||
* Encode data in RFC 3548 base 32 representation. The target buffer must
|
||||
* have room for base32_enclen(len) characters and a terminating NUL.
|
||||
*/
|
||||
int
|
||||
base32_enc(const uint8_t *in, size_t ilen, char *out, size_t *olen)
|
||||
{
|
||||
uint64_t bits;
|
||||
|
||||
if (*olen <= base32_enclen(ilen))
|
||||
return (-1);
|
||||
*olen = 0;
|
||||
while (ilen >= 5) {
|
||||
bits = 0;
|
||||
bits |= (uint64_t)in[0] << 32;
|
||||
bits |= (uint64_t)in[1] << 24;
|
||||
bits |= (uint64_t)in[2] << 16;
|
||||
bits |= (uint64_t)in[3] << 8;
|
||||
bits |= (uint64_t)in[4];
|
||||
ilen -= 5;
|
||||
in += 5;
|
||||
out[0] = b32[bits >> 35 & 0x1f];
|
||||
out[1] = b32[bits >> 30 & 0x1f];
|
||||
out[2] = b32[bits >> 25 & 0x1f];
|
||||
out[3] = b32[bits >> 20 & 0x1f];
|
||||
out[4] = b32[bits >> 15 & 0x1f];
|
||||
out[5] = b32[bits >> 10 & 0x1f];
|
||||
out[6] = b32[bits >> 5 & 0x1f];
|
||||
out[7] = b32[bits & 0x1f];
|
||||
*olen += 8;
|
||||
out += 8;
|
||||
}
|
||||
if (ilen > 0) {
|
||||
bits = 0;
|
||||
switch (ilen) {
|
||||
case 4:
|
||||
bits |= (uint64_t)in[3] << 8;
|
||||
case 3:
|
||||
bits |= (uint64_t)in[2] << 16;
|
||||
case 2:
|
||||
bits |= (uint64_t)in[1] << 24;
|
||||
case 1:
|
||||
bits |= (uint64_t)in[0] << 32;
|
||||
}
|
||||
out[0] = b32[bits >> 35 & 0x1f];
|
||||
out[1] = b32[bits >> 30 & 0x1f];
|
||||
out[2] = ilen > 1 ? b32[bits >> 25 & 0x1f] : '=';
|
||||
out[3] = ilen > 1 ? b32[bits >> 20 & 0x1f] : '=';
|
||||
out[4] = ilen > 2 ? b32[bits >> 15 & 0x1f] : '=';
|
||||
out[5] = ilen > 3 ? b32[bits >> 10 & 0x1f] : '=';
|
||||
out[6] = ilen > 3 ? b32[bits >> 5 & 0x1f] : '=';
|
||||
out[7] = '=';
|
||||
*olen += 8;
|
||||
out += 8;
|
||||
}
|
||||
out[0] = '\0';
|
||||
++*olen;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode data in RFC 2548 base 32 representation, stopping at the
|
||||
* terminating NUL, the first invalid (non-base32, non-whitespace)
|
||||
* character or after len characters, whichever comes first.
|
||||
*
|
||||
* The olen argument is used by the caller to pass the size of the buffer
|
||||
* and by base32_dec() to return the amount of data successfully decoded.
|
||||
* If the buffer is too small, base32_dec() discards the excess data, but
|
||||
* returns the total amount.
|
||||
*/
|
||||
int
|
||||
base32_dec(const char *in, size_t ilen, uint8_t *out, size_t *olen)
|
||||
{
|
||||
size_t len;
|
||||
uint64_t bits;
|
||||
int shift;
|
||||
|
||||
for (len = 0, bits = 0, shift = 40; ilen && *in; --ilen, ++in) {
|
||||
if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n') {
|
||||
continue;
|
||||
} else if (*in >= 'A' && *in <= 'Z') {
|
||||
shift -= 5;
|
||||
bits |= (uint64_t)(*in - 'A') << shift;
|
||||
} else if (*in >= 'a' && *in <= 'z') {
|
||||
shift -= 5;
|
||||
bits |= (uint64_t)(*in - 'a') << shift;
|
||||
} else if (*in >= '2' && *in <= '7') {
|
||||
shift -= 5;
|
||||
bits |= (uint64_t)(*in - '2' + 26) << shift;
|
||||
} else if (*in == '=' &&
|
||||
(shift == 30 || shift == 20 || shift == 15 || shift == 5)) {
|
||||
/* hack: assume the rest of the padding is ok */
|
||||
shift = 0;
|
||||
} else {
|
||||
*olen = 0;
|
||||
return (-1);
|
||||
}
|
||||
if (shift == 0) {
|
||||
if ((len += 5) <= *olen) {
|
||||
out[0] = (bits >> 32) & 0xff;
|
||||
out[1] = (bits >> 24) & 0xff;
|
||||
out[2] = (bits >> 16) & 0xff;
|
||||
out[3] = (bits >> 8) & 0xff;
|
||||
out[4] = bits & 0xff;
|
||||
out += 5;
|
||||
}
|
||||
bits = 0;
|
||||
shift = 40;
|
||||
}
|
||||
if (*in == '=')
|
||||
break;
|
||||
}
|
||||
if (len > *olen) {
|
||||
*olen = len;
|
||||
return (-1);
|
||||
}
|
||||
*olen = len;
|
||||
return (0);
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <security/oath.h>
|
||||
|
||||
static const char b64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
/*
|
||||
* Encode data in RFC 3548 base 64 representation. The target buffer must
|
||||
* have room for base64_enclen(len) characters and a terminating NUL.
|
||||
*/
|
||||
int
|
||||
base64_enc(const uint8_t *in, size_t ilen, char *out, size_t *olen)
|
||||
{
|
||||
uint32_t bits;
|
||||
|
||||
if (*olen <= base64_enclen(ilen))
|
||||
return (-1);
|
||||
*olen = 0;
|
||||
while (ilen >= 3) {
|
||||
bits = 0;
|
||||
bits |= (uint32_t)in[0] << 16;
|
||||
bits |= (uint32_t)in[1] << 8;
|
||||
bits |= (uint32_t)in[2];
|
||||
ilen -= 3;
|
||||
in += 3;
|
||||
out[0] = b64[bits >> 18 & 0x3f];
|
||||
out[1] = b64[bits >> 12 & 0x3f];
|
||||
out[2] = b64[bits >> 6 & 0x3f];
|
||||
out[3] = b64[bits & 0x3f];
|
||||
*olen += 4;
|
||||
out += 4;
|
||||
}
|
||||
if (ilen > 0) {
|
||||
bits = 0;
|
||||
switch (ilen) {
|
||||
case 2:
|
||||
bits |= (uint32_t)in[1] << 8;
|
||||
case 1:
|
||||
bits |= (uint32_t)in[0] << 16;
|
||||
}
|
||||
out[0] = b64[bits >> 18 & 0x3f];
|
||||
out[1] = b64[bits >> 12 & 0x3f];
|
||||
out[2] = ilen > 1 ? b64[bits >> 6 & 0x3f] : '=';
|
||||
out[3] = '=';
|
||||
*olen += 4;
|
||||
out += 4;
|
||||
}
|
||||
out[0] = '\0';
|
||||
++*olen;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode data in RFC 2548 base 64 representation, stopping at the
|
||||
* terminating NUL, the first invalid (non-base64, non-whitespace)
|
||||
* character or after len characters, whichever comes first.
|
||||
*
|
||||
* The olen argument is used by the caller to pass the size of the buffer
|
||||
* and by base64_dec() to return the amount of data successfully decoded.
|
||||
* If the buffer is too small, base64_dec() discards the excess data, but
|
||||
* returns the total amount.
|
||||
*/
|
||||
int
|
||||
base64_dec(const char *in, size_t ilen, uint8_t *out, size_t *olen)
|
||||
{
|
||||
size_t len;
|
||||
uint32_t bits;
|
||||
int shift;
|
||||
|
||||
for (len = 0, bits = 0, shift = 24; ilen && *in; --ilen, ++in) {
|
||||
if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n') {
|
||||
continue;
|
||||
} else if (*in >= 'A' && *in <= 'Z') {
|
||||
shift -= 6;
|
||||
bits |= (uint32_t)(*in - 'A') << shift;
|
||||
} else if (*in >= 'a' && *in <= 'z') {
|
||||
shift -= 6;
|
||||
bits |= (uint32_t)(*in - 'a' + 26) << shift;
|
||||
} else if (*in >= '0' && *in <= '9') {
|
||||
shift -= 6;
|
||||
bits |= (uint32_t)(*in - '2' + 52) << shift;
|
||||
} else if (*in == '+') {
|
||||
shift -= 6;
|
||||
bits |= (uint32_t)62 << shift;
|
||||
} else if (*in == '/') {
|
||||
shift -= 6;
|
||||
bits |= (uint32_t)63 << shift;
|
||||
} else if (*in == '=' && (shift == 12 || shift == 6)) {
|
||||
/* hack: assume the rest of the padding is ok */
|
||||
shift = 0;
|
||||
} else {
|
||||
*olen = 0;
|
||||
return (-1);
|
||||
}
|
||||
if (shift == 0) {
|
||||
if ((len += 3) <= *olen) {
|
||||
out[1] = (bits >> 16) & 0xff;
|
||||
out[1] = (bits >> 8) & 0xff;
|
||||
out[2] = bits & 0xff;
|
||||
out += 3;
|
||||
}
|
||||
bits = 0;
|
||||
shift = 24;
|
||||
}
|
||||
if (*in == '=')
|
||||
break;
|
||||
}
|
||||
if (len > *olen) {
|
||||
*olen = len;
|
||||
return (-1);
|
||||
}
|
||||
*olen = len;
|
||||
return (0);
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2012-2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <security/oath.h>
|
||||
|
||||
#define StToNum(St) (St)
|
||||
|
||||
static uint32_t
|
||||
DT(const uint8_t *String)
|
||||
{
|
||||
uint8_t OffsetBits;
|
||||
int Offset;
|
||||
uint32_t P;
|
||||
|
||||
OffsetBits = String[19] & 0x0f;
|
||||
Offset = StToNum(OffsetBits);
|
||||
P = (uint32_t)String[Offset + 0] << 24 |
|
||||
(uint32_t)String[Offset + 1] << 16 |
|
||||
(uint32_t)String[Offset + 2] << 8 |
|
||||
(uint32_t)String[Offset + 3];
|
||||
return (P & 0x7fffffffUL);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
oath_hotp(const uint8_t *K, size_t Klen, uint64_t seq, unsigned int Digit)
|
||||
{
|
||||
HMAC_CTX ctx;
|
||||
uint8_t C[8];
|
||||
uint8_t HS[20];
|
||||
unsigned int HSlen;
|
||||
uint32_t Sbits, Snum;
|
||||
unsigned int mod, D;
|
||||
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
C[i] = seq & 0xff;
|
||||
seq >>= 8;
|
||||
}
|
||||
|
||||
/* HS = HMAC-SHA-1(K,C) */
|
||||
HMAC_CTX_init(&ctx);
|
||||
HMAC_Init_ex(&ctx, K, Klen, EVP_sha1(), NULL);
|
||||
HMAC_Update(&ctx, (const uint8_t *)&C, sizeof C);
|
||||
HMAC_Final(&ctx, HS, &HSlen);
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
|
||||
Sbits = DT(HS);
|
||||
Snum = StToNum(Sbits);
|
||||
for (mod = 1; Digit > 0; --Digit)
|
||||
mod *= 10;
|
||||
D = Snum % mod;
|
||||
return (D);
|
||||
}
|
||||
|
||||
/*
|
||||
* Computes the current code for the given key and advances the counter.
|
||||
*/
|
||||
unsigned int
|
||||
oath_hotp_current(struct oath_key *k)
|
||||
{
|
||||
unsigned int code;
|
||||
|
||||
if (k == NULL)
|
||||
return (-1);
|
||||
if (k->mode != om_hotp)
|
||||
return (-1);
|
||||
if (k->counter == UINT64_MAX)
|
||||
return (-1);
|
||||
code = oath_hotp(k->key, k->keylen, k->counter, k->digits);
|
||||
k->counter += 1;
|
||||
return (code);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares the code provided by the user with expected values within a
|
||||
* given window. Returns 1 if there was a match, 0 if not, and -1 if an
|
||||
* error occurred. Also advances the counter if there was a match.
|
||||
*/
|
||||
int
|
||||
oath_hotp_match(struct oath_key *k, unsigned int response, int window)
|
||||
{
|
||||
unsigned int code;
|
||||
int dummy;
|
||||
|
||||
if (k == NULL)
|
||||
return (-1);
|
||||
if (window < 1)
|
||||
return (-1);
|
||||
if (k->mode != om_hotp)
|
||||
return (-1);
|
||||
if (k->counter >= UINT64_MAX - window)
|
||||
return (-1);
|
||||
dummy = (strcmp(k->label, OATH_DUMMY_LABEL) == 0);
|
||||
for (int i = 0; i < window; ++i) {
|
||||
code = oath_hotp(k->key, k->keylen, k->counter + i, k->digits);
|
||||
if (code == response && !dummy) {
|
||||
k->counter = k->counter + i;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2012-2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef OATH_IMPL_H_INCLUDED
|
||||
#define OATH_IMPL_H_INCLUDED
|
||||
|
||||
/*
|
||||
* Dummy key parameters
|
||||
*/
|
||||
#define OATH_DUMMY_LABEL ("oath-dummy-key")
|
||||
#define OATH_DUMMY_LABELLEN (sizeof DUMMY_LABEL)
|
||||
#define OATH_DUMMY_KEYLEN 80
|
||||
|
||||
#endif
|
|
@ -1,268 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/openpam.h>
|
||||
|
||||
#include "openpam_asprintf.h"
|
||||
#include "openpam_strlcmp.h"
|
||||
|
||||
#include <security/oath.h>
|
||||
|
||||
/*
|
||||
* Allocate a struct oath_key and populate it from a Google Authenticator
|
||||
* otpauth URI
|
||||
*/
|
||||
struct oath_key *
|
||||
oath_key_from_uri(const char *uri)
|
||||
{
|
||||
struct oath_key *key;
|
||||
const char *p, *q, *r;
|
||||
uintmax_t n;
|
||||
char *e;
|
||||
|
||||
if ((key = oath_key_alloc()) == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* check method */
|
||||
p = uri;
|
||||
if (strlcmp("otpauth://", p, 10) != 0)
|
||||
goto invalid;
|
||||
p += 10;
|
||||
|
||||
/* check mode (hotp = event, totp = time-sync) */
|
||||
if ((q = strchr(p, '/')) == NULL)
|
||||
goto invalid;
|
||||
if (strlcmp("hotp", p, q - p) == 0) {
|
||||
key->mode = om_hotp;
|
||||
} else if (strlcmp("totp", p, q - p) == 0) {
|
||||
key->mode = om_totp;
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
p = q + 1;
|
||||
|
||||
/* extract label */
|
||||
if ((q = strchr(p, '?')) == NULL)
|
||||
goto invalid;
|
||||
if ((key->labellen = q - p + 1) > sizeof key->label)
|
||||
goto invalid;
|
||||
memcpy(key->label, p, q - p);
|
||||
key->label[q - p] = '\0';
|
||||
p = q + 1;
|
||||
|
||||
/* extract parameters */
|
||||
key->counter = UINT64_MAX;
|
||||
while (*p != '\0') {
|
||||
if ((q = strchr(p, '=')) == NULL)
|
||||
goto invalid;
|
||||
q = q + 1;
|
||||
if ((r = strchr(p, '&')) == NULL)
|
||||
r = strchr(p, '\0');
|
||||
if (r < q)
|
||||
/* & before = */
|
||||
goto invalid;
|
||||
/* p points to key, q points to value, r points to & or NUL */
|
||||
if (strlcmp("secret=", p, q - p) == 0) {
|
||||
if (key->keylen != 0)
|
||||
/* dupe */
|
||||
goto invalid;
|
||||
key->keylen = sizeof key->key;
|
||||
if (base32_dec(q, r - q, key->key, &key->keylen) != 0)
|
||||
goto invalid;
|
||||
if (base32_enclen(key->keylen) != (size_t)(r - q))
|
||||
goto invalid;
|
||||
} else if (strlcmp("algorithm=", p, q - p) == 0) {
|
||||
if (key->hash != oh_undef)
|
||||
/* dupe */
|
||||
goto invalid;
|
||||
if (strlcmp("SHA1", q, r - q) == 0)
|
||||
key->hash = oh_sha1;
|
||||
else if (strlcmp("SHA256", q, r - q) == 0)
|
||||
key->hash = oh_sha256;
|
||||
else if (strlcmp("SHA512", q, r - q) == 0)
|
||||
key->hash = oh_sha512;
|
||||
else if (strlcmp("MD5", q, r - q) == 0)
|
||||
key->hash = oh_md5;
|
||||
else
|
||||
goto invalid;
|
||||
} else if (strlcmp("digits=", p, q - p) == 0) {
|
||||
if (key->digits != 0)
|
||||
/* dupe */
|
||||
goto invalid;
|
||||
/* only 6 or 8 */
|
||||
if (r - q != 1 || (*q != '6' && *q != '8'))
|
||||
goto invalid;
|
||||
key->digits = *q - '0';
|
||||
} else if (strlcmp("counter=", p, q - p) == 0) {
|
||||
if (key->counter != UINT64_MAX)
|
||||
/* dupe */
|
||||
goto invalid;
|
||||
n = strtoumax(q, &e, 10);
|
||||
if (e != r || n >= UINT64_MAX)
|
||||
goto invalid;
|
||||
key->counter = (uint64_t)n;
|
||||
} else if (strlcmp("period=", p, q - p) == 0) {
|
||||
if (key->timestep != 0)
|
||||
/* dupe */
|
||||
goto invalid;
|
||||
n = strtoumax(q, &e, 10);
|
||||
if (e != r || n > OATH_MAX_TIMESTEP)
|
||||
goto invalid;
|
||||
key->timestep = n;
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
/* final parameter? */
|
||||
if (*r == '\0')
|
||||
break;
|
||||
/* skip & and continue */
|
||||
p = r + 1;
|
||||
}
|
||||
|
||||
/* sanity checks and default values */
|
||||
if (key->mode == om_hotp) {
|
||||
if (key->timestep != 0)
|
||||
goto invalid;
|
||||
if (key->counter == UINTMAX_MAX)
|
||||
key->counter = 0;
|
||||
} else if (key->mode == om_totp) {
|
||||
if (key->counter != UINTMAX_MAX)
|
||||
goto invalid;
|
||||
if (key->timestep == 0)
|
||||
key->timestep = OATH_DEF_TIMESTEP;
|
||||
} else {
|
||||
/* unreachable */
|
||||
oath_key_free(key);
|
||||
return (NULL);
|
||||
}
|
||||
if (key->hash == oh_undef)
|
||||
key->hash = oh_sha1;
|
||||
if (key->digits == 0)
|
||||
key->digits = 6;
|
||||
if (key->keylen == 0)
|
||||
goto invalid;
|
||||
return (key);
|
||||
|
||||
invalid:
|
||||
openpam_log(PAM_LOG_NOTICE, "invalid OATH URI: %s", uri);
|
||||
oath_key_free(key);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct oath_key *
|
||||
oath_key_from_file(const char *filename)
|
||||
{
|
||||
struct oath_key *key;
|
||||
FILE *f;
|
||||
char *line;
|
||||
size_t len;
|
||||
|
||||
if ((f = fopen(filename, "r")) == NULL)
|
||||
return (NULL);
|
||||
/* get first non-empty non-comment line */
|
||||
line = openpam_readline(f, NULL, &len);
|
||||
if (strlcmp("otpauth://", line, len) == 0) {
|
||||
key = oath_key_from_uri(line);
|
||||
} else {
|
||||
openpam_log(PAM_LOG_ERROR,
|
||||
"unrecognized key file format: %s", filename);
|
||||
key = NULL;
|
||||
}
|
||||
fclose(f);
|
||||
return (key);
|
||||
}
|
||||
|
||||
char *
|
||||
oath_key_to_uri(const struct oath_key *key)
|
||||
{
|
||||
const char *hash;
|
||||
char *tmp, *uri;
|
||||
size_t kslen, urilen;
|
||||
|
||||
switch (key->hash) {
|
||||
case oh_sha1:
|
||||
hash = "SHA1";
|
||||
break;
|
||||
case oh_sha256:
|
||||
hash = "SHA256";
|
||||
break;
|
||||
case oh_sha512:
|
||||
hash = "SHA512";
|
||||
break;
|
||||
case oh_md5:
|
||||
hash = "MD5";
|
||||
break;
|
||||
default:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (key->mode == om_hotp) {
|
||||
urilen = asprintf(&uri, "otpauth://"
|
||||
"%s/%s?algorithm=%s&digits=%d&counter=%ju&secret=",
|
||||
"hotp", key->label, hash, key->digits,
|
||||
(uintmax_t)key->counter);
|
||||
} else if (key->mode == om_totp) {
|
||||
urilen = asprintf(&uri, "otpauth://"
|
||||
"%s/%s?algorithm=%s&digits=%d&period=%u&secret=",
|
||||
"totp", key->label, hash, key->digits, key->timestep);
|
||||
} else {
|
||||
/* unreachable */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* compute length of base32-encoded key and append it */
|
||||
kslen = base32_enclen(key->keylen) + 1;
|
||||
if ((tmp = realloc(uri, urilen + kslen)) == NULL) {
|
||||
free(uri);
|
||||
return (NULL);
|
||||
}
|
||||
uri = tmp;
|
||||
if (base32_enc(key->key, key->keylen, uri + urilen, &kslen) != 0) {
|
||||
free(uri);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (uri);
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/openpam.h>
|
||||
#include <security/oath.h>
|
||||
|
||||
/*
|
||||
* OATH
|
||||
*
|
||||
* Allocates an OATH key structure
|
||||
*/
|
||||
|
||||
struct oath_key *
|
||||
oath_key_alloc(void)
|
||||
{
|
||||
struct oath_key *key;
|
||||
int prot, flags;
|
||||
|
||||
prot = PROT_READ|PROT_WRITE;
|
||||
flags = MAP_ANON;
|
||||
#ifdef MAP_NOCORE
|
||||
flags |= MAP_NOCORE;
|
||||
#endif
|
||||
if ((key = mmap(NULL, sizeof *key, prot, flags, -1, 0)) != NULL) {
|
||||
memset(key, 0, sizeof *key);
|
||||
key->mapped = 1;
|
||||
if (mlock(key, sizeof *key) == 0)
|
||||
key->locked = 1;
|
||||
} else {
|
||||
openpam_log(PAM_LOG_ERROR, "mmap(): %m");
|
||||
if ((key = calloc(sizeof *key, 1)) == NULL)
|
||||
openpam_log(PAM_LOG_ERROR, "malloc(): %m");
|
||||
}
|
||||
return (key);
|
||||
}
|
||||
|
||||
/**
|
||||
* The =oath_key_alloc function allocates and initializes an OATH key
|
||||
* structure.
|
||||
*
|
||||
* Keys allocated with =oath_key_alloc must be freed using =oath_key_free.
|
||||
*
|
||||
* >oath_key_free
|
||||
*
|
||||
* AUTHOR UIO
|
||||
*/
|
|
@ -1,76 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <security/oath.h>
|
||||
|
||||
/*
|
||||
* OATH
|
||||
*
|
||||
* Creates a dummy OATH key structure
|
||||
*/
|
||||
|
||||
struct oath_key *
|
||||
oath_key_dummy(enum oath_mode mode, enum oath_hash hash, unsigned int digits)
|
||||
{
|
||||
struct oath_key *key;
|
||||
|
||||
if ((key = oath_key_alloc()) == NULL)
|
||||
return (NULL);
|
||||
key->mode = mode;
|
||||
key->digits = digits;
|
||||
key->counter = 0;
|
||||
key->timestep = 30;
|
||||
key->hash = hash;
|
||||
strcpy(key->label, "oath-dummy-key");
|
||||
key->labellen = strlen(key->label);
|
||||
key->keylen = sizeof key->key;
|
||||
return (key);
|
||||
}
|
||||
|
||||
/**
|
||||
* The =oath_key_dummy function allocates and initializes a dummy OATH key
|
||||
* structure.
|
||||
* Authentication attempts using a dummy key will always fail.
|
||||
*
|
||||
* Keys allocated with =oath_key_dummy must be freed using =oath_key_free.
|
||||
*
|
||||
* >oath_key_alloc
|
||||
* >oath_key_free
|
||||
*
|
||||
* AUTHOR UIO
|
||||
*/
|
|
@ -1,78 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/openpam.h>
|
||||
#include <security/oath.h>
|
||||
|
||||
/*
|
||||
* OATH
|
||||
*
|
||||
* Wipes and frees an OATH key structure
|
||||
*/
|
||||
|
||||
void
|
||||
oath_key_free(struct oath_key *key)
|
||||
{
|
||||
int mapped, locked;
|
||||
|
||||
if (key != NULL) {
|
||||
mapped = key->mapped;
|
||||
locked = key->locked;
|
||||
memset(key, 0, sizeof *key);
|
||||
if (mapped) {
|
||||
if (locked)
|
||||
munlock(key, sizeof *key);
|
||||
munmap(key, sizeof *key);
|
||||
} else {
|
||||
free(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The =oath_key_free function wipes and frees an OATH key structure which
|
||||
* was previously allocated using the =oath_key_alloc function.
|
||||
*
|
||||
* >oath_key_alloc
|
||||
*
|
||||
* AUTHOR UIO
|
||||
*/
|
|
@ -1,105 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2012-2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <security/oath.h>
|
||||
|
||||
#define TOTP_TIME_STEP 30
|
||||
|
||||
unsigned int
|
||||
oath_totp(const uint8_t *K, size_t Klen, unsigned int Digit)
|
||||
{
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
return (oath_hotp(K, Klen, now / TOTP_TIME_STEP, Digit));
|
||||
}
|
||||
|
||||
unsigned int
|
||||
oath_totp_current(const struct oath_key *k)
|
||||
{
|
||||
unsigned int code;
|
||||
uint64_t seq;
|
||||
|
||||
if (k == NULL)
|
||||
return (-1);
|
||||
if (k->mode != om_totp)
|
||||
return (-1);
|
||||
if (k->timestep == 0)
|
||||
return (-1);
|
||||
seq = time(NULL) / k->timestep;
|
||||
code = oath_hotp(k->key, k->keylen, seq, k->digits);
|
||||
return (code);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares the code provided by the user with expected values within a
|
||||
* given window. Returns 1 if there was a match, 0 if not, and -1 if an
|
||||
* error occurred.
|
||||
*/
|
||||
int
|
||||
oath_totp_match(struct oath_key *k, unsigned int response, int window)
|
||||
{
|
||||
unsigned int code;
|
||||
uint64_t seq;
|
||||
int dummy;
|
||||
|
||||
if (k == NULL)
|
||||
return (-1);
|
||||
if (window < 1)
|
||||
return (-1);
|
||||
if (k->mode != om_totp)
|
||||
return (-1);
|
||||
if (k->timestep == 0)
|
||||
return (-1);
|
||||
seq = time(NULL) / k->timestep;
|
||||
dummy = (strcmp(k->label, OATH_DUMMY_LABEL) == 0);
|
||||
for (int i = -window; i <= window; ++i) {
|
||||
#if OATH_TOTP_PREVENT_REUSE
|
||||
/* XXX disabled for now, should be a key parameter? */
|
||||
if (seq + i <= k->lastuse)
|
||||
continue;
|
||||
#endif
|
||||
code = oath_hotp(k->key, k->keylen, seq + i, k->digits);
|
||||
if (code == response && !dummy) {
|
||||
k->lastuse = seq;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
|
@ -5,7 +5,3 @@ SUBDIRS = pam_deny pam_permit
|
|||
if WITH_PAM_UNIX
|
||||
SUBDIRS += pam_unix
|
||||
endif
|
||||
|
||||
if WITH_OATH
|
||||
SUBDIRS += pam_oath
|
||||
endif
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
# $Id$
|
||||
|
||||
if CUSTOM_MODULES_DIR
|
||||
moduledir = @OPENPAM_MODULES_DIR@
|
||||
else
|
||||
moduledir = $(libdir)
|
||||
endif
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
|
||||
module_LTLIBRARIES = pam_oath.la
|
||||
|
||||
pam_oath_la_SOURCES = pam_oath.c
|
||||
pam_oath_la_LDFLAGS = -no-undefined -module -version-info @LIB_MAJ@ \
|
||||
-export-symbols-regex '^pam_sm_'
|
||||
pam_oath_la_LIBADD = \
|
||||
$(top_builddir)/lib/libpam/libpam.la \
|
||||
$(top_builddir)/lib/liboath/liboath.la
|
|
@ -1,319 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2012-2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define PAM_SM_AUTH
|
||||
#define PAM_SM_ACCOUNT
|
||||
|
||||
#include <security/pam_modules.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/oath.h>
|
||||
|
||||
#define PAM_OATH_PROMPT "Verification code: "
|
||||
#define PAM_OATH_HOTP_WINDOW 3
|
||||
#define PAM_OATH_TOTP_WINDOW 3
|
||||
|
||||
enum pam_oath_nokey { nokey_error = -1, nokey_fail, nokey_fake, nokey_ignore };
|
||||
|
||||
static const char *pam_oath_default_keyfile = "/var/oath/%u.otpauth";
|
||||
|
||||
/*
|
||||
* Parse the nokey or badkey option, which indicates how we should act if
|
||||
* the user has no keyfile or the keyfile is invalid.
|
||||
*/
|
||||
static enum pam_oath_nokey
|
||||
pam_oath_nokey_option(pam_handle_t *pamh, const char *option)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
if ((value = openpam_get_option(pamh, option)) == NULL)
|
||||
return (nokey_fail);
|
||||
else if (strcmp(value, "fail") == 0)
|
||||
return (nokey_fail);
|
||||
else if (strcmp(value, "fake") == 0)
|
||||
return (nokey_fake);
|
||||
else if (strcmp(value, "ignore") == 0)
|
||||
return (nokey_ignore);
|
||||
openpam_log(PAM_LOG_ERROR, "the value of the %s option "
|
||||
"must be either 'fail', 'fake' or 'ignore'", option);
|
||||
return (nokey_error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a numeric option. Returns -1 if the option is not set or its
|
||||
* value is not an integer in the range [0, INT_MAX].
|
||||
*/
|
||||
static int
|
||||
pam_oath_int_option(pam_handle_t *pamh, const char *option)
|
||||
{
|
||||
const char *value;
|
||||
char *end;
|
||||
long num;
|
||||
|
||||
if ((value = openpam_get_option(pamh, option)) == NULL)
|
||||
return (-1);
|
||||
num = strtol(value, &end, 10);
|
||||
if (*value == '\0' || *end != '\0' || num < 0 || num > INT_MAX) {
|
||||
openpam_log(PAM_LOG_ERROR, "the value of the %s option "
|
||||
"is invalid.", option);
|
||||
return (-1);
|
||||
}
|
||||
return (num);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the location of the user's keyfile.
|
||||
*/
|
||||
static char *
|
||||
pam_oath_keyfile(pam_handle_t *pamh)
|
||||
{
|
||||
const char *keyfile;
|
||||
char *path;
|
||||
size_t size;
|
||||
|
||||
if ((keyfile = openpam_get_option(pamh, "keyfile")) == NULL)
|
||||
keyfile = pam_oath_default_keyfile;
|
||||
size = 0;
|
||||
if (openpam_subst(pamh, NULL, &size, keyfile) != PAM_TRY_AGAIN)
|
||||
return (NULL);
|
||||
if ((path = malloc(size)) == NULL)
|
||||
return (NULL);
|
||||
if (openpam_subst(pamh, path, &size, keyfile) != PAM_SUCCESS) {
|
||||
free(path);
|
||||
return (NULL);
|
||||
}
|
||||
return (path);
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the user's key.
|
||||
*/
|
||||
static struct oath_key *
|
||||
pam_oath_load_key(const char *keyfile)
|
||||
{
|
||||
|
||||
/* XXX should check ownership and permissions */
|
||||
return (oath_key_from_file(keyfile));
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the user's key.
|
||||
*/
|
||||
static int
|
||||
pam_oath_save_key(const struct oath_key *key, const char *keyfile)
|
||||
{
|
||||
char *keyuri;
|
||||
int fd, len, pam_err;
|
||||
|
||||
keyuri = NULL;
|
||||
len = 0;
|
||||
fd = -1;
|
||||
pam_err = PAM_SYSTEM_ERR;
|
||||
if ((keyuri = oath_key_to_uri(key)) == NULL)
|
||||
goto done;
|
||||
len = strlen(keyuri);
|
||||
if ((fd = open(keyfile, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0 ||
|
||||
write(fd, keyuri, len) != len || write(fd, "\n", 1) != 1) {
|
||||
openpam_log(PAM_LOG_ERROR, "%s: %m", keyfile);
|
||||
goto done;
|
||||
}
|
||||
pam_err = PAM_SUCCESS;
|
||||
done:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
if (keyfile != NULL) {
|
||||
memset(keyuri, 0, len);
|
||||
free(keyuri);
|
||||
}
|
||||
return (pam_err);
|
||||
}
|
||||
|
||||
PAM_EXTERN int
|
||||
pam_sm_authenticate(pam_handle_t *pamh, int flags,
|
||||
int argc, const char *argv[])
|
||||
{
|
||||
enum pam_oath_nokey nokey, badkey;
|
||||
struct passwd *pwd;
|
||||
const char *user;
|
||||
char *keyfile;
|
||||
struct oath_key *key;
|
||||
unsigned long response;
|
||||
char *password, *end;
|
||||
int pam_err, ret, window;
|
||||
|
||||
/* unused */
|
||||
(void)flags;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
keyfile = NULL;
|
||||
key = NULL;
|
||||
|
||||
openpam_log(PAM_LOG_VERBOSE, "attempting OATH authentication");
|
||||
|
||||
/* check how to behave if the user does not have a valid key */
|
||||
if ((nokey = pam_oath_nokey_option(pamh, "nokey")) == nokey_error ||
|
||||
(badkey = pam_oath_nokey_option(pamh, "badkey")) == nokey_error) {
|
||||
pam_err = PAM_SERVICE_ERR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* identify user */
|
||||
if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
|
||||
goto done;
|
||||
if ((pwd = getpwnam(user)) == NULL) {
|
||||
pam_err = PAM_USER_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
openpam_log(PAM_LOG_VERBOSE, "authenticating user %s", user);
|
||||
|
||||
/* load key */
|
||||
if ((keyfile = pam_oath_keyfile(pamh)) == NULL) {
|
||||
pam_err = PAM_SYSTEM_ERR;
|
||||
goto done;
|
||||
}
|
||||
openpam_log(PAM_LOG_VERBOSE, "attempting to load %s for %s", keyfile, user);
|
||||
key = pam_oath_load_key(keyfile);
|
||||
|
||||
/*
|
||||
* The user doesn't have a key, should we fake it?
|
||||
*
|
||||
* XXX implement badkey - currently, oath_key_from_file() doesn't
|
||||
* provide enough information for us to tell the difference
|
||||
* between a bad key and no key at all.
|
||||
*
|
||||
* XXX move this into pam_oath_load_key()
|
||||
*/
|
||||
if (key == NULL) {
|
||||
openpam_log(PAM_LOG_VERBOSE, "no key found for %s", user);
|
||||
switch (nokey) {
|
||||
case nokey_fail:
|
||||
pam_err = PAM_AUTHINFO_UNAVAIL;
|
||||
goto done;
|
||||
case nokey_fake:
|
||||
key = oath_key_dummy(om_hotp, oh_sha1, 6);
|
||||
break;
|
||||
case nokey_ignore:
|
||||
pam_err = PAM_IGNORE;
|
||||
goto done;
|
||||
default:
|
||||
/* can't happen */
|
||||
pam_err = PAM_SERVICE_ERR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* get user's response */
|
||||
pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
|
||||
(const char **)&password, PAM_OATH_PROMPT);
|
||||
if (pam_err != PAM_SUCCESS) {
|
||||
openpam_log(PAM_LOG_VERBOSE, "conversation failure");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* convert to number */
|
||||
response = strtoul(password, &end, 10);
|
||||
if (end == password || *end != '\0')
|
||||
response = ULONG_MAX;
|
||||
|
||||
/* verify response */
|
||||
if (key->mode == om_hotp) {
|
||||
if ((window = pam_oath_int_option(pamh, "hotp_window")) < 0 &&
|
||||
(window = pam_oath_int_option(pamh, "window")) < 0)
|
||||
window = PAM_OATH_HOTP_WINDOW;
|
||||
ret = oath_hotp_match(key, response, window);
|
||||
} else {
|
||||
if ((window = pam_oath_int_option(pamh, "totp_window")) < 0 &&
|
||||
(window = pam_oath_int_option(pamh, "window")) < 0)
|
||||
window = PAM_OATH_TOTP_WINDOW;
|
||||
ret = oath_totp_match(key, response, window);
|
||||
}
|
||||
openpam_log(PAM_LOG_VERBOSE, "verification code %s",
|
||||
ret ? "matched" : "did not match");
|
||||
if (ret == 0) {
|
||||
pam_err = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* write back (update counter for HOTP etc) */
|
||||
if (pam_oath_save_key(key, keyfile) != 0) {
|
||||
pam_err = PAM_SERVICE_ERR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
openpam_log(PAM_LOG_VERBOSE, "OATH authentication succeeded");
|
||||
pam_err = PAM_SUCCESS;
|
||||
done:
|
||||
oath_key_free(key);
|
||||
free(keyfile);
|
||||
return (pam_err);
|
||||
}
|
||||
|
||||
PAM_EXTERN int
|
||||
pam_sm_setcred(pam_handle_t *pamh, int flags,
|
||||
int argc, const char *argv[])
|
||||
{
|
||||
|
||||
/* unused */
|
||||
(void)pamh;
|
||||
(void)flags;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return (PAM_SUCCESS);
|
||||
}
|
||||
|
||||
PAM_EXTERN int
|
||||
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
|
||||
int argc, const char *argv[])
|
||||
{
|
||||
|
||||
/* unused */
|
||||
(void)pamh;
|
||||
(void)flags;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return (PAM_SUCCESS);
|
||||
}
|
||||
|
||||
PAM_MODULE_ENTRY("pam_unix");
|
|
@ -8,9 +8,6 @@ noinst_HEADERS = t.h
|
|||
TESTS =
|
||||
TESTS += t_openpam_readword
|
||||
TESTS += t_openpam_readlinev
|
||||
if WITH_OATH
|
||||
TESTS += t_rfc4648
|
||||
endif
|
||||
check_PROGRAMS = $(TESTS)
|
||||
|
||||
# libt - common support code
|
||||
|
@ -19,6 +16,3 @@ libt_a_SOURCES = t_main.c t_file.c
|
|||
|
||||
# link with libpam and libt
|
||||
LDADD = libt.a $(top_builddir)/lib/libpam/libpam.la
|
||||
if WITH_OATH
|
||||
LDADD += $(top_builddir)/lib/liboath/liboath.la
|
||||
endif
|
||||
|
|
194
t/t_rfc4648.c
194
t/t_rfc4648.c
|
@ -1,194 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2013 Universitetet i 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/openpam.h>
|
||||
#include <security/oath.h>
|
||||
|
||||
#include "t.h"
|
||||
|
||||
/*
|
||||
* Test vectors from RFC 4648
|
||||
*/
|
||||
static struct t_vector {
|
||||
const char *plain;
|
||||
/* const char *base16; */
|
||||
const char *base32;
|
||||
const char *base64;
|
||||
} t_vectors[] = {
|
||||
{
|
||||
.plain = "",
|
||||
.base32 = "",
|
||||
.base64 = "",
|
||||
},
|
||||
{
|
||||
.plain = "f",
|
||||
.base32 = "MY======",
|
||||
.base64 = "Zg=="
|
||||
},
|
||||
{
|
||||
.plain = "fo",
|
||||
.base32 = "MZXQ====",
|
||||
.base64 = "Zm8=",
|
||||
},
|
||||
{
|
||||
.plain = "foo",
|
||||
.base32 = "MZXW6===",
|
||||
.base64 = "Zm9v",
|
||||
},
|
||||
{
|
||||
.plain = "foob",
|
||||
.base32 = "MZXW6YQ=",
|
||||
.base64 = "Zm9vYg==",
|
||||
},
|
||||
{
|
||||
.plain = "fooba",
|
||||
.base32 = "MZXW6YTB",
|
||||
.base64 = "Zm9vYmE=",
|
||||
},
|
||||
{
|
||||
.plain = "foobar",
|
||||
.base32 = "MZXW6YTBOI======",
|
||||
.base64 = "Zm9vYmFy",
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Encoding test function
|
||||
*/
|
||||
static int
|
||||
t_rfc4648_enc(const char *plain, const char *encoded,
|
||||
int (*enc)(const uint8_t *, size_t, char *, size_t *))
|
||||
{
|
||||
char buf[64];
|
||||
size_t blen, ilen, olen;
|
||||
|
||||
blen = sizeof buf;
|
||||
ilen = strlen(plain);
|
||||
olen = strlen(encoded) + 1;
|
||||
if (enc((const uint8_t *)plain, ilen, buf, &blen) != 0) {
|
||||
t_verbose("encoding failed\n");
|
||||
return (0);
|
||||
}
|
||||
if (blen != olen) {
|
||||
t_verbose("expected %zu B got %zu B\n", olen, blen);
|
||||
return (0);
|
||||
}
|
||||
if (strcmp(buf, encoded) != 0) {
|
||||
t_verbose("expected \"%s\" got \"%s\"\n", encoded, buf);
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encoding test wrapper for base 32
|
||||
*/
|
||||
static int
|
||||
t_base32(void *arg)
|
||||
{
|
||||
struct t_vector *tv = (struct t_vector *)arg;
|
||||
|
||||
return (t_rfc4648_enc(tv->plain, tv->base32, base32_enc));
|
||||
}
|
||||
|
||||
/*
|
||||
* Encoding test wrapper for base 64
|
||||
*/
|
||||
static int
|
||||
t_base64(void *arg)
|
||||
{
|
||||
struct t_vector *tv = (struct t_vector *)arg;
|
||||
|
||||
return (t_rfc4648_enc(tv->plain, tv->base64, base64_enc));
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a test case for a given test vector
|
||||
*/
|
||||
static struct t_test *
|
||||
t_create_test(int (*func)(void *), const char *name, struct t_vector *tv)
|
||||
{
|
||||
struct t_test *test;
|
||||
char *desc;
|
||||
|
||||
if ((test = calloc(1, sizeof *test)) == NULL)
|
||||
return (NULL);
|
||||
test->func = func;
|
||||
if ((desc = calloc(1, strlen(name) + strlen(tv->plain) + 5)) == NULL)
|
||||
return (NULL);
|
||||
sprintf(desc, "%s(\"%s\")", name, tv->plain);
|
||||
test->desc = desc;
|
||||
test->arg = tv;
|
||||
return (test);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the test plan
|
||||
*/
|
||||
const struct t_test **
|
||||
t_prepare(int argc, char *argv[])
|
||||
{
|
||||
struct t_test **plan, **test;
|
||||
int n;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
n = sizeof t_vectors / sizeof t_vectors[0];
|
||||
plan = calloc(n * 2 + 1, sizeof *plan);
|
||||
if (plan == NULL)
|
||||
return (NULL);
|
||||
test = plan;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
*test++ = t_create_test(t_base32, "BASE32", &t_vectors[i]);
|
||||
*test++ = t_create_test(t_base64, "BASE64", &t_vectors[i]);
|
||||
}
|
||||
return ((const struct t_test **)plan);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
void
|
||||
t_cleanup(void)
|
||||
{
|
||||
}
|
Loading…
Reference in New Issue