EAP-TEAP not doing 2nd inner Method

Alan DeKok aland at deployingradius.com
Wed Dec 4 11:38:49 UTC 2024


On Dec 4, 2024, at 4:11 AM, Martin B. via Freeradius-Users <freeradius-users at lists.freeradius.org> wrote:
> 
> I have spent the last few days trying to get EAP-TEAP to work, but so far
> with only partial success.

  That is unfortunately the reality of TEAP.  It is horrifically complex, for reasons I don't really understand.

  I say this as the author of the updated RFC (soon to be published), which fixes and clarifies a lot of issues around TEAP.
  
> The goal of this configuration was to verify
> both the user certificate and the machine certificate and only allow the
> device access to the network if both certificates could be successfully
> verified. At a later stage, I would like to be able to distinguish whether
> only the machine certificate or both certificates were successfully
> verified, and accordingly grant the device different access to the network.

  That is what TEAP is supposed to do.  The reality is somewhat more complex.

> For my tests, I created a CA which then issued the required client and
> server certificates. On a Windows client, I installed a client certificate
> for both the user and the machine, as well as the CA. On the RADIUS server,
> I installed a server certificate and the CA certificate.

  That's good.

> When I configure EAP-TEAP on the Windows client with only one inner EAP
> method (EAP-TLS), the FreeRADIUS server sends an Access-Accept back (as
> expected). However, as soon as I add a second inner EAP method in the
> EAP-TEAP configuration on the laptop (regardless of whether it is EAP-TLS
> or MSCHAPv2), an Access-Reject is always returned, without the second inner
> EAP method even being attempted. To my untrained eye, it looks like the
> client is sending an error back to the server, but unfortunately, there is
> no information about what the reason might be.

  Welcome to TEAP and Windows.  Windows says "Stuff went wrong".  OK... can you _tell_ me what went wrong?

  Windows then runs away and hides in a corner.  <sigh>

> I have tested this with Windows 11 and Windows 10 and tried both FreeRADIUS
> 3.2.4 and 3.2.6. All with the same result.
> 
> Is my FreeRADIUS configuration faulty, or is the behavior of the Windows
> client the problem here?

  A bit of both.

> ...
> (11) Virtual server sending reply
> (11)   MS-MPPE-Recv-Key =
> 0x68b33fa03c2a947717ab842050d1e6eb12eded7e0feb2dd0141e02b9ba42de62
> (11)   MS-MPPE-Send-Key =
> 0x2912104beaf44768c82898fee9792a14d76ecd2da4f8a9e8673462d4244bce4a
> (11)   EAP-MSK =
> 0x68b33fa03c2a947717ab842050d1e6eb12eded7e0feb2dd0141e02b9ba42de622912104beaf44768c82898fee9792a14d76ecd2da4f8a9e8673462d4244bce4a
> (11)   EAP-EMSK =
> 0x539ddd8a80123822102125690512d370f86ef93b1e4b8a258c02b92be19c3a04fd3dbd4c3bf034c244e02a117285a6576c837bf6304d59656052f9cbfb837c88
> (11)   EAP-Session-Id =
> 0x0d894df71571b44caa45ce419e7802bc2f64696a756113459d3036ed36abbf8be85e6cb1c6fd2673e4e50a26b49d6a3157a086a7f38d6f0d55e7e3ff8b8e4a1e03
> (11)   EAP-Message = 0x030c0004
> (11)   Message-Authenticator = 0x00000000000000000000000000000000
> (11)   User-Name = "martin-test-client-cert"
> (11) eap_teap: Got tunneled Access-Accept

  That's good.

> (12) eap_teap: Session established.  Proceeding to decode tunneled
> attributes
> (12) eap_teap: EAP-TEAP TLV Status indicates failure.  Rejecting request.
> (12) eap: ERROR: Failed continuing EAP TEAP (55) session.  EAP sub-module
> failed

  And the Windows session sends failure.

  I'll see if I can poke the error messages a little bit, but there isn't really any more information which can be added.

  So let's try some FreeRADIUS configuration magic.  This is undocumented right now, because "TEAP", but here goes:

* in the default virtual server, edit it to add some magic after the "eap" block in "authorize"

...
	eap {
		ok = return
#		updated = return
	}

	#
	# TEAP EAP sequence (chaining) - Machine (EAP-TLS) followed by User (EAP-MSCHAPv2)
	#
	# note this attribute is automatically deleted by FR's internals once auth is complete
	#
	if (&EAP-Type == TEAP && !(&session-state:FreeRADIUS-EAP-TEAP-Identity-Type)) {
		update session-state {
			&FreeRADIUS-EAP-TEAP-Identity-Type := Machine
		}
	}
...

  That tells FreeRADIUS to ask the other end for the Machine identity first.

* in the inner-tunnel virtual server, update it to do more EAP sequence chaining in the "authorize" section:

...
	update control {
		&Proxy-To-Realm := LOCAL
	}

	#
	# TEAP EAP sequence (chaining) - Machine (EAP-TLS) followed by User (EAP-MSCHAPv2)
	#
	# you should comment out the standalone main 'eap' whilst uncommenting this one
	#
	if (&outer.request:EAP-Type == TEAP) {
		if (&outer.session-state:FreeRADIUS-EAP-TEAP-Identity-Type) {
			if (&FreeRADIUS-EAP-TEAP-Identity-Type && (&FreeRADIUS-EAP-TEAP-Identity-Type != &outer.session-state:FreeRADIUS-EAP-TEAP-Identity-Type)) {
				reject
			}
		}

		eap
		if (ok) {
			update config {
				&Auth-Type := TEAP
			}
			return
		}

		update config {
			&Auth-Type := TEAP
		}
	}
	else {
		eap {
			ok = return
		}
	}
...

* and in the "authenticate" section of the inner-tunnel virtual server, add:

...
	#
	# TEAP EAP sequence (chaining) - Machine (EAP-TLS) followed by User (EAP-MSCHAPv2)
	#
	Auth-Type TEAP {
		if (&outer.session-state:FreeRADIUS-EAP-TEAP-Identity-Type == Machine) {
			update control {
				&EAP-Type := EAP-TLS
			}

		} elsif (&outer.session-state:FreeRADIUS-EAP-TEAP-Identity-Type == User) {
			update control {
				&EAP-Type := EAP-MSCHAPv2
			}
		}

		# when chaining, the eap module will return 'ok' for each successfully completed eap type
		eap
		if (ok) {
			if (&outer.session-state:FreeRADIUS-EAP-TEAP-Identity-Type == Machine) {
				update outer.session-state {
					&FreeRADIUS-EAP-TEAP-Identity-Type := User
				}
			} elsif (&outer.session-state:FreeRADIUS-EAP-TEAP-Identity-Type == User) {
				# required so to inform the TEAP module we have finished
				update outer.session-state {
					&FreeRADIUS-EAP-TEAP-Identity-Type !* ANY
				}
			}
		}
	}
...

  This *should* work a bit better.

  TEAP does EAP sequence chaining through an overly complicated design.  It's basically EAP-FAST with some tweaks.

  When TEAP was first being designed, I pushed to use TTLS as the basis instead.  But TEAP had $$$$ behind it, and that was that.

  We're now left with something cobbled together which *might* work.  Or might not.  We don't know, and we don't know why.

  Oh, if FreeRADIUS asks for an identity type that Windows doesn't have, Windows doesn't send an error TLV back.  It sends an empty EAP-Message in the inner tunnel.  Because, why send helpful messages?

  The result is that the only way EAP method chaining works is if both supplicant and server are configured to do exactly the same thing.  If the supplicant is configured to do Machine auth only, and the server wants to do method chaining, it won't work.  And the errors you get will be completely useless for debugging.

  I really just suggest avoiding TEAP if at all possible.  I don't see how the method chaining helps anything.  Doing both Machine and User auth is pretty pointless when both credentials are cached on the same machine.  It's not like the user is prompted for an OTP, or some other method which proves that the user was present.

  TEAP method change is just using *two* cached credentials instead of one.  It offers no more security than using one cached credential.

  Alan DeKok.




More information about the Freeradius-Users mailing list