

    X9.9 Token Module


0.  INTRODUCTION

    This module allows the RADIUS server to authenticate users that hold
    ANSI X9.9 challenge/response tokens.  These tokens are basically
    handheld DES calculators and are sold by various vendors.  Currently
    known vendors are:

	CRYPTOCard (RB-1, KT-1)
	<http://www.cryptocard.com/>
	Full support.

	Secure Computing (SafeWord (various models))
	<http://www.securecomputing.com/index.cfm?sKey=688>
	Not supported.
	Formerly Enigma Logic.

	VASCO (DigiPass (various models))
	<http://www.vasco.com/R3DEngine.asp?reference=03-01.01-01&lang=en>
	Not supported.

	ActivCard (ActivCard One)
	<http://www.activcard.com/>
	Not supported (patented sync mode).

	PassGo (Defender aka SNK, Defender Plus, Defender One)
	<http://www.passgo.com/products/defender/>
	Not supported.
	This product has a history of acquisition:
	PassGo, Symantec, AXENT, AssureNet Pathways (name change only),
	Digital Pathways.  Also, to add to the fun, PassGo was acquired
	by AXENT, whom Symantec then acquired.  The original product
	seems to have been called "SecureNet Key" aka SNK or SNK/4.

    If you know of other vendors, please email me (frank@google.com)
    and I'll add them to the list above.  If you own any of the above
    tokens and would like support added (except ActivCard and PassGo),
    and can send me the docs and some sample tokens, I will be happy to
    add support.

    Although ActivCard has full specs, I cannot add support because their
    synchronous algorithm is patented.  Oh, well, their loss.

    The PassGo Defender One is an OEM version of the ActivCard One and
    so it suffers from the same patent issues.  I believe the Defender Plus
    also uses the same algorithm.  The Defender doesn't support a sync
    mode, so support for PassGo tokens will probably never be added.

    Note that I would be happy to add support for ActivCard/PassGo if
    ActivCard will give me a license to implement and distribute code.

    I believe that most of the above tokens should work in "generic" mode,
    however, this is highly discouraged due to the weakness of DES.

    No support is available for programming tokens.  You will need to
    write this yourself, or use the vendor's programming tools and extract
    the key information in order to use this module.

    I *strongly* discourage the use of "soft tokens" or Palm tokens.  These
    are easily compromisable, since the key is insufficiently protected.

    In addition to this freeradius module, I will make a PAM module available
    that will support the same file format.  These docs will be updated
    when the module is available (ETA before Dec 31, 2001).


1.  STRONG WARNING SECTION

    ANSI X9.9 has been withdrawn as a standard, due to the weakness of DES.
    An attacker can learn the token's secret by observing two
    challenge/response pairs.  See ANSI document X9 TG-24-1999,
    <http://www.x9.org/TG24_1999.pdf>.

    The obvious fix is to not display the challenge; the attacker will
    not have access to the plaintext.  This is possible since most X9.9
    tokens support a synchronous mode; the only exception I know of is
    the PassGo Defender.  So, in synchronous modes, the challenge presented
    to the user is NOT the challenge used for response calculation.
    Read on for more info.

    The default configuration of this module effectively disables pure
    challenge/response (hereafter: async) mode.


2.  INSTALLATION

    You'll need to have openssl, <http://www.openssl.org/>, installed.
    I am using 0.9.6b, but I suspect this module will work with all versions.

    You will also need /dev/urandom available.  AFAIK, this is available on
    Linux and *BSD.  For Solaris, you'll need to install the SUNWski
    package (look on SunSolve).  Information for other OS's is welcome.

    This module will only work on ILP32 machines, so if you build it
    as 64-bit under Solaris, you'll find that it fails at runtime.
    Solaris supports 32-bit and 64-bit binaries, so just build as 32-bit.
    If you are running UltraLinux (?) or NetBSD/sparc64, you are probably
    out of luck.  I'm willing to add the support needed if anyone actually
    has a need to run on those platforms.

    You'll also need to write a site-specific challenge transform in order
    to use async mode.  You will almost certainly need async mode, to sync
    the user's token with the server initially.  More on this below.


3.  END-USER OPERATION

    "Normally", upon login, users would enter enter the challenge into
    their token and give the server the response.  However, this is unsafe
    given that DES is so weak.  Luckily, most tokens support a synchronous
    mode which lets the user skip the part where they enter the challenge.

    For some tokens, the token displays the synchronous challenge, which
    typically the user would verify is the same as the challenge presented
    by the server.  Then they can safely just press "ENT" and enter the
    response.  This is very easy to use, but we're still stuck with the
    problem that an attacker has observed a plaintext/ciphertext pair.

    So instead of presenting the synchronous challenge, the server ALWAYS
    displays a random challenge.  Instead of verifying that the challenge
    matches the token display, the user should just press "ENT" and enter
    the response.  This might be confusing, you will need to train users.
    Even with training, they will forget.  Be warned!

    For other tokens, the token does not display the synchronous
    challenge, only the response is displayed.  This is a bit easier on
    the user, they won't be confused as to which number to enter for the
    response.  Since the token's challenge display really just serves
    to verify the sync state, and we don't present that information,
    I recommend operating tokens in the no-challenge-display mode if
    possible.  The disadvantage is that the user cannot resync the token.

    I will go out on a limb here and say that as long as the user doesn't
    play with the token, the token will almost never get out of sync.
    The only way I can see this really happening (besides state file
    corruption) is if a future response, within ewindow_size, differs
    from the "current" response by only a digit or a transposition, and
    the user typos the response entry -- a near impossible turn of events.

    In addition to the shielding of the plaintext, and ease of use,
    another advantage of sync mode is to support authentication methods
    where a challenge cannot be presented to the user, e.g. when using
    the Microsoft Windows VPN client.  [This support does not exist yet.]
    

4.  SITE-SPECIFIC CHALLENGE TRANSFORM

    Even though the normal mode of operation will be sync mode,
    we want async mode support for (at least) two reasons:

        1) to sync/resync the token, and
        2) because state is not shared across multiple RADIUS servers.

    Note that only some tokens support "user" sync/resync.  For others,
    an admin must create the initial state and manual intervention is
    required for resync.

    Since pure challenge/response is unsafe, I came up with the concept
    of the "site-specific challenge transform".  For the user, this
    means that instead of entering the challenge as presented to them,
    they enter something based on the challenge.  For example, a simple
    transform would be to enter the challenge backwards; if the server
    presents "123456" the user enters "654321".  This has the effect
    that an observer does not have access to the plaintext.

    This is security through obscurity, and is not really "safe", but
    for an outsider it may present at least some barrier.  Even though
    it presents no advantage in the face of a determined attacker, I
    recommend using it.

    The server logs each time a user authenticates via async mode, so
    I recommend a log scanner which alerts you to this.  You should
    reprogram tokens when the user authenticates via async mode.

    Instead of, or in addition to, implementing a site-specific challenge
    transform, you might wish to restrict async mode to specific NAS's.
    You can probably do this via hints configuration and separate
    x99_token instances.  If someone can supply a working config
    example, I will include it here.

    x99_site.c implements the site-specific challenge transform.  The
    default transform is to replace the challenge with the text "DISABLED".
    This effectively disables async mode (the user will not be able to
    enter this into their token).

    If you do not believe applying a transform gives any advantage,
    you can just comment out the single line of code there.  This actually
    may have some benefit, since your users don't need to be trained.
    I can guarantee your most annoying user will complain when they can't
    remember what they really are supposed to enter into the token.
    Also, this can be safe if you diligently reprogram tokens when async
    mode has been used.  You might automatically disable a token after two
    async authentications.

    DO NOT use the transform suggested above, reversing the challenge.
    That is now exceptionally weak.  An example of a possibly strong
    transform is to have the user enter the square of the challenge.
    The VASCO DigiPass 500 is also a [regular] calculator, so this
    could be a good one if you use that token.  Well, there's no support
    for that token yet, and now that I've mentioned it, it is another
    exceptionally weak transform, but you get the idea.

    Note that the CRYPTOCard RB-1 supports arbitrarily long challenge
    strings.  You should take advantage of this when implementing your
    transform.  You will still have to stay under MAX_CHALLENGE_LEN
    digits.  (This is why MAX_CHALLENGE_LEN is set to 32 even though
    the displayed challenge would generally be much smaller.)


5.  CONFIGURATION

    Most of the configuration is documented fairly well in the sample
    x99.conf file.  I will only discuss a few options here.

    ewindow_size:  This is how far out of [event] sync the server can
    get with the token.  The value is how far the user can be ahead of
    the server -- essentially how many times the user can play with the
    token.  You'll want to set this to at least 1 or 2, in case the user
    mistypes the response and the token turns off before he is able to
    try again.  It's 'e'window because I am reserving twindow for
    time synchronous modes.


6.  FILES

    See the sample x99passwd file.  State files are stored in
    /etc/x99sync.d by default.  There is one state file per user.
    The state file contains the information needed for synchronous
    mode; also the number of consecutive failed logins and the last
    time the user authenticated via async mode is stored here.


7.  LOG MESSAGES

    All errors contain the word "unable" or "bad".  You will want
    to scan for these automatically or periodically.  "bad state" messages
    indicate a problem with the State attribute, which the server uses
    to track challenges (for async mode).  They are all of the form
    "bad state for [%s]: <problem>", where <problem> is one of:

    length:  The length is not as expected.  Could be an attempted attack,
             but more likely a network blip.
    hmac:    The state is protected by a cryptographic hash which was not
             able to be verified.  This could be because you just HUP'd
             the server.
    expired: The state is older than maxdelay seconds.  If you get a lot
             of these you may wish to increase the value.
    missing: This should never happen and indicates a bug.

    Another message you'll want to lookout for is
    "%d/%d failed/max authentications" which indicates a user that is
    locked out due to exceeding maxfail failures.  You can reset this
    user by editing the state file (see x99passwd.sample).

    Also, look for "[%s] authenticated in async mode" which indicates
    a user with a sync mode card that used async authentication.  You
    may wish to reprogram these users' cards.


8.  ACKNOWLEDGEMENTS

    Author: Frank Cusack <frank@google.com>
    I would like to thank Google for allowing (encouraging) me to release
    this code.

