Implementing EAP-‍SIM at Home

EAP-‍SIM is one of the authentication methods that can be used in an 802.1x or WPA Enterprise network. Specifically, it relies on the user’s SIM card to process a presented challenge. This has been used by some telcos to provide WiFi service without having to maintain a separate set of credentials. However, not all phones support EAP-‍SIM.

Phone displaying EAP-SIM as a WiFi authentication method

Since I’m already using a RADIUS setup at home, the use of EAP-‍SIM will eliminate the need to install my CA certs onto each device. But of course, there is still a fair bit of work to do…

Reading the SIM

I bought a cheap SIM card reader for under $4 from DX (my favourite shoppping site for nonsense like this). Unfortunately, the card reader was so cheap it could not work reliably.

Photo of SIM card reader PCB with SIM slot visible

There are generally 2 kinds of smart card readers: PC/SC and Phoenix-compatible. Smart cards use the same frame format as the RS-‍232, therefore with the correct crystal and baud rate combination, it is possible to read a smart card using a serial port. This is how Phoenix-compatible card readers work.

This cheap SIM card reader is a Phoenix-compatible reader, but uses the PL2303 serial-to-USB chip to expose a USB interface. The PL2303 chip on this reader was scratched off, which could indicate it may not be a genuine chip. I populated a couple of empty footprints on the PCB with capacitors but it still fails to be recognized sometimes. You can see the flux residue below:

Photo of component side of SIM card reader, after rework to add capacitors

It comes with a CD with Windows drivers and a Windows application. Needless to say, I threw away the box and CD. Instead, I found a nice Python framework called pySim that is able to communicate with both Phoenix-compatible readers and PC/SC readers.

EAP-‍SIM relies on the GSM authentication triplets for security. Given a random number RAND, the card computes an expected response SRES and a session key Kc using its secret Ki, which is never exposed. The AuC (authentication centre, or in this case the telco) also knows the Ki and is thus able to compute the same SRES and Kc values. Together, the RAND, SRES and Kc make up the authentication triplets.

The “Run GSM Algorithm” APDU was already implemented in pySim (but not used), so I added the pySim-run-gsm.py script to run the algorithms and output a simtriplets file:

./pySim-run-gsm.py -n 3 >> /etc/raddb/simtriplets

The simtriplets file should look something like the following:

# IMSI         , RAND          , SRES   , Kc
525xxxx163xxxx0,db8844...38a327,1fxxxxe8,c52xxxxxxxxx1c44
525xxxx163xxxx0,e3d0eb...752fac,41xxxxd7,edfxxxxxxxxx72ba
525xxxx163xxxx0,914c4a...e82ba5,c0xxxx3a,284xxxxxxxxx9970

I added a delay every 5 iterations, just in case the card had some limit and locks us out. Earlier versions of the algorithm (COMP128v1) had a flaw that leaked the secret Ki through ciphertexts, so card manufacturers might throttle the number of runs to prevent such attacks.

FreeRADIUS Configuration

I’m using FreeRADIUS 2.1.12 on CentOS 6. The CentOS/RHEL package doesn’t ship with rlm_sim_files but that functionality can supposedly be added through existing modules. After reading the source file rlm_sim_files.c, I thought it could be easily added into the users file, like some examples I have seen. However, I kept getting the “can not initiate sim, no RAND1 attribute” error. I finally found out what was wrong when I saw this message:

Looking at the rlm_eap_sim module, the RAND attributes have to go into the reply, not the check items. Ugh.

See “man unlang” in 2.0 for putting attributes into the reply list. Don’t use the “users” file.

By putting the values in the users file, they get added to the control list, but the module expects the RAND attributes to be in the reply list. This StackOverflow answer best describes how the users file works, and in general, attribute-value pair (AVP) lists in FreeRADIUS.

Despite what Alan DeKok says, we can actually use the users file and the unlang module to make this work. This approach avoids us having to recompile FreeRADIUS with the rlm_sim_files module, though the users file might get unwiedly after a while.

First, add the single line below to users file based on the values you have extracted from your SIM card:

1525000116337555@wlan.mnc001.mcc525.3gppnetwork.org    EAP-Type := SIM,
	EAP-Sim-RAND1 := 0x888...3237, 
	EAP-Sim-SRES1 := 0x1fad1278, 
	EAP-Sim-KC1   := 0xc526921113891444, 
	EAP-Sim-RAND2 := 0xe3d...5acc, 
	EAP-Sim-SRES2 := 0x41bd49dd, 
	EAP-Sim-KC2   := 0xedfab114663372bb, 
	EAP-Sim-RAND3 := 0x914...db15, 
	EAP-Sim-SRES3 := 0xc010313a, 
	EAP-Sim-KC3   := 0x2846fffb5aab9970

Note that the identity consists of the realm (the @wlan... part) described in section 4.2.1.5 of RFC 4186 and the username in the following section. wpa_supplicant follows the RFC and prefixes the IMSI with a 1 to indicate EAP-‍SIM (the code can be traced to a switch-case at the end of the eap_sm_imsi_identity function).

Next, add the following block to your authorize { ... } section, after the files directive to read your users file:

if (User-Name =~ /^[0-9]+/) {
  update reply {
	EAP-Sim-Rand1 := "%{control:EAP-Sim-Rand1}"
	EAP-Sim-Rand2 := "%{control:EAP-Sim-Rand2}"
	EAP-Sim-Rand3 := "%{control:EAP-Sim-Rand3}"
	EAP-Sim-SRES1 := "%{control:EAP-Sim-SRES1}"
	EAP-Sim-SRES2 := "%{control:EAP-Sim-SRES2}"
	EAP-Sim-SRES3 := "%{control:EAP-Sim-SRES3}"
	EAP-Sim-KC1   := "%{control:EAP-Sim-KC1}"
	EAP-Sim-KC2   := "%{control:EAP-Sim-KC2}"
	EAP-Sim-KC3   := "%{control:EAP-Sim-KC3}"
  }
}

This update block will copy the required variables over, provided there was a matching user (that begins with numbers).

A Better Alternative

The rlm_eap module only requires at maximum 3 triplets to be sent, and therefore the users file only contains 3 hardcoded triplets. If you are indeed the operator and know the SIM Ki, you can write a module that computes SRES and Kc dynamically. However, since I most definitely am not, the next best thing to do is to query a bunch of values from the SIM card and have a module randomly pick 3 each time. I wrote a Python module that does exactly that.

You will need to install the Python “module” into the site-packages directory so that FreeRADIUS can find it. Subsequently, add a module file that specifies the functions in the Python module:

pip install https://bitbucket.org/geekman/simtriplets/get/tip.tar.gz

curl https://bitbucket.org/geekman/simtriplets/raw/tip/simtriplets_module > /etc/raddb/modules/simtriplets

Add the line simtriplets at an appropriate location within the authorize { ... } block. For now, the location of the simtriplets “database” file is hardcoded to /etc/raddb/simtriplets. Until such time that FreeRADIUS implements some method of passing configuration values to the Python module, we are stuck with this.

That’s it. You should see the following output in the FreeRADIUS log:

Info: Loaded virtual server <default>
Info: Loaded virtual server inner-tunnel
Info: [simtriplets.py] instantiated simtriplets.py
Info: [simtriplets.py] loaded 2 IMSIs
Info: Ready to process requests.

To prevent cluttering up the logs, the simtriplets.py module is usually very quiet. It is therefore helpful to run radiusd -X to enable full debugging.

Security

Section 12.3 of RFC 4186 describes security concerns, such as mutual authentication and the leakage of SRES and Kc values. Before reading the RFC, I assumed that the EAP peer (mobile device) blindly transmits its computed SRES and Kc values to the server, in clear. This is, of course, an incorrect assumption.

During the EAP exchange, the server selects 2 or 3 RAND values and computes an AT_MAC value to be sent back together with the RAND values. Using the AT_MAC value, the peer is able to confirm that the server indeed knows the SRES and Kc values before it replies with its own calculated AT_MAC value that includes the SRES values – the raw SRES values are never sent in clear.

The EAP-‍SIM authentication method implemented this way provides sufficient security for my purposes.

References

Here are some additional documents you might want to read up on: