eap-ttls/mschapv2 versus eap-peap/mschapv2 behaviour
Hello, We're in the middle of migrating all of our radius server to FR3. This is the opportunity to discuss a the difference of behaviour between EAP-TTLS/MSCHAPv2 and EPA-PEAP/MSCHAPv2 which is bothersome. With EAP-TTLS/MSCHAPv2 we have the following flow 1. NAS and Freeradius establish TLS tunnel while in authorize{} 2. Once tunnel is established, the ldap/sql/ntlm_auth modules are executed in authorize{} 3. Then the request pass to authenticate{} and eap/mschap does theire job 4. The request is then passed to post-auth and the final response is sent to the outer tunnel With EAP-PEAP/MSCHAPv2 the flow is somewhat different 1. NAS and Freeradius establish TLS tunnel while in authorize{} 2. Once tunnel is established, the ldap/sql/ntlm_auth modules are executed in authorize{} 3. Then the request pass to authenticate{} and eap does another round of challenge/response 4. While in authenticate, mschap does the authentication 5. The request is then passed to post-auth This mean that with EAP-PEAP/MSCHAPv2, if the ldap/sql/xxx module in authorize{} add attributes to the reply, they will be sent during the last challenge/response in authenticate{}, and will not be present in post-auth or the final access-accept. On our side, we are doing the policying in the inner-tunnel post-auth section, based on values directly mapped from ldap attributes to our private dictionary through the ldap module called in authz{} With EAP-TTLS we don't need to do anything special to make this work, but for PEAP actually we need to use the rlm_cache to cache and restore the attributes in post-auth. It would be really nice if eap would cache automatically all attributes present in the reply list if it has to do another round of challenge/response and restore them once the final access-accept (or reject) is reached. Now this is a behaviour I always encountered in our configs (based on the default shipped config). Still it's possible that it is due to what've done. For this purpose you'll find the inner-tunnel config below [1]. Olivier [1] server secure-hefr-inner-tunnel{ authorize { mschap ntdomain update control { Proxy-To-Realm := LOCAL } if(User-Name =~ /SOFR.(.*)$/) { update request { Stripped-User-Name := "%{1}" } } eap { ok = return } ldap pap } authenticate { Auth-Type MS-CHAP { mschap } Auth-Type CHAP { chap } Auth-Type PAP{ pap } eap } post-auth { Post-Auth-Type REJECT { -sql attr_filter.access_reject } auth_log # that's where we need the attributes added # by the ldap module in authz{} wireless-policy } } -- Olivier Beytrison Network & Security Engineer, HES-SO Fribourg Mail: olivier@heliosnet.org
On 07/18/2013 07:25 AM, Olivier Beytrison wrote:
Hello,
We're in the middle of migrating all of our radius server to FR3.
This is the opportunity to discuss a the difference of behaviour between EAP-TTLS/MSCHAPv2 and EPA-PEAP/MSCHAPv2 which is bothersome.
With EAP-TTLS/MSCHAPv2 we have the following flow
With EAP-PEAP/MSCHAPv2 the flow is somewhat different
FWIW I don't think either of those are complete or accurate. For starters, TTLS/MSCHAPv2 and TTLS/EAP-MSCHAPv2 are different, and PEAP/MSCHAP is *really* PEAP/EAP-MSCHAPv2. Comparing TTLS/MSCHAP and PEAP/EAP-MSCHAPv2 is comparing two different things, and of course they may behave differently.
This mean that with EAP-PEAP/MSCHAPv2, if the ldap/sql/xxx module in authorize{} add attributes to the reply, they will be sent during the last challenge/response in authenticate{}, and will not be present in post-auth or the final access-accept.
You're not being very precise here. authorize in the inner or outer tunnel?
On our side, we are doing the policying in the inner-tunnel post-auth section, based on values directly mapped from ldap attributes to our private dictionary through the ldap module called in authz{}
With EAP-TTLS we don't need to do anything special to make this work, but for PEAP actually we need to use the rlm_cache to cache and restore the attributes in post-auth.
Why don't you just set them in post-auth, and skip setting them in authorize completely? You can do this, remember: post-auth { ldap.authorize sql.authorize ... }
It would be really nice if eap would cache automatically all attributes present in the reply list if it has to do another round of challenge/response and restore them once the final access-accept (or reject) is reached.
I'm not sure about that. You definitely have to take care with reply attributes, but if you always set them in post-auth, you should always be safe. Setting them in authorize is only safe if you set them on *every pass* through authorize. You're not doing this, because you have: eap { ok = return } ldap sql In 3.0, the "ok = return" will match on EAP-identity packets for the inner tunnel but *also* EAP-MSCHAPv2 success/failure packets. So, the final pass through the tunnel will be skipped. This should be logged in the debug with a quite specific/verbose message, for exactly this reason: https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_... Maybe this is the issue you're facing?
Now this is a behaviour I always encountered in our configs (based on the default shipped config). Still it's possible that it is due to what've done. For this purpose you'll find the inner-tunnel config below [1].
# that's where we need the attributes added # by the ldap module in authz{} wireless-policy }
What does "wireless-policy" do, and where does it get its data from?
On Thu, Jul 18, 2013 at 09:53:02AM +0100, Phil Mayers wrote:
Setting them in authorize is only safe if you set them on *every pass* through authorize. You're not doing this, because you have:
eap { ok = return } ldap sql
In 3.0, the "ok = return" will match on EAP-identity packets for the inner tunnel but *also* EAP-MSCHAPv2 success/failure packets. So, the final pass through the tunnel will be skipped.
Is there any benefit in returning ok here for MSCHAP success/failure? I guess it saves one extra duplicate call to ldap/sql/etc. https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_... It seems that this is likely a time when it would be better to *not* short-circuit, i.e. the last time through authorize before the accept/reject? Matthew -- Matthew Newton, Ph.D. <mcn4@le.ac.uk> Systems Specialist, Infrastructure Services, I.T. Services, University of Leicester, Leicester LE1 7RH, United Kingdom For IT help contact helpdesk extn. 2253, <ithelp@le.ac.uk>
On 18/07/13 10:50, Matthew Newton wrote:
On Thu, Jul 18, 2013 at 09:53:02AM +0100, Phil Mayers wrote:
Setting them in authorize is only safe if you set them on *every pass* through authorize. You're not doing this, because you have:
eap { ok = return } ldap sql
In 3.0, the "ok = return" will match on EAP-identity packets for the inner tunnel but *also* EAP-MSCHAPv2 success/failure packets. So, the final pass through the tunnel will be skipped.
Is there any benefit in returning ok here for MSCHAP success/failure? I guess it saves one extra duplicate call to ldap/sql/etc.
Exactly that.
It seems that this is likely a time when it would be better to *not* short-circuit, i.e. the last time through authorize before the accept/reject?
Maybe, maybe not. This got discussed on (I think) the JANET-ROAMING list ages ago - people wanted it, so I wrote the patch. I personally want to short-circuit there - we currently do it with a horrible regexp. Sadly there aren't an infinity of return codes we can (ab)use, so unless we set an attribute, removing this code will get us back to the situation where using a horrible regexp to parse hex is the "solution".
On 18.07.2013 10:53, Phil Mayers wrote:
On 07/18/2013 07:25 AM, Olivier Beytrison wrote:
Hello,
We're in the middle of migrating all of our radius server to FR3.
This is the opportunity to discuss a the difference of behaviour between EAP-TTLS/MSCHAPv2 and EPA-PEAP/MSCHAPv2 which is bothersome.
With EAP-TTLS/MSCHAPv2 we have the following flow
With EAP-PEAP/MSCHAPv2 the flow is somewhat different
FWIW I don't think either of those are complete or accurate.
For starters, TTLS/MSCHAPv2 and TTLS/EAP-MSCHAPv2 are different, and PEAP/MSCHAP is *really* PEAP/EAP-MSCHAPv2.
Comparing TTLS/MSCHAP and PEAP/EAP-MSCHAPv2 is comparing two different things, and of course they may behave differently.
I agree after writing the mail I went deeper in the analysis and the flows are quite different. But the difference of behaviour is still there.
This mean that with EAP-PEAP/MSCHAPv2, if the ldap/sql/xxx module in authorize{} add attributes to the reply, they will be sent during the last challenge/response in authenticate{}, and will not be present in post-auth or the final access-accept.
You're not being very precise here. authorize in the inner or outer tunnel?
I'm only talking about the inner tunnel here (sorry for not specifying)
On our side, we are doing the policying in the inner-tunnel post-auth section, based on values directly mapped from ldap attributes to our private dictionary through the ldap module called in authz{}
With EAP-TTLS we don't need to do anything special to make this work, but for PEAP actually we need to use the rlm_cache to cache and restore the attributes in post-auth.
Why don't you just set them in post-auth, and skip setting them in authorize completely?
You can do this, remember:
post-auth { ldap.authorize sql.authorize ... }
I know, but I can't and don't want. ldap retrieve the clear-text password from eDirectory, so this have to be done before authenticate {}. And I take this opportunity to do a one ldap call for all needs.
It would be really nice if eap would cache automatically all attributes present in the reply list if it has to do another round of challenge/response and restore them once the final access-accept (or reject) is reached.
I'm not sure about that.
You definitely have to take care with reply attributes, but if you always set them in post-auth, you should always be safe.
Well actually the attributes from ldap are all added to the reply list as we want to see them on wire and they need to be copied to the outer tunnel. When going to production most of them will move the the control list, but this issue will remain
Setting them in authorize is only safe if you set them on *every pass* through authorize. You're not doing this, because you have:
eap { ok = return } ldap sql
In 3.0, the "ok = return" will match on EAP-identity packets for the inner tunnel but *also* EAP-MSCHAPv2 success/failure packets. So, the final pass through the tunnel will be skipped.
This should be logged in the debug with a quite specific/verbose message, for exactly this reason:
https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_...
Maybe this is the issue you're facing?
I'm well aware of the short-circuit code in eap, and this is a nice feature. It's meant to save unneeded module calls, but in this situation it would indeed require a second ldap.authorize call.
Now this is a behaviour I always encountered in our configs (based on the default shipped config). Still it's possible that it is due to what've done. For this purpose you'll find the inner-tunnel config below [1].
# that's where we need the attributes added # by the ldap module in authz{} wireless-policy }
What does "wireless-policy" do, and where does it get its data from?
It sets the Airspace-Interface-Name attribute based on an attribute populated from the ldap module. See [1] The main difference between the two types is that with TTLS, once the tunnel is established, the request is decoded. So we have in the inner-tunnel : authorize { eap -> noop ldap -> ok + attributes added } authenticate { mschap -> ok } post-auth { wireless-policy -> ok (it finds the attributes) } Request sent to the outer virtual server With PEAP it's more like that once the initial tls tunnel is established : authorize { eap -> updated ldap -> ok + attributes added } authenticate { eap -> mschap [ok] -> handled } Challenge sent to the NAS Access request comes back authorize { eap -> mschapv2 ok -> short circuit } authenticate { eap ->ok } post-auth { wireless-policy -> doesn't find the attributes } Request sent to the outer tunnel Now I like the short-circuit concept as it save quite some uneeded processing. But I'd like to have a mechanism that remove and stores any attributes present in the reply (within the inner-tunnel) until the mschapv2 succeeded. If you want I have the debug and configuration ready to be posted on a gist. But I think this is a situation that everyone has already faced. So I'm also interested in how people actually circumvented this behaviour. Olivier
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
-- Olivier Beytrison Network & Security Engineer, HES-SO Fribourg Mail: olivier@heliosnet.org
On 18/07/13 10:56, Olivier Beytrison wrote:
Now I like the short-circuit concept as it save quite some uneeded processing. But I'd like to have a mechanism that remove and stores any attributes present in the reply (within the inner-tunnel) until the mschapv2 succeeded.
Ok. What, in detail, are you proposing? For clarity - I think it would be a mistake for the server core to save all attributes from Access-Challenge and copy them to the Access-Accept; it would *have* to be smarter/more conditional than that, and I would want a way to disable it.
On 18.07.2013 12:47, Phil Mayers wrote:
On 18/07/13 10:56, Olivier Beytrison wrote:
Now I like the short-circuit concept as it save quite some uneeded processing. But I'd like to have a mechanism that remove and stores any attributes present in the reply (within the inner-tunnel) until the mschapv2 succeeded.
Ok. What, in detail, are you proposing?
Well, that the use_tunneled_reply work as expected for EAP-PEAP/PEAPv0-MSCHAPv2 ;)
For clarity - I think it would be a mistake for the server core to save all attributes from Access-Challenge and copy them to the Access-Accept; it would *have* to be smarter/more conditional than that, and I would want a way to disable it.
Sure we don't want that. But we could imagine a form of integration of rlm_cache within eap. One of the benefit would be that we could save attribute present in other lists (like control in my case). That way we could work on those attributes in post-auth. Actually I need to put them in reply (in order for them to be saved), and in post-auth I need to remove them (or through attr_filters). Olivier -- Olivier Beytrison Network & Security Engineer, HES-SO Fribourg Mail: olivier@heliosnet.org
On 18/07/13 12:02, Olivier Beytrison wrote:
Sure we don't want that. But we could imagine a form of integration of rlm_cache within eap. One of the benefit would be that we could save attribute present in other lists (like control in my case). That way we could work on those attributes in post-auth.
Actually I need to put them in reply (in order for them to be saved), and in post-auth I need to remove them (or through attr_filters).
So just write a suitable cache config and wrap it in a policy, then submit a patch? I could probably do it, but I don't have the time right now. At minimum the effect of "ok = return" should probably be documented in comments in the default configs; at least it won't be as surprising then.
On 18.07.2013 13:15, Phil Mayers wrote:
On 18/07/13 12:02, Olivier Beytrison wrote:
Sure we don't want that. But we could imagine a form of integration of rlm_cache within eap. One of the benefit would be that we could save attribute present in other lists (like control in my case). That way we could work on those attributes in post-auth.
Actually I need to put them in reply (in order for them to be saved), and in post-auth I need to remove them (or through attr_filters).
So just write a suitable cache config and wrap it in a policy, then submit a patch?
That's already done on the IdP currently in production (also running 3.0 but from february/march). It works very well (using 3 different cache modules for different needs/attributes). Here this is, IMHO, a feature that is not working as expected. I narrowed it down to why this happen now with EAP-PEAP/PEAP-MSCHAPv2 ... in authorize, when eap (eap_peap) return "handled", the ldap module is executed, and adds attributes to the reply. It the goes to authenticate and EAP is called again, but only eap and peap_mschapv2 are executed, not eap_peap. so the fix would be to save the attributes in rlm_peap_mschapv2 Olivier -- Olivier Beytrison Network & Security Engineer, HES-SO Fribourg Mail: olivier@heliosnet.org
Olivier Beytrison wrote:
in authorize, when eap (eap_peap) return "handled", the ldap module is executed, and adds attributes to the reply. It the goes to authenticate and EAP is called again, but only eap and peap_mschapv2 are executed, not eap_peap.
I'm not sure what that means. There's EAP-MSCHAPv2, but not peap-mschapv2. And EAP-MSCHAPv2 runs inside of PEAP. So the code should always go EAP -> PEAP -> EAP-MSCHAPv2. Alan DeKok.
On 18.07.2013 14:37, Alan DeKok wrote:
Olivier Beytrison wrote:
in authorize, when eap (eap_peap) return "handled", the ldap module is executed, and adds attributes to the reply. It the goes to authenticate and EAP is called again, but only eap and peap_mschapv2 are executed, not eap_peap.
I'm not sure what that means. There's EAP-MSCHAPv2, but not peap-mschapv2.
Yeah sorry, made a typo, it's eap_mschapv2
And EAP-MSCHAPv2 runs inside of PEAP. So the code should always go EAP -> PEAP -> EAP-MSCHAPv2
Ran the server in gdb, and couldn't verify this. That's what I had : #0 mschapv2_authenticate (arg=0x8dc7e0, handler=0x924a50) at src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c:371 #1 0x00007fffeff8a35b in eap_module_call (handler=0x924a50, module=<optimized out>) at src/modules/rlm_eap/eap.c:217 #2 0x00007fffeff8a758 in eap_method_select (inst=0x8b8e10, handler=<optimized out>) at src/modules/rlm_eap/eap.c:473 #3 0x00007fffeff89de3 in mod_authenticate (request=0x917220, instance=0x8b8e10) at src/modules/rlm_eap/rlm_eap.c:302 #4 mod_authenticate (instance=0x8b8e10, request=0x917220) at src/modules/rlm_eap/rlm_eap.c:262 #5 0x000000000041e410 in call_modsingle (request=0x917220, component=0, sp=<optimized out>) at src/main/modcall.c:311 #6 modcall (component=0, c=0x8e2fe0, request=<optimized out>) at src/main/modcall.c:796 no peap in the stack. eap_mschapv2 is directly run from EAP The main point I'm discussing here is that, at least on OUR side eap-ttls/mschapv2 and eap-peap/peap-mschapv2 are the main method used by our clients. And we get different behaviour on the server (okay they are two different eap types with different flows). With ttls we can set attributes in authz and use them in post-auth, with peap we can't. Now if this will remain because of the design, the protocols ect, it should be documented, and I'll setup the cache module again. But I think, for consistency, that attributes added in authz should be made available in post-auth. The base code is here (accept_vps being saved), it just needs to be used at the right time. Full debug of a eap-peap/mschapv2 : https://gist.github.com/olivierbeytrison/912b9aa8e0ebc3cc0385 full debug of an eap-ttls/mschapv2 : https://gist.github.com/olivierbeytrison/3ca76806d015ad108104 Olivier -- Olivier Beytrison Network & Security Engineer, HES-SO Fribourg Mail: olivier@heliosnet.org
On 18/07/13 14:59, Olivier Beytrison wrote:
The main point I'm discussing here is that, at least on OUR side eap-ttls/mschapv2 and eap-peap/peap-mschapv2 are the main method used by our clients.
And we get different behaviour on the server (okay they are two different eap types with different flows).
TTLS and PEAP are a red herring. The issue is that MSCHAP is different to EAP-MSCHAPv2, and is processed in a single pass through the inner-tunnel virtual server - so of course, attributes from authorize are present in post-auth. EAP-MSCHAPv2 is different, and is processed in 3 passes through the inner-tunnel (ident/challenge, response/success, success/ack). You are proposing to save attributes from pass 2, and restore them in pass 3, so that you can continue to take advantage of the short-circuit in pass 1/3. If you were to use EAP-TTLS/EAP-MSCHAPv2, you would see the same behaviour as with EAP-PEAP/EAP-MSCHAPv2. If you *must* fix this anywhere, the right place to fix it is in the EAP-MSCHAPv2 code. Save the attributes somewhere here: https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_... ...then restore them somewhere here; https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_... However, I think you're underestimating how hard this is; to make the EAP-MSCHAPv2 case look like plain MSCHAP, you need to save request, control and reply attributes, and somehow merge them back in. I think this is a complex enough decision that it should be kept out of the server core, and implemented with a cache/policy wrapper so people can modify it.
Full debug of a eap-peap/mschapv2 : https://gist.github.com/olivierbeytrison/912b9aa8e0ebc3cc0385
Yes, note that request #6 (line 1610) #7 (line 1798) and #8 (line 2024) are *EAP*, and short-circuits happen in #6 and #8.
full debug of an eap-ttls/mschapv2 : https://gist.github.com/olivierbeytrison/3ca76806d015ad108104
...whereas in this, request #7 (line 983) is plain MSCHAP (no EAP) and is the *only* request which goes to inner-tunnel.
Olivier Beytrison wrote:
And EAP-MSCHAPv2 runs inside of PEAP. So the code should always go EAP -> PEAP -> EAP-MSCHAPv2
Ran the server in gdb, and couldn't verify this. That's what I had :
The stack trace should be much larger than that. PEAP creates a "fake" request, and calls rad_authenticate() again, for the inner-tunnel data.
The main point I'm discussing here is that, at least on OUR side eap-ttls/mschapv2 and eap-peap/peap-mschapv2 are the main method used by our clients.
Try eapol_test, and eap-ttls/EAP-MSCHAPv2. You'll see the same thing as with PEAP.
But I think, for consistency, that attributes added in authz should be made available in post-auth. The base code is here (accept_vps being saved), it just needs to be used at the right time.
I think this is the same as v2, right? Or am I missing something... If it's the same as v2, we'll fix it in the next release. Alan DeKok.
On 18.07.2013, at 17:42, Alan DeKok <aland@deployingradius.com> wrote:
Olivier Beytrison wrote:
And EAP-MSCHAPv2 runs inside of PEAP. So the code should always go EAP -> PEAP -> EAP-MSCHAPv2
Ran the server in gdb, and couldn't verify this. That's what I had :
The stack trace should be much larger than that. PEAP creates a "fake" request, and calls rad_authenticate() again, for the inner-tunnel data.
Weird. That's what I get for each call to mschapv2 functions.
The main point I'm discussing here is that, at least on OUR side eap-ttls/mschapv2 and eap-peap/peap-mschapv2 are the main method used by our clients.
Try eapol_test, and eap-ttls/EAP-MSCHAPv2. You'll see the same thing as with PEAP. Yeah it will be the same.
But I think, for consistency, that attributes added in authz should be made available in post-auth. The base code is here (accept_vps being saved), it just needs to be used at the right time.
I think this is the same as v2, right? Or am I missing something...
If it's the same as v2, we'll fix it in the next release.
Well I can't tell. In my last servers running v2 I didn't implement the short-circuit logic, so the ldap module is called on every packets (those were my first freeradius server and the config is horrible) Well I implemented the cache module as I had before, but maybe this could be an enhancement for a future release (either in then server core or through a policy using rlm_cache) Olivier
On 18/07/13 12:55, Olivier Beytrison wrote:
Here this is, IMHO, a feature that is not working as expected.
*Which* feature?
I narrowed it down to why this happen now with EAP-PEAP/PEAP-MSCHAPv2 ...
in authorize, when eap (eap_peap) return "handled", the ldap module is executed, and adds attributes to the reply. It the goes to authenticate and EAP is called again, but only eap and peap_mschapv2 are executed, not eap_peap.
I'm sorry, I don't understand any of this.
so the fix would be to save the attributes in rlm_peap_mschapv2
Disagree, strongly.
Olivier Beytrison wrote:
This is the opportunity to discuss a the difference of behaviour between EAP-TTLS/MSCHAPv2 and EPA-PEAP/MSCHAPv2 which is bothersome.
As Phil said, it's really EAP-PEAP/EAP-MSCHAPv2. That's the source of the difference.
This mean that with EAP-PEAP/MSCHAPv2, if the ldap/sql/xxx module in authorize{} add attributes to the reply, they will be sent during the last challenge/response in authenticate{}, and will not be present in post-auth or the final access-accept.
That's what "use_tunneled_reply" is for. The reply gets cached, and sent in the final Access-Accept. This is the same behavior as 2.x. See "accept_vps" in peap.c. Maybe you don't have "use_tunneled_reply" set? Alan DeKok.
On 18.07.2013 12:15, Alan DeKok wrote:
Olivier Beytrison wrote:
This is the opportunity to discuss a the difference of behaviour between EAP-TTLS/MSCHAPv2 and EPA-PEAP/MSCHAPv2 which is bothersome.
As Phil said, it's really EAP-PEAP/EAP-MSCHAPv2. That's the source of the difference.
This mean that with EAP-PEAP/MSCHAPv2, if the ldap/sql/xxx module in authorize{} add attributes to the reply, they will be sent during the last challenge/response in authenticate{}, and will not be present in post-auth or the final access-accept.
That's what "use_tunneled_reply" is for. The reply gets cached, and sent in the final Access-Accept. This is the same behavior as 2.x.
See "accept_vps" in peap.c. Maybe you don't have "use_tunneled_reply" set?
both copy_request_to_tunnel and use_tunneled_reply are set to yes. As discussed, the code to save the VP is there. What happen on my side is that it's called on the 8th packet, whereas the ldap module has been called on the 7th packet. So there's nothing to save at this time. imho there is something to fix here. -- Olivier Beytrison Network & Security Engineer, HES-SO Fribourg Mail: olivier@heliosnet.org
participants (4)
-
Alan DeKok -
Matthew Newton -
Olivier Beytrison -
Phil Mayers