This document describes two RADIUS security mechanisms:
- Authenticator Header
- Message-Authenticator attribute
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:
- Authentication of response
- Password hiding
Authentication of Response
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.
When should you expect validation failure?
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()
return "".join(chr(ord(x) ^ ord(y)) for x, y in zip(password.ljust
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,
The HMAC-MD5 function takes in two arguments:
- The payload of the packet, which includes the 16 byte Message-Authenticator field filled with zeros
- The shared secret
When should the Message-Authenticator be used?
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.
When should you expect validation failure?
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.
Validate the Message-Authenticator Attribute
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:
- Right-click Radius Protocol and choose Export selected packet bytes.
- Write that RADIUS payload to a file (binary data).
- In order to compute Message-Authenticator field, you must put zeros there and compute the HMAC-MD5.
For example, when you use hex/binary editor, such as vim, after you type ":%!xxd", which switches to hex mode and zeroes 16 bytes starting after "5012" (50hex is 80 in dec which is Message-Authenticator type, and 12 is the size which is 18 including the Attribute Value Pairs (AVP) header):
After that modification, the payload is ready. It is necessary to return back to hex/binary mode (type: ":%!xxd -r") and save the file (":wq").
- Use OpenSSL in order to compute HMAC-MD5:
pluton # cat packet30-clear-msgauth.bin | openssl dgst -md5 -hmac 'cisco'
The HMAD-MD5 function takes two arguments: the first one from standard input (stdin) is the message itself and the second one is the shared secret (Cisco in this example). The result is exactly the same value as the Message-Authenticator attached to the RADIUS Access-Request packet.
The same can be computed with the use of the Python script:
pluton # cat hmac.py
f = open('packet30-clear-msgauth.bin', 'rb')
body = f.read()
digest = hmac.new('cisco', body, hashlib.md5)
pluton # python hmac.py
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.