There’s normally hardly any point using PEAP if you’re already using EAP-TLS for network client authentication over RADIUS. The vast majority of the EAP conversation is encrypted with EAP-TLS anyway. The general consensus seems to be that it’s a waste of time adding the complexity of the PEAP layer too, just to hide the client certificate.
For this reason, examples of how to actually do it in FreeRADIUS are few and far between. In fact, they seem to be rather non-existant. The easy answer via a simple Google search is that you just probably can’t do it. However, there’s now a reason to consider this slightly unusual method, which is that FreeRADIUS now has support for Microsoft Statement of Health (SoH). This is a method where an agent, built in to Windows from XP SP3 and above, can supply a report about the anti-virus software and firewall, etc, upon connection to the network. It’s one component that can be used as part of Network Access Control in deciding whether to permit a client to connect.
Unfortunately for those that want to use TLS and certificates for network authentication, SoH fits into the PEAP layer. Which neatly brings us back to ‘how do I do PEAP/EAP-TLS?’
It turns out that with a recent FreeRADIUS this will now work, and it’s not actually that hard. As always, the key is knowing what to put where. The main configuration, as expected, goes in eap.conf. It needs to look something like this:
eap { default_eap_type = peap timer_expire = 60 ignore_unknown_eap_types = no cisco_accounting_username_bug = no tls { private_key_file = ${raddbdir}/certs/radius.key certificate_file = ${raddbdir}/certs/radius.pem # Don't add CA_file here unless you also # want to allow plain EAP-TLS. dh_file = ${raddbdir}/certs/dh random_file = /dev/urandom # must be around 50 or more bytes greater than # fragment_size in innereap below: fragment_size = 1200 check_crl = no cipher_list = "DEFAULT" } peap { default_eap_type = tls copy_request_to_tunnel = yes use_tunneled_reply = yes proxy_tunneled_request_as_eap = no virtual_server = "inner-tunnel" # SoH configuration goes here # soh = yes # soh_virtual_server = "soh-server" } } eap innereap { default_eap_type = tls timer_expire = 60 ignore_unknown_eap_types = no cisco_accounting_username_bug = no tls { check_cert_issuer = "/DC=com/DC=example/CN=Test CA" private_key_file = ${raddbdir}/certs/radius.key certificate_file = ${raddbdir}/certs/radius.pem CA_file = ${raddbdir}/certs/ca.pem dh_file = ${raddbdir}/certs/dh random_file = /dev/urandom fragment_size = 1024 check_crl = no cipher_list = "DEFAULT" # OCSP configuration goes here #ocsp { # enable = yes # override_cert_url = yes # url = "http://ocsp-responder.example.com/ocsp/" #} } }
The main server configuration needs to call ‘eap’ as usual. A very basic config might contain:
authorize { eap { ok = return } } authenticate { eap } preacct { } accounting { } session { } post-auth { } pre-proxy { } post-proxy { }
However, the inner-tunnel server that is used by PEAP needs to call the second “innereap” instantiation of the eap module. Again, a very basic config might be:
server inner-tunnel { authorize { innereap } authenticate { innereap } session { } post-auth { } pre-proxy { } post-proxy { } } # inner-tunnel server block
The key to all this seems to be the fragment_size setting. The TLS component for EAP-TLS must have a smaller fragment_size than the TLS component for PEAP. Experimentation indicated that it should probably at least be 50 bytes smaller, so using the values in eap.conf above is probably safe — your mileage may vary. This difference also seems to be the reason why you can’t just use the same eap instantiation for both the outer and inner servers, as otherwise the configuration could be identical.
(Note: Please don’t put these examples into production as they are — I can’t guarantee they are secure, they’re just examples from the way I got this to work. You should base your server on the default FreeRADIUS configuration until you really know what you are doing.)
After this is working, which hopefully it should do fairly easily, you can start to add the extras, such as SoH (see FreeRADIUS SoH.txt documentation) or client certificate checking with OCSP.
First of all – great article. I’ve been struggling for days to get this to work, and then found your blog here – lifesaving stuff as I need to replace and already existing 2k8 NPS server that’s showing it’s limitations with something a bit more capable.
Anyway, whilst this seems to work and clients connect, I’m a little bothered about the fact that I get multiple WARNING : eap session for state … did not finish, please read wiki page re certificate compatibility. Using exactly the same certificates and these work with plain EAP-TLS ok. Is this something you came across? If so, is there an easy fix?
Thanks
Andy Franks
Is this up-to-date for FreeRadius 3.0?
I’ve followed all the configurations in here by making changes to:
eap.conf
inner-eap.conf
inner-tunnel.conf
However no even using just PEAP as an outer method (no inner method) fails as well.
Any suggestions?
Yes, this is fine for FreeRADIUS 3.0. Possibly not 3.1 or 4 with Windows clients, but you shouldn’t be using them in production as they’re development branches anyway.
If PEAP on its own isn’t working, then you need to start by getting that fixed first. Try from the default config, which generally works for everything, and change one thing at a time.
If you can’t work it out then your best option is to post full debug output (right from the first banner and including a broken authentication) to the freeradius-users list, and we’ll have a look there.