Adding Authentication and Encryption to the Public Release
The C2.8 commercial release currently supports A3/A8 authentication via a SIP interface modeled on the IMS authentication exchange. This procedure is similar to SIP digest authentication, but using the RAND as a the nonce and an externally-supplied A3/A8 algorithm in place of MD5 or SHA2. An implementation of COMP128v1 is provided as an example A3/A8. This capability was brought into the subscriberRegistry/features/a3a8 branch of the public release in r2583 and into the openbts/features/a3a8 in r2878. So at this point, these feature branches, together, support authentication for COMP128v1 SIMs. But as of r2878 they do not yet support encryption.
To add encryption to this system, we need to:
- Add code to sipauthserve to generate Kc when we run A3/A8 and send that Kc back to OpenBTS in the SIP 200 OK response in some kind of SIP header.
- Add code to SIPEngine to extract Kc from the 200 OK and store it in gTMSITable.
- Add code to GSML3RRMessages to encode the Ciphering Mod Command (GSM 04.08 9.1.9) and decode the Ciphering Mode Complete message (GSM 04.08 9.1.10).
- Add an XOR step to the L1 FEC encoder (GSM::L1Encoder) and decoder (GSM::L1Decoder) to apply the cipherstream.
- Add a cipherstream generator to the system somewhere. For simplicity, the cipherstream generator should be continuously active, and just generate a stream of 0s for Kc=0. The input to the generator is the frame number and Kc. The output of the generator is a frame of cipherstream bits. If we are smart, we will find a way to avoid calling the generator twice in a row with the same parameters.
- Add methods to GSM::L1FEC and GSM::LogicalChannel to set Kc.
The total authentication/encryption process is:
- Generate a Kc in sipauthserver when we run A3/A8.
- Send that Kc back to OpenBTS in the SIP 200 OK response in some kind of SIP header or content.
- Store Kc locally in the TMSI table.
- When we start a new transaction, at some point early in that transaction, the handset will identify itself by IMSI or TMSI. When this happens, we start the ciphering process with the Ciphering Mode Command message (GSM 04.08 9.1.9).
- Set the Kc on the L1 decoder part of the logical channel. Because GSM::L1FEC::writeHighSide() is blocking and synchronous, synchronization of the L1 Kc change with the outgoing frame stream should be simple.
- The L1 decoder watches for the first valid inbound frame with ciphering turned on. When it arrives, the L1 decoder sets Kc on the corresponding L1 encoder using the mSibling pointer. (See GSM 03.20 4.5.)
- Receive the Ciphering Mode Complete message (GSM 04.08 9.1.10).
(We need a new message flow diagram for this.)
This is all for a minimal first-cut implementation. For longer term, scalable ciphering support, we will need other work as well, but we can deal with that once this basic plan is in place. The phases of implementation are:
- Get A3/A8 and ciphering working for LUR.
- Add ciphering to other transactions, using the Kc stored in the TMSI table, referenced by key sequence number.
- Add authentication and Kc generation to other transactions.
Kc is generated along with SRES when comp128v1 (or any other A3/A8) is invoked in SubscriberRegistry?. Acquiring it is just a matter of adding a little extra string processing to sipauthserve.
Ciphering Key Sequence Number (CKSN)
From GSM 04.08 220.127.116.11:
The security parameters for authentication and ciphering are tied together in sets, i.e. from a challenge parameter RAND both the authentication response SRES and the ciphering key can be computed given the secret key associated to the IMSI.
In order to allow start of ciphering on a RR connection without authentication, the ciphering key sequence numbers are introduced. The sequence number is managed by the network in the way that the AUTHENTICATION REQUEST message contains the sequence number allocated to the key which may be computed from the RAND parameter carried in that message.
The mobile station stores this number with the key, and indicates to the network in the first message (LOCATION UPDATING REQUEST, CM SERVICE REQUEST, PAGING RESPONSE, CM RE-ESTABLISHMENT REQUEST) which sequence number the stored key has. When the deletion of the sequence number is described this also means that the associated key shall be considered as invalid.
The network may choose to start ciphering with the stored key (under the restrictions given in 3GPP TS 02.09) if the stored sequence number and the one given from the mobile station are equal.
Sending Kc to OpenBTS
Kc should be communicated to OpenBTS in the final 200 OK response from sipauthserve.
Use SIP 200 OK message with Authentication-Info header set to Kc, and cnonce value set to CKSN.
- This header is already use in IMS AKA protocol, RFC3310.
- Supported by oSIP library which is already used in OpenBTS: http://www.antisip.com/doc/osip2/group__oSIP__AUTH__INFO.html.
Available via following repositories:
- git clone git://github.com/zabbal/openbts-p2.8.git -b authenc
- git clone git://github.com/zabbal/subscriberRegistry.git -b authenc
(Note to Range developers: Do not even look at the above repositories.)
Storing Kc and CKSN Locally in OpenBTS
When Kc and CKSN arrives in the 200 OK, they should be stored locally in the TMSI table. When a channel is actually using Kc, the active Kc value is also stored in the L1FEC for that channel. A Kc value of zero will indicate that cihpering is off. Setting the Kc value on the L1FEC results in immediate application of the new ciphering setting. The actual Kc value should be kept in L1FEC, with accessor in the L1Encoder and L1Decoder classes and a passthrough accessor in LogicalChannel so that it can also be presented in the transaction table records.
Cipher Stream Generation
For licensing compatibility with both the public and commercial releases, the A5/1 cipher stream generator needs to be under a permissive (non-copyleft) license, like this one. Maybe we can speed that up a little if nobody else has. The proper place for cipherstream generation is in the lower parts of L1. See the next section for details.
Cipher Stream Application
An earlier plan called for Kc to be in GSM::L1FEC and accessed from there by GSM::L1Encoder and GSM::L1Decoder.
But that won't work, since we need to set Kc on uplink and downlink at different times (GSM 03.30 4.5). So the encoder and decoder need separate Kc values and the decoder needs to be able to control Kc on the encoder. This would work just fine if we keep bool flags indicating whether encryption has been enabled for particular direction or not. The Kc value is common for both uplink and downlink and hence should be stored in single place: GSM::L1FEC.
The best place to apply the downlink cipher stream is in XCCHL1Encoder::transmit() in GSM/GSML1FEC.cpp.
The best place to apply the uplink cipher stream is in TCHFACCHL1Decoder::processBurst() for TCH/F+FACCH and XCCHL1Decoder::processBurst() for everything else. Both of these are in GSM/GSML1FEC.cpp.