FreeRADIUS with OTP via PAM

This documentation will describe, how to setup a FreeRADIUS Server, that can authenticate users via PAM (Pluggable Authentication Modules). This document specifically describes the implementation of libpam-google-authenticator and libpam-oath.

The result will be ONLY A BASE SYSTEM. There is a lot of additional configuration necessary to make this a productive system like:

  • If using libpam-oath and libpam-google-authenticator together as optional modules in /etc/pam.d/radiusd you have to make sure you have different usernames for the 2 modules. If not, a failure will always increase the counter of the google-authenticator token and might bring it out of the window size
  • If you want to use non-local users make sure you change the settings for pam_google_authenticator so that it will look in a different location for the userfiles
  • If you did not use a fresh FreeRADIUS installation and modified a previous installation, make sure everything works correctly. It is very easy to misconfigure FreeRADIUS and let authentication succeed by mistake.
  • If you already have a RADIUS server but want to add a new one supporting OTP (google and oath) you might take a look at my documentation about a FreeRADIUS Proxy that decides which server to ask via REALMS based on regular expression checks with the usernames.

User authentication is a serious job. Any configuration errors could result in security breaches! - Keep that in mind!

But for now, go ahead and try this out, it really works! With this configuration you are able to use the following (tested) software and hardware tokens:

Google Authenticator for Android, iOS and Blackberry

Gooze c100 event based hardware token

Gooze c200 time based hardware token (HOTP/T60/6)

OATH Token iOS App

Prerequisites

We should have a debian based linux system with the following packages installed:

libpam-google-authenticator     - Google Authenticator PAM module
liboath0                        - OATH Toolkit Liboath library
libpam-oath                     - OATH Toolkit libpam_oath PAM module
oathtool                        - OATH Toolkit oathtool command line tool
datefudge                       - Fake the system date (optional)

You can take a look at my other documentations to see how to install them here:

libpam-google-authenticator

OATH Toolkit

Installation of FreeRADIUS

To install the FreeRADIUS server on our Debian machine we simply enter the following commands as the root user:

apt-get install freeradius freeradius-utils

This will install FreeRADIUS, the FreeRADIUS client utilities and all necessary dependencies. At this point we will NOT change any of the FreeRADIUS default passwords to make sure this documentation works. Please make sure, if you go productive with your system, that you change the default password (testing123) to something more secure.

Enable PAM and setup PAM as default authentication

Enable PAM

By default the following line is commented out in /etc/freeradius/sites-enabled/default.

#       pam

Make sure, you enable it to enable PAM. (remove the comment)

#
#  Pluggable Authentication Modules.
pam

The entire file (most comments removed should look like this:

######################################################################
#
#       As of 2.0.0, FreeRADIUS supports virtual hosts using the
#       "server" section, and configuration directives.
#
#       Virtual hosts should be put into the "sites-available"
#       directory.  Soft links should be created in the "sites-enabled"
#       directory to these files.  This is done in a normal installation.
#
#       $Id$
#
######################################################################
authorize {
        preprocess
        chap
        mschap
        digest
        suffix
        eap {
                ok = return
        }
        files
        expiration
        logintime
        pap
}

authenticate {
        Auth-Type PAP {
                pap
        }
        Auth-Type CHAP {
                chap
        }
        Auth-Type MS-CHAP {
                mschap
        }
        digest
        pam
        unix
        eap
}

preacct {
        preprocess
        acct_unique
        suffix
        files
}

accounting {
        detail
        unix
        radutmp
        exec
        attr_filter.accounting_response
}

session {
        radutmp
}

post-auth {
        exec
        Post-Auth-Type REJECT {
                attr_filter.access_reject
        }
}

pre-proxy {
}

post-proxy {
#        eap
}

Set PAM as default authentication type

Add the lines

#Added by PCFreak
DEFAULT Auth-Type := PAM

to your /etc/freeradius/users file to setup PAM as default authentication type. The file should then look like this (most comments removed):

#
#       Please read the documentation file ../doc/processing_users_file,
#       or 'man 5 users' (after installing the server) for more information.
#

DEFAULT Framed-Protocol == PPP
        Framed-Protocol = PPP,
        Framed-Compression = Van-Jacobson-TCP-IP

DEFAULT Hint == "CSLIP"
        Framed-Protocol = SLIP,
        Framed-Compression = Van-Jacobson-TCP-IP

DEFAULT Hint == "SLIP"
        Framed-Protocol = SLIP

#Added by PCFreak
DEFAULT Auth-Type := PAM

Enable Clients (clients.conf)

To be able to allow local clients (127.0.0.1) to authenticate, make sure your /etc/freeradius/clients.conf looks like this and contains a password.

client localhost {
        ipaddr = 127.0.0.1
        secret          = testing123
        require_message_authenticator = no
        nastype     = other     # localhost isn't usually a NAS...
}

If you want to access your FreeRADIUS server from an external IP make sure you add another section for the external client. I usually add my personal computer as a client to be able to do all tests, too. I prefer using the windows based tool NTRadPing

# access from my personal machine with fixed IP
client pcfreakbox {
        ipaddr = 192.168.178.234
        secret = testing123
        require_message_authenticator = no
        nastype = other
}

Start FreeRADIUS

For a test you should stop the FreeRADIUS service

service freeradius stop

and start FreeRADIUS from the command line to see some debug output.

freeradius -X

If FreeRADIUS stops at this point with an error message, you have to fix this error first, before you continue.

If everything went fine, you should see FreeRADIUS running and waint for requests:

...
... a lot of lines before ...
...
Listening on authentication address * port 1812
Listening on accounting address * port 1813
Listening on authentication address 127.0.0.1 port 18120 as server inner-tunnel
Listening on proxy address * port 1814
Ready to process requests.

If you want to debug, always service stop freeradius and freeradius -X. For now we stop debugging (press Ctrl+C) and re-start the server

service freeradius start

Testing our FreeRADIUS with PAM

Since the default configuration in /etc/pam.d/radiusd already includes the default system PAM modules we are able to test our FreeRADIUS servers PAM capability by invoking the following command

radtest <username> <password> 127.0.0.1 18120 <radius client password>

Please change the values to your needs. In my test environment root had the password LetMeIn so my request looked like this

radtest root LetMeIn 127.0.0.1 18120 testing123

!! Make sure you escape special characters like $. For example if your password is “Test$99” then you have to enter “Test\$99” here.

The above command should succeed and the result should look like this:

Sending Access-Request of id 64 to 127.0.0.1 port 1812
        User-Name = "root"
        User-Password = "LetMeIn"
        NAS-IP-Address = 127.0.1.1
        NAS-Port = 18120
rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=64, length=20

We know at this point, that our FreeRADIUS server is correctly configured for PAM authentication using PAM-modules from /etc/pam.d/radiusd.

Modification for Google Authenticator

If you want to authenticate users via libpam-google-authenticator, FreeRADIUS needs to run as user root, therefore change the following line in

/etc/freeradius/radiusd.conf

from

user = freerad

to

user = root

The group can stay the same (freerad).

Restart the FreeRADIUS server with

service freeradius restart

Create a token for libpam-oath

libpam-oath stores all user accounts in a single file. The default location is

/etc/users.oath

After installing libpam-oath the file is not there. I created a template with some documentation. So create a file /etc/users.oath now with the following content

### Fields
###   1. Token Type  See below
###   2. Username           User's username
###   3. PIN                User's PIN, or "-" if user has no PIN
###   4. Token Key          Secret key for the token algorithm (see RFC 4226)
###   5. Counter/Offset     Next expected counter value (event tokens) or counter offset (time tokens)
###   6. Last OTP           The previous successfully used one-time password
###   7. Time of Last OTP   Local timestamp when the last OTP was generated (in the form 2009-06-12T17:52:32L)
###
### Token Types
###   HOTP            - HOTP event-based token with six digit OTP
###   HOTP/E          - HOTP event-based token with six digit OTP
###   HOTP/E/8        - HOTP event-based token with eight digit OTP
###   HOTP/T30        - HOTP time-based token with 30 second interval and six digit OTP
###   HOTP/T60        - HOTP time-based token with 60 second interval and six digit OTP
###   HOTP/T60/5      - HOTP time-based token with 60 second interval and five digit OTP
###
### Samples
###    # Gooze c200 or Google-Authenticator (time-based)
###    HOTP time-based token with 60 seconds interval and 6 digit OTP and prefix 1234
###    HOTP/T60/6     tT123456        1234 99995BF224B2352885AABAA4DF3C13773AC5C883
###
###    HOTP time-based token with 60 seconds interval and 6 digit OTP - no prefix
###    HOTP/T60/6     tT123456        - 99995BF224B2352885AABAA4DF3C13773AC5C883  
###
###    # Gooze c100 or Google-Authenticator (event based) 
###    HOTP event-based token with 6 digit OTP and prefix 1234
###    HOTP/E/6       tT123456        1234    99996BF224B2352885AABAA4DF3C13773AC5C883
###
###    HOTP event-based token with 6 digits OTP, prefix 1234 and next expected counter value 27
###    HOTP/E/6       tT123456        1234    99996BF224B2352885AABAA4DF3C13773AC5C883        27
###
###    !!! DISABLED TOKEN MUST START WITH ## --> exactly 2 not more not less          !!!
###    !!! Comments # are allowed before or after a token line but not inside a token !!!
##########################################################################################
# START - Add accounts below here -                                                      #
##########################################################################################
#TYPE           USER    PASSD   SECRET                  COUNTER LASTPASS        TIME     #

Now generate a random 16 digit hex-code with the following command

for i in $(seq 1 20); do echo -n $(echo "obase=16; $(($RANDOM % 16))" | bc); done; echo

In my case the created hex-code was

C10C558DBF45DFE7D856

For testing purpose you should USE MY CODE when following this documentation.

Now add the following line to /etc/users.oath

HOTP/E/6        root     -       C10C558DBF45DFE7D856    0

This will create an event-based token (HOTP/E/6)with 6 digits, the username root without password prefix (-) using the token secret (C10C558DBF45DFE7D856). The initial counter of the token is set to 0.

Safe the file.

Create a token for libpam-google-authenticator

libpam-google-authentciator needs a single file for each user. The default setup for libpam-google-authenticator is to store a file .google-authenticator in the users home-directory.

This is no problem, if you want to authenticate “real” local users but does not make sence if you have “virtual” users since they don't even exist on your linux box and therefor have no home-directory.

At this point of the documentation we will now create a google-authenticator token for the currently logged on user. In my case this is the user “root”.

Enter the following command to generate a token for

google-authenticator -c -f -q -l root -Q none -r 3 -R 30 -w 10

The user root will now have a file “.google_authenticator”. Show it's contents with the following command

cat /root/.google_authenticator

It should look like this:

KJWJOFRUMJ7SCOCK
"RATE_LIMIT 3 30
" WINDOW_SIZE 10
" HOTP_COUNTER 1
61116293
13529265
12095888
35330501
90750662

The 8digit numbers at the end of the file are “scratchcodes”. They will always work and if used will be deleted from the file. They are ideal for us to test our RADIUS authentication later.

Enable PAM Modules

Prerequisites

In my previous documentation I described how to install

libpam-google-authenticator

and

libpam-oath.

Verify the correct installation by checking if the following 2 files exist:

/lib/security/pam_google_authenticator.so
/lib/security/pam_oath.so

If they do not exist, verify your installation before you continue.

Our FreeRADIUS server already supports PAM. It looks in the file /etc/pam.d/radiusd what PAM modules it should ask for authentication.

The standard entries in /etc/pam.d/radiusd are

@include common-auth
@include common-account
@include common-password
@include common-session

They are responsible to be able to use accounts from /etc/passwd. We don't want this, so we comment them out.

The file will now look like this:

#
# /etc/pam.d/radiusd - PAM configuration for FreeRADIUS
#

# We fall back to the system default in /etc/pam.d/common-*
#

#@include common-auth
#@include common-account
#@include common-password
#@include common-session

so it will do nothing.

libpam-google-authenticator

To add libpam-google-authenticator to the RADIUS PAM configuration add the following line to /etc/pam.d/radiusd

auth requisite pam_google_authenticator.so

so that it is the only line (comment out all others).

Remember our previously generated token with the following content (yours may vary).

KJWJOFRUMJ7SCOCK
"RATE_LIMIT 3 30
" WINDOW_SIZE 10
" HOTP_COUNTER 1
61116293
13529265
12095888
35330501
90750662

Use one of the “scratchcodes” and issue the following command (use one of your scratchcodes from your file)

radtest <username> <scratchcode> 127.0.0.1 18120 <radius password>

eg.

radtest root 12095888 127.0.0.1 18120 testing123

PAM-authentication via Google-Authenticator should succeed with the following message:

Sending Access-Request of id 214 to 127.0.0.1 port 1812
        User-Name = "root"
        User-Password = "12095888"
        NAS-IP-Address = 127.0.1.1
        NAS-Port = 18120
rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=214, length=20

If you now take a look at the tokenfile (/root/.google_authenticator) the scratchcode you used is removed and 4 more should remain.

KJWJOFRUMJ7SCOCK
"RATE_LIMIT 3 30
" WINDOW_SIZE 10
" HOTP_COUNTER 1
61116293
13529265
35330501
90750662

You have successfully configured your RADIUS server to use libpam-google-authenticator for authentication!

Info
If you want to add multiple PAM modules and users can login by having success with either one of them, use

auth optional pam_google_authenticator.so

instead of

auth requisite pam_google_authenticator.so

Also take a look at the man page of pam.conf (man 5 pam.conf) for more information.

libpam-oath

To add libpam-oath to the RADIUS PAM configuration add the following line to /etc/pam.d/radiusd

auth requisite pam_oath.so usersfile=/etc/users.oath window=10 digits=6

if it is the only module you want to use. If it is not the only one you might try something like

auth optional pam_oath.so usersfile=/etc/users.oath window=10 digits=6

In my case I already had configured libpam-google-authenticator in /etc/pam.d/radiusd and I wanted both modules be optional, meaning one of them is enough to successfully logon, so my file looks like this:

#
# /etc/pam.d/radiusd - PAM configuration for FreeRADIUS
#

# We fall back to the system default in /etc/pam.d/common-*
#

#@include common-auth
#@include common-account
#@include common-password
#@include common-session
auth optional pam_oath.so debug usersfile=/etc/users.oath window=20
auth optional pam_google_authenticator.so  

We previously created the file /etc/users.oath and added the following line

HOTP/E/6        root     -       C10C558DBF45DFE7D856    0

So let's create a password for the above secret C10C558DBF45DFE7D856 and a counter of 0 with oathtool:

oathtool -c 0 C10C558DBF45DFE7D856

The result will be this password (may vary if you used a different secret)

106996

We now have a password and can try to authenticate with the radtest utility

radtest <username> <generated password> 127.0.0.1 18120 <radius password>

eg.

radtest root 106996 127.0.0.1 18120 testing123

The output should be:

Sending Access-Request of id 40 to 127.0.0.1 port 1812
        User-Name = "root"
        User-Password = "106996"
        NAS-IP-Address = 127.0.1.1
        NAS-Port = 18120
rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=40, length=20  

To be sure, that libpam-oath has been used, take a look at the file /etc/users.oath. As you will see, the PAM module added the last used password and a time-stamp like this:

HOTP/E/6        root    -       C10C558DBF45DFE7D856    0       106996  2012-06-20T15:18:31L

This means, the token has been initialized. The next password the PAM module expects has the counter 1 and can be calculated with the following command:

oathtool -c 1 C10C558DBF45DFE7D856

So the next valid password will be

600944

We could also calculate the next 5 passwords starting from counter 1 with the following command

oathtool -c 1 -w 5  C10C558DBF45DFE7D856

and will get:

600944
984265
145499
535567
468669
857919

Try to use the last password in this list now with radtest

radtest root 857919 127.0.0.1 18120 testing123

The authentication should succeed. Now take a look at your /etc/users.oath

HOTP/E/6        root    -       C10C558DBF45DFE7D856    6       857919  2012-06-20T15:23:27L

The counter increased to 6, so the next valid password needs to have the counter 7 (or 7 + window size as configured in /etc/pam.d/radiusd).

Nice! You have now successfully configured your RADIUS server to use libpam-oath for authentication via PAM.

so that it is the only line (comment out all others).

Additional information

General about using Hard- and Software Tokens

time-based vs. event-based

I would recommend time-based tokens form hardware tokens and event-based tokens for software-tokens (like Authenticator, OATH Token).

Why?

It is very easy to clone a time-based token if you have the secret code. You can duplicate it as often as you like. All copies will show the same password at the same time. If this token is a hardware token, cloning is impossible. So better use only hardware token for time-based tokens.

If you initially setup an event-based token the token gets initialized with the counter 0. If you clone this token, both copies will show the same password. If you used the token once and authenticated successfully, the counter will increase. Since a bad guy who cloned your token does not easily know, what your current counter is after using the token for a while, his copy will be out of the window-size and never work.

One could say, and why not using hardware event-based token. Well, you know your users, they will press the button on their token just for fun, if they to that more than the configured window-size, the token will no longer work and you (the adminitrator) must synchronize it (edit the tokenfile) on the server side. You don't want to do this all the time, right?

Gooze c100 Token

The Gooze c100 is an event-based 6digit hardware token with a 40 character hexadecimal seed like this:

BB8F160AC1D153C52A50088E425BC731EC56788A

You could use the seed directly with libpam-oath. If you want to use this token with libpam-google-authenticator (writing the seed manually into a tokens configuration file) you need to convert the seed from hex to base32.

This can be easily done with oathtool by invoking it mit -v for verbose. It will then also show the base32 value of the hex seed like this:

# oathtool -v BB8F160AC1D153C52A50088E425BC731EC56788A
Hex secret: bb8f160ac1d153c52a50088e425bc731ec56788a
Base32 secret: XOHRMCWB2FJ4KKSQBCHEEW6HGHWFM6EK
Digits: 6
Window size: 0
Start counter: 0x0 (0)

743881

So the base32 representation of the hex key will be

XOHRMCWB2FJ4KKSQBCHEEW6HGHWFM6EK

You can use this value in your event-based users .google_authenticator file and it will work!

Gooze c200 Token

The Gooze c200 is a time-based 6digit hardware token that changes every 60 seconds. Because it changes every 60 seconds, you can not use it with libpam-google-authenticator, since it expects changes every 30seconds. c200 is at this point NOT compatible with google-authenticator but it works perfectly with libpam-oath!

The seed is 40 character hexadecimal like this:

EA81870D6B13E3447FDAD0AE676035ED440BBB69

You could use the seed directly with libpam-oath like this

HOTP/T60/6        root    -       EA81870D6B13E3447FDAD0AE676035ED440BBB69

Gooze c100 and c200 serial number

I was in contact with Gooze.eu headquarter in France and they gave me some nice information about the serial printed on the backside of the tokens:

Length of serial number: 13 digits

Digit 1                : OTP Type (1=c100=event-based 2=c200=time-based)
Digit 2                : Time interval in seconds (6=60seconds 0=c100=not used)
Digit 3                : algorithm (0=OATH)
Digit 4                : 0
Digit 5-8              : internal production information
Digit 9-13             : unique serial number

Here are 2 examples:

1000136202994
\\\\\   \______________ 02294 serial number
|||||__________________ 1362 internal production info
||||___________________ 0
|||____________________ 0 algorithm OATH
||_____________________ 0 time interval 0 (event based token)
|______________________ 1 OTP Type (1=event-based c100)


2600136302995
\\\\\   \______________ 02295 serial number
|||||__________________ 1363 internal production info
||||___________________ 0
|||____________________ 0 algorithm OATH
||_____________________ 6 time interval 6=60 seconds
|______________________ 2 OTP Type (2=time-based c200)  
    

So if you would like to use parts of the token serial number for your usernames you are doing best to use the most right 5 digits of the serial number.

Google Authenticator iOS App

The Google Authenticator iOS App works perfectly with libpam-google-authenticator. It is designed for

  • time-based tokens that change every 30seconds

or

  • event-based tokens

The tokens can be deployed by entering the seed (16 character long base32) or via QR-Codes. How to create the QR-Codes is described here. Even this is not the default, it will also work with 32 character long base32 secrets! (tested on iOS, Android and Blackberry)

You can clone a hardware token into the Google-Authenticator app by converting the seed to base32 and calculate the counter for the current password with oathtool. then generate a QR-Code that contains the token counter and it will work. (successfully tested that)

OATH Token iOS App

The OATH Token iOS App is very flexible. It can handle

  • time-based tokens (interval and digits can be set, digits can be displayed in hex)
  • event-based tokens (counter and digits can be set, digits can be displayed in hex)

It also can generate a random seed that you can then bring to the server. A nice feature is to be able to optionally “lockdown” the token. This means the configuration of the token cannot be changed inside the software.

OATH Token does not directly support the scanning of QR-Codes BUT if you have installed an additional App like the free version of Qrafter and scan a valid QR-Code based on this documentation, it will transfer the token directly into the app. Btw. you can add the “lockdown” feature to the QR-Code!

If you run into trouble, you have to start your QR-Code URL with the following

https://www.google.com/chart?chs=400x400&chld=M|0&cht=qr&chl=oathtoken:///addToken

The rest like

?name=hans&key=49AA5DAF3666A1B62333&numDigits=6&displayHex=false&counter=4&lockdown=true

has to be URL encoded and added at the end, so the result looks like this:

https://www.google.com/chart?chs=400x400&chld=M|0&cht=qr&chl=oathtoken:///addToken%3Fname%3DE00002%26key%3D49FE5DAF3666A1B62333%26numDigits%3D6%26displayHex%3Dfalse%26counter%3D4%26lockdown%3Dtrueounter%253D4%2526lockdown%253Dtrue

It was very easy for me to create a bash script that generates QR-Codes out of my users.oath file!

Qrafter iOS App

Qrafter is the only iOS app that perfectly supports the scanning of QR-Codes. It supports the URI-Format for “Google Authenticator” and also the URI-Format of “OATH Token”.

After scanning a QR-Code you have the option to “Open App URL”. This will result in opening either “Google Authenticator” or “OATH Token” (if installed) and add the token to them. - A must have app!

public/linux/otp/setup_feeradius_for_otp.txt · Last modified: 2015/08/11 08:20 (external edit)
CC Attribution-Share Alike 3.0 Unported
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0