Monday 26 June 2023

Exploring Identity Privacy, TEAP and TTLS in conjunction with Microsoft Network Policy Server

 

Windows 10/11 clients include at least three EAP (Extensible Authentication Protocol) methods than can both be used in conjunction with 802.1X or VPN protocols and also support identity privacy/protection: PEAP (Protected EAP), TEAP (Tunnel EAP) and EAP-TTLS (EAP Tunneled Transport Layer Security).

On the server side, NPS (Network Policy Server) only supports PEAP natively but additional EAP methods can be plugged in (either as legacy methods or EAPHost based methods).

Enabling identity privacy on the client side is straightforward: just enable the feature and optionally specify a name to be used as the outer (visible) identity. How to “enable” identity privacy on the server side is less obvious; I have used quotation marks around “enable” because identity privacy is not explicitly enabled – one just has to ensure that the NPS configuration is compatible with identity privacy.

NPS has two types of policies: Connection Request Policies (CRP) and Network Policies (previously known as Remote Access Policies (RAP)). The policy type names don’t clearly demarcate their intended purposes. The Microsoft documentation says:

Connection request policies are sets of conditions and settings that allow network administrators to designate which Remote Authentication Dial-In User Service (RADIUS) servers perform the authentication and authorization of connection requests that the server running Network Policy Server (NPS) receives from RADIUS clients. Connection request policies can be configured to designate which RADIUS servers are used for RADIUS accounting.

Network policies are sets of conditions, constraints, and settings that allow you to designate who is authorized to connect to the network and the circumstances under which they can or cannot connect.

Configuring authentication (allowed authentication mechanisms, etc.) seems like something that should be part of the network policy and this indeed is where it is typically defined. However, when searching Microsoft documentation for help on configuring identity privacy, only this short “tip” is readily findable:

Tip

The NPS policy for 802.1X Wireless must be created by using NPS Connection Request Policy. If the NPS policy is created in by using NPS Network Policy, then identity privacy will not work.

The implications of this simple statement are also not immediately obvious. Awareness of the availability of a setting named “Override network policy authentication settings” suggests a possibility:

[…] if the option to Override network policy authentication settings is enabled on the Settings tab in a connection request policy, then authentication is performed in connection request policy. Otherwise, authentication is performed in network policy. Authentication can be configured in both types of policies.

RADIUS requests to NPS are processed by a “pipeline” of stages, defined at HKLM\SYSTEM\CurrentControlSet\Services\RemoteAccess\Policy\Pipeline; the stages (in order of evaluation) are:

 

Stage

Providers

Reasons

Replays

Requests

Responses

1

IAS.ProxyPolicyEnforcer

 

 

 

0 1 2

0 1 2 3 4

2

IAS.Realm

1

 

 

0 1

0

3

IAS.Realm

0 2

 

 

0 1

0

4

IAS.NTSamNames

1

 

 

0

0

5

IAS.CRPBasedEAP

1

 

 

0 2

0

6

IAS.Realm

1

 

0

0

0

7

IAS.NTSamNames

1

 

0

0

0

8

IAS.MachineNameMapper

1

 

0

0

0

9

IAS.BaseCampHost

 

 

0

 

 

10

IAS.RadiusProxy

2

 

0

 

0

11

IAS.ExternalAuthNames

2

 

0

 

0

12

IAS.NTSamAuthentication

1

 

0

0

0 1 2

13

IAS.UserAccountValidation

1 3

33

0

0

0 1

14

IAS.MachineAccountValidation

1

 

0

0

0 1

15

IAS.EAPIdentity

1

 

0

0

0 1

17

IAS.PolicyEnforcer

1 3

33

0

0

0 1

18

IAS.NTSamPerUser

1 3

33

0

0

0 1

19

IAS.URHandler

1 3

33

0

0

0 1

20

IAS.RAPBasedEAP

1

 

0

0 2

0

21

IAS.PostEapRestrictions

0 1 3

 

0

0

0 1

23

IAS.ChangePassword

1

 

0

0

1

24

IAS.AuthorizationHost

 

 

0

 

 

25

IAS.EAPTerminator

0 1

 

0

0 2

1 2 3 5

26

IAS.DatabaseAccounting

 

 

 

 

 

27

IAS.Accounting

 

 

 

 

 

28

IAS.MSChapErrorReporter

0 1 3

 

0

0

2

Providers: 0 None, 1 Windows, 2 RADIUS Proxy, 3  External Authentication

Reasons: 33 → PASSWORD_MUST_CHANGE

Replays: 0 → FALSE

Requests: 0 → ACCESS_REQUEST, 1 → ACCOUNTING, 2 → CHALLENGE_RESPONSE

Responses: 0 → INVALID, 1 → ACCESS_ACCEPT, 2 → ACCESS_REJECT, 3 → ACCESS_CHALLENGE, 4 → ACCOUNTING, 5 → DISCARD_PACKET

Each stage gets a chance to handle the request, if the current request state (provider, reason, replays, requests, responses) allows.

If the “outer” identity does not exist, stage 13 (IAS.UserAccountValidation) reports reason NO_SUCH_USER.

If the “outer” identity exists but is disabled, stage 13 (IAS.UserAccountValidation) reports reason ACCOUNT_EXPIRED.

If the “outer” identity is usable but differs from the “inner” identity, stage 20 (IAS.RAPBasedEAP) reports problem ERROR_PEAP_IDENTITY_MISMATCH.

If the authentication settings are set on the Connection Request Policy then stage 5 (IAS.CRPBasedEAP) gets a chance to handle the request and influence its handling by later pipeline stages.

The NPS log file entries for a PEAP-MSCHAPv2 authenticated VPN session with identity privacy contain the following usernames:

User-Name = "anonymous"
User-Name = "anonymous"
User-Name = "anonymous"
User-Name = "anonymous"
User-Name = "anonymous"
User-Name = "anonymous"
User-Name = "anonymous"
User-Name = "GARY"
User-Name = "GARY"
User-Name = "GARY"
User-Name = "GARY"
User-Name = "anonymous"
User-Name = "anonymous"

There are 24 entries in total (the “challenge response” entries don’t have a username value). The initial EAP and EAP TLS establishment entries contain the “outer” identity, the inner MSCHAPv2 exchanges contain the “inner” identity and the accounting start/stop entries use the “outer” identity.

Implementing “toy” server-side (authenticator) TEAP and EAP-TTLS support

Each client-side (supplicant) EAP method includes a “properties” value in the registry; below is a summary of five of the methods installed by default in Windows 10/11.

Property

Value

TEAP

PEAP

EAP-TTLS

EAP-TLS

MSCHAPv2

PropCipherSuiteNegotiation

0x00000001

X

X

X

X

 

PropMutualAuth

0x00000002

X

X

X

X

X

PropIntegrity

0x00000004

X

X

X

X

X

PropReplayProtection

0x00000008

X

X

X

X

X

PropConfidentiality

0x00000010

X

X

 

 

 

PropKeyDerivation

0x00000020

X

X

X

X

X

PropKeyStrength64

0x00000040

 

 

 

 

X

PropKeyStrength128

0x00000080

X

X

X

X

 

PropKeyStrength256

0x00000100

 

 

 

 

 

PropKeyStrength512

0x00000200

 

 

 

 

 

PropKeyStrength1024

0x00000400

 

 

 

 

 

PropDictionaryAttackResistance

0x00000800

X

X

X

X

 

PropFastReconnect

0x00001000

X

X

X

X

 

PropCryptoBinding

0x00002000

X

X

 

 

 

PropSessionIndependence

0x00004000

X

X

X

X

X

PropFragmentation

0x00008000

X

X

X

X

 

PropChannelBinding

0x00010000

 

 

 

 

 

PropNap

0x00020000

 

X

 

 

 

PropStandalone

0x00040000

X

X

X

 

X

PropMppeEncryption

0x00080000

X

X

X

X

X

PropTunnelMethod

0x00100000

X

X

X

 

 

PropSupportsConfig

0x00200000

X

X

X

X

X

PropCertifiedMethod

0x00400000

X

 

 

 

 

PropHiddenMethod

0x00800000

 

 

 

 

 

PropMachineAuth

0x01000000

X

X

X

X

X

PropUserAuth

0x02000000

X

X

X

X

X

PropIdentityPrivacy

0x04000000

X

X

X

 

 

PropMethodChaining

0x08000000

X

 

 

 

 

PropSharedStateEquivalence

0x10000000

X

X

X

X

 

 

0x20000000

X

 

 

 

 

PropReserved

0x80000000

 

 

 

 

 

Based on experience analyzing PEAP behaviour, I thought that it would be feasible to implement server-side (authenticator) support for EAP-TTLS and TEAP; furthermore, I expected a good deal of commonality between the implementations, so I created a generic (in the C# sense) tunnel EAP class to handle common tasks (such as establishing the TLS tunnel using Schannel, EAP identity, EAP negotiation, EAP fragmentation) which could be specialized by types that could handle method specific tasks (such as TLV or AVP encapsulation, master session key generation, etc.).

There are two development frameworks for EAP methods: legacy EAP and EAPHost. Because the implementation would be tunneling EAP-MSCHAPv2 (which is a legacy EAP implementation) and because PEAP is also a legacy EAP implementation, I chose to use the legacy EAP framework too.

Implementing EAP-TTLS without support for identity privacy was straightforward. It (more specifically EAP-TTLSv0) does not support cryptobinding, so all that is required is packing and unpacking EAP messages in TTLS AVP (attribute-value pair) format and calculating/obtaining the master session key (available via SetContextAttributes /QueryContextAttributes with SecPkgContext_EapPrfInfo/SecPkgContext_EapKeyBlock and “EAP-TTLSv0 Keying Material”).

Adding identity privacy support involves use of undocumented (or poorly documented) features of the Windows EAP frameworks. In particular, the “action” EAPACTION_IndicateIdentity (documentation: “Reserved for system use”) or its EAPHost equivalent EAP_METHOD_AUTHENTICATOR_RESPONSE_AUTHENTICATE (documentation: “The authenticator method has started authentication of the supplicant” – at best unhelpful and possibly totally incorrect). It seems that although frameworks for new EAP methods are supported, it was not expected that new “tunnel” EAP methods would be needed.

The EAPACTION_IndicateIdentity action allows NPS to be informed of the inner identity which can then be passed on to NPS policy stages such as IAS.UserAccountValidation that might otherwise fail the authentication on the basis of the outer identity.

TEAP

The TEAP RFC is twice the length of the EAP-TTLS RFC (100 pages vs. 50 pages) and there is also quite a lengthy “Errata” report for the TEAP RFC. Before reading the errata, I puzzled over whether an Intermediate-Result TLV was necessary if there was only one inner method: the RFC is ambiguous (with a tendency to “not necessary”), the errata says that an Intermediate-Result TLV is mandatory and the Windows TEAP client expects such a TLV. I also make a mistake with the “MSK Compound MAC” in the crypto-binding TLV (not truncating the value when, for example, SHA-384 is used instead of SHA-1).

Fortunately the ETW tracing for TEAP (provider Microsoft.Windows.Eap.Teap) is very helpful. This highlighted extract shows some of the useful information in the trace data:


The keying information from the TLS tunnel that is needed for the TEAP cryptographic calculations can be obtained via SetContextAttributes /QueryContextAttributes with SecPkgContext_KeyingMaterialInfo/SecPkgContext_KeyingMaterial.