Skip to content

[defect]: Incorrect example for dynamic loading of certificate chains #5735

@sigprof

Description

@sigprof

What type of defect/bug is this?

Unexpected behaviour (obvious or verified by project member)

How can the issue be reproduced?

In the v3.2.x branch raddb/certs/realms/README.md contains this unlang example code:

authenticate {
	...
	Auth-Type eap {
		if ("%{unpack:&EAP-Message 4 byte}" == 1) {
			update control {
				TLS-Session-Cert-File := "${certdir}/realms/%{Realm}"
			}
		}

		eap
	}
	...
}

However, this example is not 100% correct — it handles only EAP Identity requests, so it works for the method specified in default_eap_type, but not for any other methods which may be supported by the server. E.g., if using default_eap_type = ttls, but the client supports only PEAP, and the server also allows PEAP, the server would try to start TTLS first, and the client will send a NAK EAP-Message specifying PEAP, then the server will abandon TTLS and try to start PEAP; but the example code above won't set TLS-Session-Cert-File at this point, therefore PEAP will use the default TLS certificate instead of the one matching the realm.

A more correct condition may look like

		if ("%{unpack:&EAP-Message 4 byte}" == 1 || "%{unpack:&EAP-Message 4 byte}" == 3) {

Alternatively, the code may rely on the eap module setting the EAP-Type attribute when invoked from the authorize section:

		if (&request:EAP-Type == Identity || &request:EAP-Type == NAK) {

And yet another option could be to omit that condition check completely and just set TLS-Session-Cert-File every time (the eap module code would just ignore that attribute if the TLS session is either unneeded or had been started already).

Which of those three options would be better to show in the example code? (Looks like this would be relevant only for the v3.2.x branch, because there is no raddb/certs/realms/README.md in the master branch anymore.)

And there is another problem in that example code:

				TLS-Session-Cert-File := "${certdir}/realms/%{Realm}"

There is no .pem suffix there, therefore the code is not compatible with the realms_dir option, which loads only *.pem files from the specified directory. So that line should be changed to

				TLS-Session-Cert-File := "${certdir}/realms/%{Realm}.pem"

Log output from the FreeRADIUS daemon

# Relevant part for TTLS with the original code (works when TTLS is the default)

(0) Found Auth-Type = eap
(0) # Executing group from file /etc/raddb/sites-enabled/default
(0)   Auth-Type eap {
(0)     if ("%{unpack:&EAP-Message 4 byte}" == 1) {
(0)     EXPAND %{unpack:&EAP-Message 4 byte}
(0)        --> 1
(0)     if ("%{unpack:&EAP-Message 4 byte}" == 1)  -> TRUE
(0)     if ("%{unpack:&EAP-Message 4 byte}" == 1)  {
(0)       update control {
(0)         EXPAND /etc/raddb/certs/realms/%{Realm}.pem
(0)            --> /etc/raddb/certs/realms/NULL.pem
(0)         TLS-Session-Cert-File := /etc/raddb/certs/realms/NULL.pem
(0)       } # update control = noop
(0)     } # if ("%{unpack:&EAP-Message 4 byte}" == 1)  = noop
(0) eap: Peer sent packet with method EAP Identity (1)
(0) eap: Calling submodule eap_ttls to process data
(0) eap_ttls: (TLS) TTLS -Initiating new session
(0) eap_ttls: (TLS) TTLS - Loading session certificate file "/etc/raddb/certs/realms/NULL.pem"
(0) eap: Sending EAP Request (code 1) ID 72 length 6



# Relevant part for PEAP with the original code (custom certificate not loaded for PEAP)

(0) # Executing group from file /etc/raddb/sites-enabled/default
(0)   Auth-Type eap {
(0)     if ("%{unpack:&EAP-Message 4 byte}" == 1) {
(0)     EXPAND %{unpack:&EAP-Message 4 byte}
(0)        --> 1
(0)     if ("%{unpack:&EAP-Message 4 byte}" == 1)  -> TRUE
(0)     if ("%{unpack:&EAP-Message 4 byte}" == 1)  {
(0)       update control {
(0)         EXPAND /etc/raddb/certs/realms/%{Realm}.pem
(0)            --> /etc/raddb/certs/realms/NULL.pem
(0)         TLS-Session-Cert-File := /etc/raddb/certs/realms/NULL.pem
(0)       } # update control = noop
(0)     } # if ("%{unpack:&EAP-Message 4 byte}" == 1)  = noop
(0) eap: Peer sent packet with method EAP Identity (1)
(0) eap: Calling submodule eap_ttls to process data
(0) eap_ttls: (TLS) TTLS -Initiating new session
(0) eap_ttls: (TLS) TTLS - Loading session certificate file "/etc/raddb/certs/realms/NULL.pem"
(0) eap: Sending EAP Request (code 1) ID 145 length 6
...
(1) # Executing group from file /etc/raddb/sites-enabled/default
(1)   Auth-Type eap {
(1)     if ("%{unpack:&EAP-Message 4 byte}" == 1) {
(1)     EXPAND %{unpack:&EAP-Message 4 byte}
(1)        --> 3
(1)     if ("%{unpack:&EAP-Message 4 byte}" == 1)  -> FALSE
(1) eap: Removing EAP session with state 0x9046b90b90d7acef
(1) eap: Previous EAP request found for state 0x9046b90b90d7acef, released from the list
(1) eap: Peer sent packet with method EAP NAK (3)
(1) eap: Found mutually acceptable type PEAP (25)
(1) eap: Calling submodule eap_peap to process data
(1) eap_peap: (TLS) PEAP -Initiating new session
(1) eap: Sending EAP Request (code 1) ID 146 length 6



# Relevant part for PEAP with the fixed code (custom certificate is loaded for PEAP)

(0) # Executing group from file /etc/raddb/sites-enabled/default
(0)   Auth-Type eap {
(0)     if (&request:EAP-Type == Identity || &request:EAP-Type == NAK) {
(0)     if (&request:EAP-Type == Identity || &request:EAP-Type == NAK)  -> TRUE
(0)     if (&request:EAP-Type == Identity || &request:EAP-Type == NAK)  {
(0)       update control {
(0)         EXPAND /etc/raddb/certs/realms/%{Realm}.pem
(0)            --> /etc/raddb/certs/realms/NULL.pem
(0)         TLS-Session-Cert-File := /etc/raddb/certs/realms/NULL.pem
(0)       } # update control = noop
(0)     } # if (&request:EAP-Type == Identity || &request:EAP-Type == NAK)  = noop
(0) eap: Peer sent packet with method EAP Identity (1)
(0) eap: Calling submodule eap_ttls to process data
(0) eap_ttls: (TLS) TTLS -Initiating new session
(0) eap_ttls: (TLS) TTLS - Loading session certificate file "/etc/raddb/certs/realms/NULL.pem"
(0) eap: Sending EAP Request (code 1) ID 152 length 6
...
(1) # Executing group from file /etc/raddb/sites-enabled/default
(1)   Auth-Type eap {
(1)     if (&request:EAP-Type == Identity || &request:EAP-Type == NAK) {
(1)     if (&request:EAP-Type == Identity || &request:EAP-Type == NAK)  -> TRUE
(1)     if (&request:EAP-Type == Identity || &request:EAP-Type == NAK)  {
(1)       update control {
(1)         EXPAND /etc/raddb/certs/realms/%{Realm}.pem
(1)            --> /etc/raddb/certs/realms/NULL.pem
(1)         TLS-Session-Cert-File := /etc/raddb/certs/realms/NULL.pem
(1)       } # update control = noop
(1)     } # if (&request:EAP-Type == Identity || &request:EAP-Type == NAK)  = noop
(1) eap: Removing EAP session with state 0x97c79cf8975f8905
(1) eap: Previous EAP request found for state 0x97c79cf8975f8905, released from the list
(1) eap: Peer sent packet with method EAP NAK (3)
(1) eap: Found mutually acceptable type PEAP (25)
(1) eap: Calling submodule eap_peap to process data
(1) eap_peap: (TLS) PEAP -Initiating new session
(1) eap_peap: (TLS) PEAP - Loading session certificate file "/etc/raddb/certs/realms/NULL.pem"
(1) eap: Sending EAP Request (code 1) ID 153 length 6

Relevant log output from client utilities

No response

Backtrace from LLDB or GDB

Metadata

Metadata

Assignees

No one assigned

    Labels

    defectcategory: a defect or misbehaviour

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions