RADIUS server using APM to authenticate users
Hi Stanislas,
per RFCs there is only a "MAY" demant for PAP based Radius authentication to include the Message-Authenticator attribute, since the User-Password field already provides some sort of origin checks by encrypting its value using the Radius Client specifc shared-key. Maybe this is the reason why APM didn't adopted this field...
But the Message-Authenticator attribute is still the better security mechanism to protect PAP based Radius requests, since it protects the entire request and not just the value of the password.
Without Message-Authenticator a spoofed but still valid Radius Request can be constructed even if you don't know the shared-key. But the authentication will most like fail and probably lock the account at some point since the password will become garbage after decryption...
With Message-Authenticator and a Radius policy configured to enforce Message-Authenticator usage the Radius stack can completely verify the Radius Request integrity before any heavy processing and the actual authentication is performed. So in the end it the Message-Authenticator may help to protect the Radius Server from overloading and may protect your account from becomming locked out.
Note: You don't have to include the Message-Authenticator attribute for non-EAP Radius responses. Its wasted computing power since the regular Radius Response Authenticator already signs the entire Radius Response in an as secure way. Furthermore Radius Client won't expect to receive this attribute on a response if the corresponding request was protected...
FYI: This is the code I'm using in my iRiule Radius Server implementation to verify the Message Authenticator attribute...
+ Handler for HMAC-based message authenticator attribute verification
log8 "Checking if HMAC-based message authenticator attribute usage is required for the RADIUS client."
if { $client(require_hmac) == 1 } then {
log8 "HMAC-based RADIUS request message authenticator usage is required.
log8 "Checking if the RADIUS request contains a HMAC-based message authenticator attribute."
if { [string length [set radius(request_hmac) [RADIUS::avp 80]]] == 16 } then {
log8 "The RADIUS request contains a HMAC-based message authenticator attribute.
log8 "Re-initializing the message authenticator attribute field (16 bytes) with 0x00 values."
RADIUS::avp replace 80 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
log8 "Performing HMAC-MD5 calculation on the initialized UDP payload using clients shared key."
log8 "Comparing the HMAC-MD5 calculation result with the received attribute value."
if { [CRYPTO::sign -alg hmac-md5 -key $client(shared_key) [UDP::payload]] eq $radius(request_hmac) } then {
log7 "The HMAC-MD5 signature could be sucessfully verified."
istats ISTATS::incr "ltm.virtual [virtual name] c Radius_HMAC_Verified" 1
} else {
log6 "The HMAC-MD5 signature from RADIUS client \"[IP::client_addr]\" could not be verified. Silently discard the packet..."
istats ISTATS::incr "ltm.virtual [virtual name] c Radius_HMAC_Failure" 1
istats ISTATS::incr "ltm.virtual [virtual name] c Radius_UDP_Drop" 1
UDP::drop
return
}
} else {
log6 "HMAC-based message authenticator attribute was not send by RADIUS client \"[IP::client_addr]\". Silently discard the packet..."
istats ISTATS::incr "ltm.virtual [virtual name] c Radius_HMAC_Missing" 1
istats ISTATS::incr "ltm.virtual [virtual name] c Radius_UDP_Drop" 1
UDP::drop
return
}
} else {
log7 "HMAC-based message authenticator attribute usage is not required for this RADIUS client."
}
Handler for HMAC-based message authenticator attribute verification
Note: The outlined code is my development-friendly syntax which gets slightly pre-compiled during run-time to make it more efficent and to enable istats and logs as needed.
Cheers, Kai