Rejecting EAP-TLS based on cert Subject field
For years, we've been doing simple EAP-TLS with various versions of FreeRADIUS. Now, a new requirement has come down to me such that radius will have to reject certain valid client certs based on a string in the Subject field of the client cert. I've met this need (using 2.1.11 from git) with a simple bit of unlang in post-auth{}: if ( "%{TLS-Client-Cert-Subject}" =~ /OU=Evil/ ) { reject } It works, but there are two non-ideal things about the way it works: 1) Windows XP doesn't seem to notice the rejection and keeps retrying for a minute or two, ultimately failing to show any failure/error message to the user. 2) The rejection is not logged in radiusd.log; rather, three "Auth: Login OK" lines are logged (the repetition is due to XP's retries) Is there any way I can address these two issues? I did try putting the above unlang into eap.conf's tls{} section (where check_cert_issuer and check_cert_cn would be), in hopes that the rejection would occur during the auth rather than after it, but the code doesn't seem to have any effect there. Thanks in advance for any clues... -Matt
hi, you are authenticating...and then rejecting in the post-auth stage. you really need to break the process in the authentication stage. alan
On 1/27/2011 1:14 PM, Alan Buxey wrote:
you are authenticating...and then rejecting in the post-auth stage. you really need to break the process in the authentication stage.
Thanks. That's actually my goal. But unlang isn't allowed in authenticate{}, and my attempts to sneak it into the authentication phase via the tls{} section in eap.conf didn't seem to work. Any other ways to do it? I'd thought of using rlm_perl, but couldn't see that the cert fields are passed to the module. Thanks, -Matt
On 1/27/2011 1:24 PM, Matt Garretson wrote:
Thanks. That's actually my goal. But unlang isn't allowed in authenticate{}, and my attempts to sneak it into the authentication phase via the tls{} section in eap.conf didn't seem to work. Any other ways to do it?
Replying to myself here.... I got a bit closer to my goal by putting this in the verify{} subsection of tls{} : tmpdir = /tmp/radiusd client = "/usr/local/bin/checkcert %{TLS-Client-Cert-Filename}" Where /usr/local/bin/checkcert contains: #!/bin/sh if /usr/bin/openssl x509 -in "$1" -noout -text | \ /bin/grep -q " Subject:.* OU=Evil," ; then RC=1 else RC=0 fi exit $RC The XP client still tries three times (duh), but at least radius.log reflects a failure: Error: TLS_accept: error in SSLv3 read client certificate B Error: rlm_eap: SSL error error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned Error: SSL: SSL_read failed in a system call (-1), TLS session fails. Auth: Login incorrect (TLS Alert write:fatal:certificate unknown): [snip] Still, it would be nice if I could use unlang (or something) to match against %{TLS-Client-Cert-Subject} during the authenticate stage somehow. Is there a way that I'm missing? Thanks, -Matt
On 1/27/2011 3:41 PM, Matt Garretson wrote:
The XP client still tries three times (duh), but at least radius.log reflects a failure:
Error: TLS_accept: error in SSLv3 read client certificate B Error: rlm_eap: SSL error error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned Error: SSL: SSL_read failed in a system call (-1), TLS session fails. Auth: Login incorrect (TLS Alert write:fatal:certificate unknown): [snip]
*sigh* I left out the first (and most useful) logging line in the above: Auth: rlm_eap_tls: Certificate CN (eviluser) fails external verification! So, again, it's better than what I'd had before, but not as elegant as I was hoping.
Matt Garretson wrote:
Thanks. That's actually my goal. But unlang isn't allowed in authenticate{},
Yes, it is. You just need to put it into a subsection. See the comments around "eap" in the authenticate section for 2.1.10.
and my attempts to sneak it into the authentication phase via the tls{} section in eap.conf didn't seem to work.
Hmm... the "tls" section is a configuration section, and has nothing to do with the modules listed in the "authenticate" section. Alan DeKok.
On 01/27/2011 06:04 PM, Matt Garretson wrote:
For years, we've been doing simple EAP-TLS with various versions of FreeRADIUS. Now, a new requirement has come down to me such that radius will have to reject certain valid client certs based on a string in the Subject field of the client cert.
I've met this need (using 2.1.11 from git) with a simple bit of unlang in post-auth{}:
if ( "%{TLS-Client-Cert-Subject}" =~ /OU=Evil/ ) { reject }
Just put this in the "authorize" section? If it's early in the EAP conversation, TLS-Client-* won't be set so won't match, meaning this will succeed as soon as yo uget that far.
It works, but there are two non-ideal things about the way it works:
1) Windows XP doesn't seem to notice the rejection and keeps retrying for a minute or two, ultimately failing to show any failure/error message to the user.
2) The rejection is not logged in radiusd.log; rather, three "Auth: Login OK" lines are logged (the repetition is due to XP's retries)
Is there any way I can address these two issues? I did try putting the above unlang into eap.conf's tls{} section (where check_cert_issuer and check_cert_cn would be), in hopes that the rejection would occur during the auth rather than after it, but the code doesn't seem to have any effect there.
Correct. Unlang is only processed in authorize-like steps, not arbitrary bits of the config.
On 1/27/2011 3:03 PM, Phil Mayers wrote:
I've met this need (using 2.1.11 from git) with a simple bit of unlang in post-auth{}: if ( "%{TLS-Client-Cert-Subject}" =~ /OU=Evil/ ) { reject }
Just put this in the "authorize" section? If it's early in the EAP conversation, TLS-Client-* won't be set so won't match, meaning this will succeed as soon as yo uget that far.
I'm not sure I follow you here. Are you saying that there is a place in the authorize section where TLS-Client-* _would_ be accessible to unlang? I've tried it in a few places (before eap, after eap, at the top of the section, at the bottom of the section) and it seemed to have no effect. But it's entirely possible that I missed something during these tests.
Correct. Unlang is only processed in authorize-like steps, not arbitrary bits of the config.
I can understand that. But given that the eap module has access to some client cert fields during authentication (e.g. check_cert_issuer and check_cert_cn), it would be nice to be able to access these and other client cert fields with unlang (or something similar) at that stage. But, admittedly, I'm way over my head here :-) so I'll make do with one of the methods described earlier in this thread. Thanks, -Matt
On 27/01/11 21:30, Matt Garretson wrote:
On 1/27/2011 3:03 PM, Phil Mayers wrote:
I've met this need (using 2.1.11 from git) with a simple bit of unlang in post-auth{}: if ( "%{TLS-Client-Cert-Subject}" =~ /OU=Evil/ ) { reject }
Just put this in the "authorize" section? If it's early in the EAP conversation, TLS-Client-* won't be set so won't match, meaning this will succeed as soon as yo uget that far.
I'm not sure I follow you here. Are you saying that there is a place in the authorize section where TLS-Client-* _would_ be accessible to unlang? I've tried it in a few places (before eap, after eap, at the top of the section, at the bottom of the section) and it seemed to have no effect. But it's entirely possible that I missed something during these tests.
You're right, I'm wrong. EAP of course runs all its guts in the "authenticate" section, so nothing is available during the "authorize" section. Sorry for the noise.
Matt Garretson wrote:
It works, but there are two non-ideal things about the way it works:
1) Windows XP doesn't seem to notice the rejection and keeps retrying for a minute or two, ultimately failing to show any failure/error message to the user.
You're sending a *radius* reject. It doesn't include an EAP-Message with an *EAP* reject. So you need to create a fake one: update reply { EAP-Message := 0x04010004 } That can work sometimes...
2) The rejection is not logged in radiusd.log; rather, three "Auth: Login OK" lines are logged (the repetition is due to XP's retries)
Put the "unlang" in the "authenticate" section, after "eap": Auth-Type eap { eap if (...) { ... } }
Is there any way I can address these two issues? I did try putting the above unlang into eap.conf's tls{} section (where check_cert_issuer and check_cert_cn would be), in hopes that the rejection would occur during the auth rather than after it, but the code doesn't seem to have any effect there.
Unlang doesn't go in module configuration sections. Alan DeKok.
On 1/28/2011 3:48 AM, Alan DeKok wrote:
Put the "unlang" in the "authenticate" section, after "eap": Auth-Type eap { eap if (...) { ... } }
Thank you!! That did the trick. The entirety of my authenticate section is now: authenticate { Auth-Type Kerberos { krb5 } Auth-Type eap { eap if ( "%{TLS-Client-Cert-Subject}" =~ /\/OU=Evil\// ) { reject } } } And it works perfectly. Thank you! As for Windows XP dealing with the rejection....
You're sending a *radius* reject. It doesn't include an EAP-Message with an *EAP* reject. So you need to create a fake one: update reply { EAP-Message := 0x } That can work sometimes...
Ah, thanks for the tip. I added this in the "Post-Auth-Type REJECT" section: if ( "%{control:Auth-Type}" == "EAP" ) { update reply { EAP-Message := 0x04010004 } } The code seems to work as expected, but Windows XP still doesn't seem to handle it sensibly. But I can live with that. Thank you, Alan! -Matt
participants (4)
-
Alan Buxey -
Alan DeKok -
Matt Garretson -
Phil Mayers