EAP-TLS - How to log TLS-Client-Cert-* attributes from expired certificates
Hello freeradius user list, I have a running freeradius from the default package coming with Debian 9 stretch , which is based on version 3.0.12 . It is configured to auth only via EAP-TLS. Clients sent their certificates, no passwords and no (real) username. Accepts and Rejects work as expected. What I am not happy with is that I can not find a way to log the certificate details if a user is sending an expired certificate. For users with valid certificates I see all the values for TLS-Client-Cert-* in %{pairs:request:} in linelog . The linelog-command for successful auth is set in the post-auth{} section in sites-enabled/default . With expired client-certificates the eap module jumps direct into Post-Auth-Type REJECT {} (located within post-auth{} section) and none of the TLS-Client-Cert-* details are available (I tried with debug_all). Only Module-Failure-Message is mentioning "... expired certificate ..." and some SSL info. As all of the clients are configured to use an anonymised identity (all use the same) as the username I can not see to whom the expired certificate belongs. In debug mode it says there are TLS attributes created for an expired certificate. So there might be hope to save them for later use ... Does anyone have an idea how I can make these attributes available in linelog? This is an example what I get for an expired certificate in debug mode . Note the lines (226) eap_tls: Creating attributes from certificate OIDs I want to log the value of TLS-Client-Cert-Subject and/or TLS-Client-Cert-Common-Name. freeradius -fxx -l stdout 2>&1 | tee /tmp/freeradius_debug.log Thread 4 handling request 226, (92 handled so far) (226) Received Access-Request Id 110 from 10.1.2.3:32847 to 10.100.0.1:1812 length 554 (226) User-Name = "anonymous@example.org" (226) NAS-IP-Address = 192.168.1.12 (226) NAS-Identifier = "0418d67042af" (226) NAS-Port = 0 (226) Called-Station-Id = "04-18-D6-78-55-E1:wifi-radius" (226) Calling-Station-Id = "60-36-DD-7C-E2-DC" (226) Framed-MTU = 1400 (226) NAS-Port-Type = Wireless-802.11 (226) Connect-Info = "CONNECT 0Mbps 802.11b" (226) EAP-Message = xxxxxxxxx... (226) State = 0x3aec898e31c584882f19a28945c85c1b (226) Message-Authenticator = 0x8eeb70cc5c6a84bf36523e303d207ff6 (226) session-state: No cached attributes (226) # Executing section authorize from file /etc/freeradius/3.0/sites-enabled/default (226) authorize { (226) policy split_username_nai { (226) if (&User-Name && (&User-Name =~ /^([^@]*)(@([-[:alnum:]]+\.[-[:alnum:].]+))?$/)) { (226) if (&User-Name && (&User-Name =~ /^([^@]*)(@([-[:alnum:]]+\.[-[:alnum:].]+))?$/)) -> TRUE (226) if (&User-Name && (&User-Name =~ /^([^@]*)(@([-[:alnum:]]+\.[-[:alnum:].]+))?$/)) { (226) update request { (226) EXPAND %{1} (226) --> anonymous (226) &Stripped-User-Name := anonymous (226) EXPAND %{3} (226) --> example.org (226) &Stripped-User-Domain = example.org (226) } # update request = noop (226) [updated] = updated (226) } # if (&User-Name && (&User-Name =~ /^([^@]*)(@([-[:alnum:]]+\.[-[:alnum:].]+))?$/)) = updated (226) ... skipping else: Preceding "if" was taken (226) } # policy split_username_nai = updated (226) if (noop || !&Stripped-User-Domain) { (226) if (noop || !&Stripped-User-Domain) -> FALSE (226) if (&Stripped-User-Domain != "example.org") { (226) if (&Stripped-User-Domain != "example.org") -> FALSE (226) if ( &Stripped-User-Name !~ /otherPKI/i ) { (226) if ( &Stripped-User-Name !~ /otherPKI/i ) -> TRUE (226) if ( &Stripped-User-Name !~ /otherPKI/i ) { (226) eap: Peer sent EAP Response (code 2) ID 41 length 369 (226) eap: No EAP Start, assuming it's an on-going EAP conversation (226) [eap] = updated (226) return (226) } # if ( &Stripped-User-Name !~ /otherPKI/i ) = updated (226) } # authorize = updated (226) Found Auth-Type = eap (226) # Executing group from file /etc/freeradius/3.0/sites-enabled/default (226) authenticate { (226) eap: Expiring EAP session with state 0x3aec898e31c58488 (226) eap: Finished EAP session with state 0x3aec898e31c58488 (226) eap: Previous EAP request found for state 0x3aec898e31c58488, released from the list (226) eap: Peer sent packet with method EAP TLS (13) (226) eap: Calling submodule eap_tls to process data (226) eap_tls: Continuing EAP-TLS (226) eap_tls: Got final TLS record fragment (363 bytes) (226) eap_tls: [eaptls verify] = ok (226) eap_tls: Done initial handshake (226) eap_tls: TLS_accept: SSLv3/TLS write server done (226) eap_tls: <<< recv TLS 1.2 [length 13a3] (226) eap_tls: Creating attributes from certificate OIDs (226) eap_tls: Creating attributes from certificate OIDs (226) eap_tls: Creating attributes from certificate OIDs (226) eap_tls: TLS-Cert-Serial := "17887d08b33e3d" (226) eap_tls: TLS-Cert-Expiration := "190709235900Z" (226) eap_tls: TLS-Cert-Subject := "/C=DE/O=Example/OU=ExampleOU/CN=Example-CA-02" (226) eap_tls: TLS-Cert-Issuer := "/C=DE/O=Example/OU=Example-PKI/CN=Example-CA-01" (226) eap_tls: TLS-Cert-Common-Name := "Example-CA-02" (226) eap_tls: TLS-Cert-Subject-Alt-Name-Email := "ca@example.org" (226) eap_tls: Creating attributes from certificate OIDs (226) eap_tls: TLS-Client-Cert-Serial := "1a694699888a48" (226) eap_tls: TLS-Client-Cert-Expiration := "181115121610Z" (226) eap_tls: TLS-Client-Cert-Subject := "/C=DE/ST=ExampleST/L=ExampleL/O=Example/OU=ExampleOU/CN=Expired_Example_Cert" (226) eap_tls: TLS-Client-Cert-Issuer := "/C=DE/O=Example/OU=ExampleOU/CN=Example-CA-02" (226) eap_tls: TLS-Client-Cert-Common-Name := "Expired_Example_Cert" (226) eap_tls: TLS-Client-Cert-Subject-Alt-Name-Upn := "anonymous@example.org" (226) eap_tls: TLS-Client-Cert-Subject-Alt-Name-Email := "gryphius@example.org" (226) eap_tls: ERROR: SSL says error 10 : certificate has expired (226) eap_tls: >>> send TLS 1.2 [length 0002] (226) eap_tls: ERROR: TLS Alert write:fatal:certificate expired tls: TLS_accept: Error in error (226) eap_tls: ERROR: Failed in __FUNCTION__ (SSL_read): error:1417C086:SSL routines:tls_process_client_certificate:certificate verify failed (226) eap_tls: ERROR: System call (I/O) error (-1) (226) eap_tls: ERROR: TLS receive handshake failed during operation (226) eap_tls: ERROR: [eaptls process] = fail (226) eap: ERROR: Failed continuing EAP TLS (13) session. EAP sub-module failed (226) eap: Sending EAP Failure (code 4) ID 41 length 4 (226) eap: Failed in EAP select (226) [eap] = invalid (226) } # authenticate = invalid (226) Failed to authenticate the user (226) Using Post-Auth-Type Reject (226) # Executing group from file /etc/freeradius/3.0/sites-enabled/default (226) Post-Auth-Type REJECT { (226) if ( &Module-Failure-Message[1] =~ /expired/ ) { (226) if ( &Module-Failure-Message[1] =~ /expired/ ) -> TRUE (226) if ( &Module-Failure-Message[1] =~ /expired/ ) -> TRUE (226) if ( &Module-Failure-Message[1] =~ /expired/ ) { (226) linelog_cert_expired: EXPAND +++++ linelog_CERT-EXPIRED +++++, %{pairs:session-state:} (226) linelog_cert_expired: --> +++++ linelog_CERT-EXPIRED +++++, (226) [linelog_cert_expired] = ok (226) } # if ( &Module-Failure-Message[1] =~ /expired/ ) = ok (226) attr_filter.access_reject: EXPAND %{User-Name} (226) attr_filter.access_reject: --> anonymous@example.org (226) attr_filter.access_reject: Matched entry DEFAULT at line 11 (226) [attr_filter.access_reject] = updated (226) linelog_send_reject: EXPAND action = Send-REJECT, User-Name = "%{User-Name}", Acesspoint-IP = "%{NAS-IP-Address}", Endgeraet-MAC = "%{Calling-Station-Id}", Stripped-User-Name = "%{Stripped-User-Name}", Stripped-User-Domain = "%{Stripped-User-Domain}", EAP-Type = "%{EAP-Type}", Module-Failure-Message(s) = "%{Module-Failure-Message[*]}" (226) linelog_send_reject: --> action = Send-REJECT, User-Name = "anonymous@example.org", Acesspoint-IP = "192.168.1.12", Endgeraet-MAC = "60-36-DD-7C-E2-DC", Stripped-User-Name = "anonymous", Stripped-User-Domain = "example.org", EAP-Type = "TLS", Module-Failure-Message(s) = "eap_tls: SSL says error 10 : certificate has expired,eap_tls: TLS Alert write:fatal:certificate expired,eap_tls: Failed in __FUNCTION__ (SSL_read): error:1417C086:SSL routines:tls_process_client_certificate:certificate verify failed,eap_tls: System call (I/O) error (-1),eap_tls: TLS receive handshake failed during operation,eap_tls: [eaptls process] = fail,eap: Failed continuing EAP TLS (13) session. EAP sub-module failed" (226) [linelog_send_reject] = ok (226) } # Post-Auth-Type REJECT = updated (226) Delaying response for 1.000000 seconds Thanks, Andreas
On Fri, 2019-02-15 at 10:02 +0100, Andreas Gryphius wrote:
In debug mode it says there are TLS attributes created for an expired certificate. So there might be hope to save them for later use ... Does anyone have an idea how I can make these attributes available in linelog?
They're not added to the request list if verification failed, so it's not currently possible. https://github.com/FreeRADIUS/freeradius-server/blob/v3.0.x/src/main/tls.c#L... I'm not sure if there's any reason why they shouldn't be, though. That line would need changing to if (certs && request) { -- Matthew
Thanks Matthew for taking care of my issue! Am 15.02.19 um 11:16 schrieb Matthew Newton:
On Fri, 2019-02-15 at 10:02 +0100, Andreas Gryphius wrote:
In debug mode it says there are TLS attributes created for an expired certificate. So there might be hope to save them for later use ... Does anyone have an idea how I can make these attributes available in linelog?
They're not added to the request list if verification failed, so it's not currently possible.
https://github.com/FreeRADIUS/freeradius-server/blob/v3.0.x/src/main/tls.c#L...
I'm not sure if there's any reason why they shouldn't be, though. That line would need changing to
if (certs && request) {
I am not a programmer, but I see a return in that function quite earlier: https://github.com/FreeRADIUS/freeradius-server/blob/v3.0.x/src/main/tls.c#L... if (!my_ok) { char const *p = X509_verify_cert_error_string(err); RERROR("SSL says error %d : %s", err, p); REXDENT(); return my_ok; } But that doesn't make a difference as I want to stay with my distro's package. Any chance that I can get further with involving some other module (i.e. cache or cache_eap)? Thanks, Andreas
On Feb 15, 2019, at 6:12 AM, Andreas Gryphius <lists.freeradius.org@ulle.dyndns.org> wrote:
I am not a programmer, but I see a return in that function quite earlier: ... But that doesn't make a difference as I want to stay with my distro's package.
I don't know why. Later versions of the server have bugs fixed, minor new features, and better debugging. In many, many cases people ask "why doesn't this work?" and the answer is "you're running something that's 5 years old: upgrade". And all too often, the answer is "no". Well...
Any chance that I can get further with involving some other module (i.e. cache or cache_eap)?
Nope. When it rejects the expired cert, it deletes all of the certificate attributes that it created. Changing that involves source code changes. Alan DeKok.
Hi Alan, Am 15.02.19 um 14:35 schrieb Alan DeKok:
On Feb 15, 2019, at 6:12 AM, Andreas Gryphius <lists.freeradius.org@ulle.dyndns.org> wrote:
I am not a programmer, but I see a return in that function quite earlier: ... But that doesn't make a difference as I want to stay with my distro's package.
I don't know why.
Later versions of the server have bugs fixed, minor new features, and better debugging. In many, many cases people ask "why doesn't this work?" and the answer is "you're running something that's 5 years old: upgrade".
And all too often, the answer is "no".
Well...
I did not want to complain. If the issue was severe enough for me, I would go the way with compiling by myself.
Any chance that I can get further with involving some other module (i.e. cache or cache_eap)?
Nope.
When it rejects the expired cert, it deletes all of the certificate attributes that it created. Changing that involves source code changes.
Okay. At least I know now that there is no work around. So thank you for pointing that out. If needed, I can catch the certificate data while in debug mode. And as Matthew already pointed to the right file in source code, anyone coming here (by search engines) can build his own fix. By the way, it looks like my issue would still be the same with freeradius current state in github: https://github.com/FreeRADIUS/freeradius-server/blob/master/src/lib/tls/vali... Same return command like in 3.0.x-code for certificate errors. Unfortunately without adding the certificate attributes into a list (request) before ... Andreas
participants (3)
-
Alan DeKok -
Andreas Gryphius -
Matthew Newton