This document describes two RADIUS security mechanisms:
This document covers what these security mechanisms are, how they are used, and when you should expect validation failure.
Per RFC 2865, the Authenticator Header is 16 bytes long. When it is used in an Access-Request, it is called a Request Authenticator. When it is used in any kind of response, it is called a Response Authenticator. It is used for:
If the server responds with the correct Response Authenticator, the client can compute if that response was related to a valid request.
The client sends the request with the random Authenticator Header. Then, the server that sends the response calculates the Response Authenticator with the use of the request packet along with the shared secret:
ResponseAuth = MD5(Code + ID + Length + RequestAuth + Attributes + Secret)
The client that receives the response performs the same operation. If the result is the same, the packet is correct.
Validation failure occurs if the switch does not cache the request anymore (for example, because of timeout). You might also experience it when the shared secret is invalid (yes - Access-Reject also includes this header). This way, the Network Access Device (NAD) can detect the shared secret mismatch. Usually it is reported by Authentication, Authorization, and Accounting (AAA) clients/servers as a shared key mismatch, but it does not reveal the details.
The Authenticator Header is also used in order to avoid sending the User-Password attribute in plain text. First the Message Digest 5 (MD5 - secret, authenticator) is computed. Then several XOR operations with the chunks of the password are executed. This method is susceptible for offline attacks (rainbow tables) because MD5 is not perceived as a strong one-way algorithm anymore.
Here is the Python script that computes the User-Password:
def Encrypt_Pass(password, authenticator, secret):
m = md5()
m.update(secret+authenticator)
return "".join(chr(ord(x) ^ ord(y)) for x, y in zip(password.ljust
(16,'\0')[:16], m.digest()[:16]))
If any of the attributes in the RADIUS Access-Request have changed (like the RADIUS ID, User-Name, and so on), the new Authenticator field should be generated and all other fields that depend on it should be recomputed. If this is a retransmission, nothing should change.
The meaning of the Authenticator Header is different for an Access-Request and an Accounting-Request.
For an Access-Request, the Authenticator is generated randomly and it is expected to receive a response with the ResponseAuthenticator calculated correctly, which proves that the response was related to that specific request.
For an Accounting-Request, the Authenticator is not random, but it is calculated (as per RFC 2866):
RequestAuth = MD5(Code + ID + Length + 16 zero octets + Attributes + Secret)
This way, the server can check the accounting message immediately and drop the packet if the recalculated value does not match the Authenticator value. The Identity Services Engine (ISE) returns:
11038 RADIUS Accounting-Request header contains invalid Authenticator field
The typical reason for this is the incorrect shared secret key.
The Message-Authenticator attribute is the RADIUS attribute defined in RFC 3579. It is used for a similar purpose: to sign and validate. But this time, it is not used in order to validate a response but a request.
The client that sends an Access-Request (it can also be a server that responds with an Access-Challenge) computes the Hash-Based Message Authentication Code (HMAC)-MD5 from its own packet, and then adds the Message-Authenticator attribute as a signature. Then, the server is able to verify it performs the same operation.
The formula looks similar to the Authenticator Header:
Message-Authenticator = HMAC-MD5 (Type, Identifier, Length, Request Authenticator,
Attributes)
The HMAC-MD5 function takes in two arguments:
The Message-Authenticator MUST be used for every packet, which includes the Extensible Authentication Protocol (EAP) message (RFC 3579). This includes both the client that sends the Access-Request and the server that responds with the Access-Challenge. The other side should silently drop the packet if validation fails.
Validation failure will occur when the shared secret is invalid. Then, the AAA server is not able to validate the request.
The ISE reports:
11036 The Message-Authenticator Radius Attribute is invalid.
This usually occurs at the later stage when the EAP message is attached. The first RADIUS packet of the 802.1x session does not include the EAP message; there is no Message-Authenticator field and it is not possible to verify the request, but at that stage, the client is able to validate the response with the use of the Authenticator field.
Here is an example to illustrate how you manually count the value in order to make sure it is computed correctly.
Packet number 30 (Access-Request) has been chosen. It is in the middle of the EAP session, and the packet includes the Message-Authenticator field. The aim is to verify that the Message-Authenticator is correct:
pluton # cat packet30-clear-msgauth.bin | openssl dgst -md5 -hmac 'cisco'
(stdin)= 01418d3b1865556918269d3cf73608b0
The same can be computed with the use of the Python script:
pluton # cat hmac.py
#!/usr/bin/env python
import base64
import hmac
import hashlib
f = open('packet30-clear-msgauth.bin', 'rb')
try:
body = f.read()
finally:
f.close()
digest = hmac.new('cisco', body, hashlib.md5)
d=digest.hexdigest()
print d
pluton # python hmac.py
01418d3b1865556918269d3cf73608b0
The previous example presents how to calculate the Message-Authenticator field from the Access-Request. For Access-Challenge, Access-Accept, and Access-Reject, the logic is exactly the same, but it is important to remember that Request Authenticator should be used, which is provided in the previous Access-Request packet.
Revision | Publish Date | Comments |
---|---|---|
1.0 |
20-Jan-2016 |
Initial Release |