Identifying FIDO2 key capabilities

Here is a tip for identifying what your FIDO2 key’s capabilities are. This is useful when you don’t have access to docs from the vendor or just want to be certain of the key capabilities.

The below process is written for those using Windows 10.

    1. Open the settings app
      fidogetinfo1
    2. Click “Accounts”—> “Sign-in Options” –> “Security Key” and then click “Manage”
      fidogetinfo2
    3. Insert your security key if you haven’t already done so now. Then tap your key.
      fidogetinfo3
      fidogetinfo4
    4. Now click close.
      fidogetinfo5
    5. Open the Event Viewer and navigate to “Application and Services” –> “Microsoft” –> “Windows” –> “WebAuthn” –> “operational”
    6. Filter for event “2102” to get CTAP responses.fidogetinfo6fidogetinfo7
    7. Use “Find” to locate the most recent “GetInfo” CTAP command response. You should have a response like so.fidogetinfo9
    8. Copy the entire hexadecimal response value to your clipboard.
    9. Open your preferred web browser and navigate to http://cbor.me
    10. Paste the copied response on the right in the “Bytes” section. Select “emb cbor” for embedded cbor and click the “left arrow” to decode into CBOR diagnostic notation.
      fidogetinfo11
    11. You should see a response like so.
      fidogetinfo12
    12. I’ve pasted a prettified version of the CBOR diagnostic notation the left below.

[{“deviceInfo”:
{“providerType”: “Hid”,
“providerName”: “MicrosoftCtapHidProvider”,
“devicePath”: “\\\\?\\hid#vid_096e&pid_0866&mi_00#7&7cce53e&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”,
“manufacturer”: “FS”,
“product”: “BioPassFIDO2”,
“pinStatus”: 0,
“pinRetries”: 8},

“status”: 0,
“response”: << 0,
{1: [“FIDO_2_0”, “FIDO_2_1_PRE”],
2: [“credProtect”, “hmac-secret”],
3: h’12DED7454BED47D4ABAAE713F51D6393′,
4: {“rk”: true, “up”: true, “uv”: false, “plat”: false, “clientPin”: false, “credentialMgmtPreview”: true, “userVerificationMgmtPreview”: false},
5: 2048,
6: [1],
7: 10,
8: 96,
9: [“usb”],
10: [{“alg”: -7, “type”: “public-key”}]} >>}]

The spec documents at https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorGetInfo help us understand the response for pure CTAP 2.0 based keys. But as this is a key supporting CTAP 2.1 preview features, Client to Authenticator Protocol (CTAP) (fidoalliance.org) provides more details.

The device info section indicates the vendor and model of my key. In my case this is a Feitian BioPass K43 which simply identifies itself as “BioPassFIDO2” . We also see it reveals pin status for the key. We have 8 retries remaining before lockout.

The response’s 1st section identifies the CTAP protocols supported. This key supports both 2.0 and 2.1 CTAP preview features.

The 2nd section of the response identifies the extensions supported. This key supports both credprotect and the hmac-secret extensions.

The 3rd section identifies the AAGUID of the key. We can convert it to the commonly recognised format with hyphens like so.

PS C:\Users\maweeras> [guid]”12DED7454BED47D4ABAAE713F51D6393″

Guid
—-
12ded745-4bed-47d4-abaa-e713f51d6393

PS C:\Users\maweeras>

The 4th section identifies the supported options. This map reveals

  • rk (resident keys) on the device are possible.
  • up (user presence) can be tested .
  • uv (user verification)is false indicating it has built-in biometric capabilities to verify user but is unconfigured currently.
  • plat (platform) is false as this is a roaming authenticator as opposed to a Windows Hello or similar key tied to the client.
  • clientPin is false as a PIN has not been set yet (although key is capable of configuring one).

The 5th is the maximum message size.

The 6th is supported pin protocol versions.

The 7th is maximum number of supported credentials in credentialid.

The 8th maximum credential id length.

The 9th is the supported transports for this key. This key supports usb only.

The 10th lists the supported algorithms for credential generation. As per https://www.iana.org/assignments/cose/cose.xhtml#algorithms “-7” is ECDSA w/ SHA-256.

All sections aren’t mandatory. Some keys may not output as much detail.

Here are some prettified versions of some of the other keys I have.

Feitian K33

[{“deviceInfo”: {“providerType”: “Hid”
“providerName”: “MicrosoftCtapHidProvider”
“devicePath”: “\\\\?\\hid#vid_096e&pid_0867&mi_00#7&3aa32f22&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”
“manufacturer”: “FS”
“product”: “BioPassFIDO2”
“pinStatus”: 0
“pinRetries”: 8}
“status”: 0, “response”: << 0
{1: [“FIDO_2_0”, “FIDO_2_1_PRE”]
2: [“credProtect”, “hmac-secret”]
3: h’12DED7454BED47D4ABAAE713F51D6393′
4: {“rk”: true, “up”: true, “uv”: true, “plat”: false, “clientPin”: true, “credentialMgmtPreview”: true, “userVerificationMgmtPreview”: true}
5: 2048
6: [1]
7: 10
8: 96
9: [“usb”]
10: [{“alg”: -7, “type”: “public-key”}]} >>}]

Feitian K25

[{“deviceInfo”: {“providerType”: “Hid”
“providerName”: “MicrosoftCtapHidProvider”
“devicePath”: “\\\\?\\hid#vid_096e&pid_085a#6&1c3b446a&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”
“manufacturer”: “FS”
“product”: “ePass FIDO”}
“status”: 0, “response”: << 0
{1: [“U2F_V2”, “FIDO_2_0”, “FIDO_2_1_PRE”]
2: [“hmac-secret”, “credProtect”]
3: h’310B2830BD4A4DA5832E9A0DFC90ABF2′
4: {“rk”: true, “up”: true, “plat”: false, “clientPin”: false, “credentialMgmtPreview”: true}
5: 1024
6: [1]
7: 6
8: 96} >>}]

Feitian A4B

[{“deviceInfo”: {“providerType”: “Hid”
“providerName”: “MicrosoftCtapHidProvider”
“devicePath”: “\\\\?\\hid#vid_096e&pid_0854&mi_01#7&2fcc7723&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”
“manufacturer”: “FT”
“product”: “FIDO”
“pinStatus”: 0
“pinRetries”: 8}
“status”: 0, “response”: << 0
{1: [“U2F_V2”, “FIDO_2_0”]
2: [“credProtect”, “hmac-secret”]
3: h’833B721AFF5F4D00BB2EBDDA3EC01E29′
4: {“rk”: true, “up”: true, “uv”: false, “plat”: false, “clientPin”: true}
5: 2048
6: [1]
7: 10
8: 96
9: [“usb”]
10: [{“alg”: -7, “type”: “public-key”}]} >>}]

Feitian K26

[{“deviceInfo”: {“providerType”: “Hid”
“providerName”: “MicrosoftCtapHidProvider”
“devicePath”: “\\\\?\\hid#vid_096e&pid_085d&mi_00#7&3a9eb008&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”
“manufacturer”: “FS”
“product”: “BioPassFIDO2”
“pinStatus”: 0
“pinRetries”: 8}
“status”: 0, “response”: << 0
{1: [“U2F_V2”, “FIDO_2_0”, “FIDO_2_1_PRE”]
2: [“credProtect”, “hmac-secret”]
3: h’77010BD7212A4FC9B236D2CA5E9D4084′
4: {“rk”: true, “up”: true, “uv”: true, “plat”: false, “clientPin”: true, “credentialMgmtPreview”: true, “userVerificationMgmtPreview”: true}
5: 2048
6: [1]
7: 10
8: 96
9: [“usb”]
10: [{“alg”: -7, “type”: “public-key”}]} >>}]

Feitian K27

[{“deviceInfo”: {“providerType”: “Hid”
“providerName”: “MicrosoftCtapHidProvider”
“devicePath”: “\\\\?\\hid#vid_096e&pid_085d&mi_00#7&7876465&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”
“manufacturer”: “FS”
“product”: “BioPassFIDO2”
“pinStatus”: 0
“pinRetries”: 8}
“status”: 0, “response”: << 0
{1: [“U2F_V2”, “FIDO_2_0”, “FIDO_2_1_PRE”]
2: [“credProtect”, “hmac-secret”]
3: h’77010BD7212A4FC9B236D2CA5E9D4084′
4: {“rk”: true, “up”: true, “uv”: true, “plat”: false, “clientPin”: true, “credentialMgmtPreview”: true, “userVerificationMgmtPreview”: true}
5: 2048
6: [1]
7: 10
8: 96
9: [“usb”]
10: [{“alg”: -7, “type”: “public-key”}]} >>}]

Feitian iePass FIDO

[{“deviceInfo”: {“providerType”: “Hid”
“providerName”: “MicrosoftCtapHidProvider”
“devicePath”: “\\\\?\\hid#vid_096e&pid_0853&mi_02#7&32d67d08&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”
“manufacturer”: “FS”
“product”: “FIDO”}
“status”: 0, “response”: << 0
{1: [“U2F_V2”, “FIDO_2_0”, “FIDO_2_1_PRE”]
2: [“credProtect”, “hmac-secret”]
3: h’3E22415D7FDF4EA48A0CDD60C4249B9D’
4: {“rk”: true, “up”: true, “plat”: false, “clientPin”: false, “credentialMgmtPreview”: true}
5: 1024
6: [1]
7: 6
8: 96
9: [“usb”]
10: [{“alg”: -7, “type”: “public-key”}]} >>}]

HyperFido Mini

[{“deviceInfo”:
{“providerType”: “Hid”,
“providerName”: “MicrosoftCtapHidProvider”,
“devicePath”: “\\\\?\\hid#vid_2ccf&pid_0854&mi_01#7&188603c6&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”,
“manufacturer”: “HS”,
“product”: “FIDO”,
“pinStatus”: 0,
“pinRetries”: 8},

“status”: 0,
“response”: << 0,
{1: [“U2F_V2”, “FIDO_2_0”],
2: [“hmac-secret”],
3: h’9F77E279A6E24D58B70031E5943C6A98′,
4: {“rk”: true, “up”: true, “uv”: false, “plat”: false, “clientPin”: false},
5: 2048,
6: [1]} >>}]

YubiKey 5 NFC

[{“deviceInfo”:
{“providerType”: “Hid”,
“providerName”: “MicrosoftCtapHidProvider”,
“devicePath”: “\\\\?\\hid#vid_1050&pid_0407&mi_01#7&233ab236&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”,
“manufacturer”: “Yubico”,
“product”: “YubiKey OTP+FIDO+CCID”,
“pinStatus”: 0,
“pinRetries”: 8},

“status”: 0,
“response”: << 0,
{1: [“U2F_V2”, “FIDO_2_0”],
2: [“hmac-secret”],
3: h’FA2B99DC9E3942578F924A30D23C4118′,
4: {“rk”: true, “up”: true, “plat”: false, “clientPin”: true},
5: 1200,
6: [1]} >>}]

YubiKey 5 NFC FIPS

[{“deviceInfo”: {“providerType”: “Hid”,
“providerName”: “MicrosoftCtapHidProvider”,
“devicePath”: “\\\\?\\hid#vid_1050&pid_0407&mi_01#7&233ab236&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”,
“manufacturer”: “Yubico”,
“product”: “YubiKey OTP+FIDO+CCID”},
“status”: 0, “response”: << 0,
{1: [“U2F_V2”, “FIDO_2_0”, “FIDO_2_1_PRE”],
2: [“credProtect”, “hmac-secret”],
3: h’C1F9A0BC1DD2404AB27F8E29047A43FD’,
4: {“rk”: true, “up”: true, “plat”: false, “clientPin”: false, “credentialMgmtPreview”: true},
5: 1200,
6: [2, 1],
7: 8,
8: 128,
9: [“nfc”, “usb”],
10: [{“alg”: -7, “type”: “public-key”}, {“alg”: -8, “type”: “public-key”}],
13: 6,
14: 328706,
19: {“FIPS-CMVP-2”: 2, “FIPS-CMVP-2-PHY”: 3}} >>}]

TrustKey G320H

[{“deviceInfo”: {“providerType”: “Hid”,
“providerName”: “MicrosoftCtapHidProvider”,
“devicePath”: “\\\\?\\hid#vid_311f&pid_4a2a&mi_00#7&3192f11f&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”,
“manufacturer”: “TrustKey”,
“product”: “TrustKey G320H”,
“pinStatus”: 0,
“pinRetries”: 8},
“status”: 0,
“response”: << 0,

{1: [“U2F_V2”, “FIDO_2_0”, “FIDO_2_1_PRE”],
2: [“credProtect”, “hmac-secret”],
3: h’87DBC5A14C944DC88A4797D800FD1F3C’,
4: {“rk”: true, “up”: true, “uv”: false, “plat”: false, “clientPin”: false, “credentialMgmtPreview”: true, “userVerificationMgmtPreview”: false},
5: 2048,
6: [1],
7: 6,
8: 192,
9: [“usb”]} >>}]

GoTrust Idem Key

[{“deviceInfo”: {“providerType”: “Hid”
“providerName”: “MicrosoftCtapHidProvider”
“devicePath”: “\\\\?\\hid#vid_32a3&pid_3201#6&29b4518a&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”
“manufacturer”: “GoTrust”
“product”: “Idem Key”
“pinStatus”: 0
“pinRetries”: 8}
“status”: 0
“response”: << 0,

{1: [“U2F_V2”, “FIDO_2_0”]
2: [“hmac-secret”]
3: h’3B1ADB990DFE46FD90B87F7614A4DE2A’
4: {“rk”: true, “up”: true, “plat”: false, “clientPin”: true}
5: 1024
6: [1]} >>}]

Solo USB-A (after firmware update)

[{“deviceInfo”:
{“providerType”: “Hid”,
“providerName”: “MicrosoftCtapHidProvider”,
“devicePath”: “\\\\?\\hid#vid_0483&pid_a2ca#6&50c1f19&0&0000\#{4d1e55b2-f16f-11cf-88cb-001111000030}”,
“manufacturer”: “SoloKeys”,
“product”: “Solo 4.1.2”,
“pinStatus”: 0,
“pinRetries”: 8},

“status”: 0,
“response”: << 0,
{1: [“U2F_V2”, “FIDO_2_0”, “FIDO_2_1_PRE”],
2: [“credProtect”, “hmac-secret”],
3: h’8976631BD4A0427F57730EC71C9E0279′,
4: {“rk”: true, “up”: true, “plat”: false, “credMgmt”: true, “clientPin”: false},
5: 1200,
6: [1],
7: 20,
8: 128} >>}]

Authentrend ATKey.Pro

[{
“deviceInfo”: {
“maxMsgSize”: 0,
“maxSerializedLargeBlobArray”: 0,
“providerType”: “Hid”,
“providerName”: “MicrosoftCtapHidProvider”,
“devicePath”: “\\\\?\\hid#vid_31bb&pid_0622&mi_00#7&2219d15&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}”,
“manufacturer”: “AuthenTrend Technology Inc.”,
“product”: “ATKey.Pro-2200003E”,
“pinStatus”: 0,
“pinRetries”: 8,
“uvStatus”: 0,
“uvRetries”: 15
},
“status”: 0,
“response”: << 0,
{
1: [“U2F_V2”, “FIDO_2_0”, “FIDO_2_1”, “FIDO_2_1_PRE”],
2: [“credBlob”, “credProtect”, “hmac-secret”, “largeBlobKey”, “minPinLength”],
3: h ‘E416201BAFEB41CAA03D2281C28322AA’,
4: {
“rk”: true,
“up”: true,
“uv”: true,
“plat”: false,
“uvAcfg”: true,
“alwaysUv”: true,
“credMgmt”: true,
“authnrCfg”: true,
“bioEnroll”: true,
“clientPin”: true,
“largeBlobs”: true,
“uvBioEnroll”: true,
“pinUvAuthToken”: true,
“setMinPINLength”: true,
“makeCredUvNotRqd”: false,
“credentialMgmtPreview”: true,
“userVerificationMgmtPreview”: true,
“noMcGaPermissionsWithClientPin”: true
},
5: 2048,
6: [1, 2],
7: 20,
8: 64,
9: [“usb”],
10: [{
“alg”: -7,
“type”: “public-key”
}, {
“alg”: -8,
“type”: “public-key”
}],
11: 1024,
12: false,
13: 4,
14: 20001,
15: 256,
16: 10,
18: 2,
21: [4222588906093956714, 3137615053190153251, 7452615122542182187, 8083404361767209739]
} >>
}]

Hope this helps someone out there Smile

Errors attempting to logon using Azure MFA on Windows Server 2016 TP5

 

Just a quick post on something I ran into while playing around with AD FS on Windows Server 2016 technical preview 5 (TP5).

Configuration

  • Azure MFA has been configured and enabled as a MFA provider in the global authentication policy
  • You may have optionally enabled this as a specific authentication method for the extranet.

 

Symptoms

  • User gets logon screen like so.
  • image
  • You choose Azure MFA and see screen like so.
  • image

You enter your UPN and press tab to enter the corresponding code from the Azure Authenticator app. But you are not given a chance to enter the code and you get the standard error page with a correlation ID etc.

AD FS event log reports an event like so with the stack as indicated.

Here is a link to a text file with event details.

Log Name:      AD FS/Admin
Source:        AD FS
Date:          5/17/2016 4:48:48 PM
Event ID:      364
Task Category: None
Level:         Error
Keywords:      AD FS
User:          contoso\adfssvc$
Computer:      mwgvm2.contoso.com
Description:
Encountered error during federation passive request.

Additional Data

Protocol Name:
wsfed

Relying Party:
https://contoso.onmicrosoft.com/WebApplication1

Exception details:
System.Exception: Exception calling SAS. —> System.Security.Cryptography.CryptographicException: Keyset does not exist

at Microsoft.IdentityServer.Aad.Sas.Adal.Net.AuthenticationContext.RunAsyncTask[T](Task`1 task)
at Microsoft.IdentityServer.Aad.Sas.RealSasProvider.ModifyHttpRequest(HttpWebRequest request)
at Microsoft.IdentityServer.Aad.Sas.HttpClientHelper.PostXml[TRequest,TResponse](String url, TRequest request, Action`1 httpRequestModifier)
at Microsoft.IdentityServer.Adapter.AzureMfa.PrimaryAuthenticationAdapter.ProcessUsernameOathCodePin(IAuthenticationContext authContext, IProofData proofData, Claim[]& outgoingClaims)
— End of inner exception stack trace —
at Microsoft.IdentityServer.Adapter.AzureMfa.PrimaryAuthenticationAdapter.ProcessUsernameOathCodePin(IAuthenticationContext authContext, IProofData proofData, Claim[]& outgoingClaims)
at Microsoft.IdentityServer.Adapter.AzureMfa.PrimaryAuthenticationAdapter.TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, Claim[]& outgoingClaims)
at Microsoft.IdentityServer.Web.Authentication.External.ExternalAuthenticationHandlerBase.TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, Claim[]& adapterClaims)
at Microsoft.IdentityServer.Web.Authentication.Azure.AzurePrimaryAuthenticationHandler.Process(ProtocolContext context)
at Microsoft.IdentityServer.Web.Authentication.AuthenticationOptionsHandler.Process(ProtocolContext context)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.OnGetContext(WrappedHttpListenerContext context)

System.Security.Cryptography.CryptographicException: Keyset does not exist

at Microsoft.IdentityServer.Aad.Sas.Adal.Net.AuthenticationContext.RunAsyncTask[T](Task`1 task)
at Microsoft.IdentityServer.Aad.Sas.RealSasProvider.ModifyHttpRequest(HttpWebRequest request)
at Microsoft.IdentityServer.Aad.Sas.HttpClientHelper.PostXml[TRequest,TResponse](String url, TRequest request, Action`1 httpRequestModifier)
at Microsoft.IdentityServer.Adapter.AzureMfa.PrimaryAuthenticationAdapter.ProcessUsernameOathCodePin(IAuthenticationContext authContext, IProofData proofData, Claim[]& outgoingClaims)
Event Xml:
<Event xmlns=”http://schemas.microsoft.com/win/2004/08/events/event”>
<System>
<Provider Name=”AD FS” Guid=”{2FFB687A-1571-4ACE-8550-47AB5CCAE2BC}” />
<EventID>364</EventID>
<Version>0</Version>
<Level>2</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000001</Keywords>
<TimeCreated SystemTime=”2016-05-17T16:48:48.786392500Z” />
<EventRecordID>260</EventRecordID>
<Correlation ActivityID=”{00000000-0000-0000-2400-0080000000CC}” />
<Execution ProcessID=”10012″ ThreadID=”10216″ />
<Channel>AD FS/Admin</Channel>
<Computer>mwgvm2.contoso.com</Computer>
<Security UserID=”S-1-5-21-875482985-643924731-3949700923-1103″ />
</System>
<UserData>
<Event xmlns=”http://schemas.microsoft.com/ActiveDirectoryFederationServices/2.0/Events”>
<EventData>
<Data>wsfed</Data>
<Data>https://contoso.onmicrosoft.com/WebApplication1</Data>
<Data>System.Exception: Exception calling SAS. —&gt; System.Security.Cryptography.CryptographicException: Keyset does not exist

at Microsoft.IdentityServer.Aad.Sas.Adal.Net.AuthenticationContext.RunAsyncTask[T](Task`1 task)
at Microsoft.IdentityServer.Aad.Sas.RealSasProvider.ModifyHttpRequest(HttpWebRequest request)
at Microsoft.IdentityServer.Aad.Sas.HttpClientHelper.PostXml[TRequest,TResponse](String url, TRequest request, Action`1 httpRequestModifier)
at Microsoft.IdentityServer.Adapter.AzureMfa.PrimaryAuthenticationAdapter.ProcessUsernameOathCodePin(IAuthenticationContext authContext, IProofData proofData, Claim[]&amp; outgoingClaims)
— End of inner exception stack trace —
at Microsoft.IdentityServer.Adapter.AzureMfa.PrimaryAuthenticationAdapter.ProcessUsernameOathCodePin(IAuthenticationContext authContext, IProofData proofData, Claim[]&amp; outgoingClaims)
at Microsoft.IdentityServer.Adapter.AzureMfa.PrimaryAuthenticationAdapter.TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, Claim[]&amp; outgoingClaims)
at Microsoft.IdentityServer.Web.Authentication.External.ExternalAuthenticationHandlerBase.TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, Claim[]&amp; adapterClaims)
at Microsoft.IdentityServer.Web.Authentication.Azure.AzurePrimaryAuthenticationHandler.Process(ProtocolContext context)
at Microsoft.IdentityServer.Web.Authentication.AuthenticationOptionsHandler.Process(ProtocolContext context)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.OnGetContext(WrappedHttpListenerContext context)

System.Security.Cryptography.CryptographicException: Keyset does not exist

at Microsoft.IdentityServer.Aad.Sas.Adal.Net.AuthenticationContext.RunAsyncTask[T](Task`1 task)
at Microsoft.IdentityServer.Aad.Sas.RealSasProvider.ModifyHttpRequest(HttpWebRequest request)
at Microsoft.IdentityServer.Aad.Sas.HttpClientHelper.PostXml[TRequest,TResponse](String url, TRequest request, Action`1 httpRequestModifier)
at Microsoft.IdentityServer.Adapter.AzureMfa.PrimaryAuthenticationAdapter.ProcessUsernameOathCodePin(IAuthenticationContext authContext, IProofData proofData, Claim[]&amp; outgoingClaims)

</Data>
</EventData>
</Event>
</UserData>
</Event>

 

Cause

The AD FS service account has no access to the private key corresponding to the cert used to communicate with Azure MFA service.

 

Resolution

  • Use procmon from sysinternals to track file activity to paths beginning with “C:\ProgramData\Application Data\microsoft\crypto\RSA\MachineKeys”. You may choose to filter the procmon so you only see the activity of interest.
  • note the “access denied” result returned for files accessed by the adfssrv service process (Microsoft.IdentityServer.ServiceHost.exe).
  • Grant read-only permissions to the “NT SERVICE\adfssrv” service SID.

Workplace join as seen by Fiddler

Workplace join (WPJ) was first introduced in Windows 8.1 but was then back ported to Windows 7. Workplace join uses the device registration service (DRS) on AD FS or Azure AD to get a certificate to authenticate the device.

Fiddler is a useful tool to examine HTTP traffic. And here is how we can use it to see what happens at the device side during a workplace join.

Basics for configuring Fiddler are

  1. Install Fiddler from here
  2. Enable HTTP decryption as per  this article
  3. Follow this article to avoid issues with extended protection if using DRS on AD FS via Windows Integrated Auth while using Fiddler on your corporate network. Else, this can be skipped.
  4. Use the this doc allow the modern settings app in Windows 8.1 and above to be traced via Fiddler.

 

The remainder of the article will examine data collected for a Windows 8.1 PC while it was doing a workplace join.

The trace below was collected while doing WPJ via a Web Application Proxy (WAP).

Lets start with the discovery request.

image

JSON tab in Fiddler is useful to view the response.

Here the response from “https://EnterpriseRegistration.maweeras2.lab/EnrollmentServer/contract?api-version=1.0” shows the OAuth endpoints we should use to get authorization codes and then access tokens. The DRS endpoint that will issue the cert is also shown here.

If you check the client side, Workplace Join/Admin event log (accessed via Applications and Services\Microsoft\Windows) you will note event 100 with this text.

Workplace Join discovery succeeded. Activity Id: NULL

Click on details to see the full event along with discovered info.

<Event xmlns=”http://schemas.microsoft.com/win/2004/08/events/event”>
<System>
<Provider Name=”Microsoft-Windows-Workplace Join” Guid=”{76AB12D5-C986-4E60-9D7C-2A092B284CDD}” />
<EventID>100</EventID>
<Version>0</Version>
<Level>4</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime=”2015-12-05T13:05:02.090168300Z” />
<EventRecordID>29</EventRecordID>
<Correlation />
<Execution ProcessID=”2264″ ThreadID=”4484″ />
<Channel>Microsoft-Windows-Workplace Join/Admin</Channel>
<Computer>PC1.maweeras2.lab</Computer>
<Security UserID=”S-1-5-21-194226691-3252264409-2149212596-1109″ />
</System>
<EventData>
<Data Name=”ActivityId”>NULL</Data>
<Data Name=”JWT”>{“DeviceRegistrationService”:{“RegistrationEndpoint”:”https:\/\/sts.maweeras2.lab\/EnrollmentServer\/DeviceEnrollmentWebService.svc”,”RegistrationResourceId”:”urn:ms-drs:sts.maweeras2.lab”,”ServiceVersion”:”1.0″},”AuthenticationService”:{“OAuth2”:{“AuthCodeEndpoint”:”https:\/\/sts.maweeras2.lab\/adfs\/oauth2\/authorize”,”TokenEndpoint”:”https:\/\/sts.maweeras2.lab\/adfs\/oauth2\/token”}},”IdentityProviderService”:{“PassiveAuthEndpoint”:”https:\/\/sts.maweeras2.lab\/adfs\/ls”}}</Data>
</EventData>
</Event>

In the next frame below we see the attempts to use OAuth2 and get an authorization token. Here is the raw request header.

GET https://sts.maweeras2.lab/adfs/oauth2/authorize?response_type=code&client_id=dd762716-544d-4aeb-a526-687b73838a22&resource=urn:ms-drs:sts.maweeras2.lab&redirect_uri=ms-app%3A%2F%2Fwindows.immersivecontrolpanel&login_hint=mw%40maweeras2.lab HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-GB
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; MSAuthHost/1.0/In-Domain; rv:11.0) like Gecko
UA-CPU: AMD64
Accept-Encoding: gzip, deflate
Host: sts.maweeras2.lab
Connection: Keep-Alive

The highlighted guid is the unique OAuth2 Client ID known to AD FS that identifies this request issuer as device registration client (for workplace join) running on the Windows 8.1 PC (invoked from the modern settings app). All Windows PC’s will use this hard coded guid.

image

I am using the webview tab in the bottom pane to show the forms based auth (FBA) page rendered while accessing the WAP. As the global authentication policy on my AD FS farm has configured only FBA for extranet I am presented with this FBA page.

I have not configured any requirement to do MFA when requesting tokens for the DRS endpoint externally via WAP as this is a lab. In production environments some MFA use is recommended.

We now see the response to the credentials been posted.

image

Note the credentials seen in the clear within the Fiddler POST request.

We get a 302 redirect which is the same request as earlier but with an added ssocookie parameter in the query string.  We also have a cookie to represent the credentials posted.

image

The cookie is validated and MSISAuth cookie is set indicating authentication was successful. We have an authorization code returned in a 302 redirect. The client side modern settings app as the OAuth2 client will use this authorization code to now get an access token.

image

 

We have a bearer token now. We see its valid for an hour.

Lets decode the value in “access_token” via http://authnauthz.com or http://jwt.io

Header section has…

{

“typ”: “JWT”,

“alg”: “RS256”,

“x5t”: “NT7XQomMBJvC5hovEkWcpY7WhVA”

}

Data section has …

{

“aud”: “urn:ms-drs:sts.maweeras2.lab”,

“iss”: “http://sts.maweeras2.lab/adfs/services/trust“,

“iat”: 1449320718,

“exp”: 1449324318,

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/implicitupn“: “mw@maweeras2.lab”,

“pwdexptime”: “2016-01-16T13:04:45.812Z”,

“authmethod”: “urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport”,

“auth_time”: “2015-12-05T13:05:18.610Z”,

“upn”: “mw@maweeras2.lab”,

“primarysid”: “S-1-5-21-194226691-3252264409-2149212596-1109”,

“unique_name”: “MAWEERAS2\\mw”,

“winaccountname”: “MAWEERAS2\\mw”,

“amr”: “urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport”,

“clientuseragent”: “Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; MSAuthHost/1.0/In-Domain; rv:11.0) like Gecko”,

“endpointpath”: “/adfs/oauth2/authorize”,

“insidecorpnetwork”: “false”,

“proxy”: “wap1”,

“clientreqid”: “00000000-0000-0000-0f00-0080000000cc”,

“forwardedclientip”: “10.1.1.4”,

“clientip”: “10.1.1.3”,

http://schemas.microsoft.com/authorization/claims/PermitDeviceRegistration“: “true”,

“ver”: “1.0”,

“appid”: “dd762716-544d-4aeb-a526-687b73838a22”

}

forwarded-client-ip represents the IP address seen by WAP when it received the request. It forwards this to AD FS. As my PC directly accessed WAP (without going via firewalls or NAT devices) the WAP saw my real client PC IP address.

client-ip is actually the WAP server’s IP address.

This access token will now be used to obtain a certificate from DRS. Note that request in the next frame.

image

Here we see the SOAP header in the request containing the Base64 encoded JWT token (access token) we received earlier. If you scroll down in the request you will see a PKCS10 request representing a request for a certificate.

AD FS process this request and sends a RSTR containing the signed cert and other info. Its received as a Base64 encoded binary blob. The XML tab is useful to see the relevant fields.

If curious you can read up more about the payload and its contents here.

The client side Workplace Join Admin event log will now have event 201 with text similar to below.

Workplace Join operation succeeded. Activity Id: 5d711a21-6f82-4178-8314-9b08da34490c
Registration Service URI: https://sts.maweeras2.lab/EnrollmentServer/DeviceEnrollmentWebService.svc

Click details to see full event like so.

<Event xmlns=”http://schemas.microsoft.com/win/2004/08/events/event”&gt;
<System>
<Provider Name=”Microsoft-Windows-Workplace Join” Guid=”{76AB12D5-C986-4E60-9D7C-2A092B284CDD}” />
<EventID>201</EventID>
<Version>0</Version>
<Level>4</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime=”2015-12-05T13:05:26.605287300Z” />
<EventRecordID>30</EventRecordID>
<Correlation />
<Execution ProcessID=”2264″ ThreadID=”4484″ />
<Channel>Microsoft-Windows-Workplace Join/Admin</Channel>
<Computer>PC1.maweeras2.lab</Computer>
<Security UserID=”S-1-5-21-194226691-3252264409-2149212596-1109″ />
</System>
<EventData>
<Data Name=”ActivityId”>5d711a21-6f82-4178-8314-9b08da34490c</Data>
<Data Name=”SoapResponse”>&lt;s:Envelope xmlns:s=”http://www.w3.org/2003/05/soap-envelope&#8221; xmlns:a=”http://www.w3.org/2005/08/addressing”&gt;&lt;s:Header&gt;&lt;a:Action s:mustUnderstand=”1″&gt;http://schemas.microsoft.com/windows/pki/2009/01/enrollment/RSTRC/wstep&lt;/a:Action&gt;&lt;ActivityId CorrelationId=”34171a3c-603c-4fd8-b6fe-ebb35c21cf63″ xmlns=”http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics”&gt;5d711a21-6f82-4178-8314-9b08da34490c&lt;/ActivityId&gt;&lt;a:RelatesTo&gt;urn:uuid:0d5a1441-5891-453b-becf-a2e5f6ea3749&lt;/a:RelatesTo&gt;&lt;/s:Header&gt;&lt;s:Body&gt;&lt;RequestSecurityTokenResponseCollection xmlns=”http://docs.oasis-open.org/ws-sx/ws-trust/200512″&gt;&lt;RequestSecurityTokenResponse&gt;&lt;TokenType&gt;http://schemas.microsoft.com/5.0.0.0/ConfigurationManager/Enrollment/DeviceEnrollmentToken&lt;/TokenType&gt;&lt;RequestedSecurityToken&gt;&lt;BinarySecurityToken ValueType=”http://schemas.microsoft.com/5.0.0.0/ConfigurationManager/Enrollment/DeviceEnrollmentProvisionDoc&#8221; EncodingType=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd#base64binary&#8221; xmlns=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”&gt;PHdhcC1wcm92aXNpb25pbmdkb2MgdmVyc2lvbj0iMS4xIj4NCiAgPGNoYXJhY3RlcmlzdGljIHR5&amp;#xD;
cGU9IkNlcnRpZmljYXRlU3RvcmUiPg0KICAgIDxjaGFyYWN0ZXJpc3RpYyB0eXBlPSJNeSI+DQog&amp;#xD;
ICAgICA8Y2hhcmFjdGVyaXN0aWMgdHlwZT0iVXNlciI+DQogICAgICAgIDxjaGFyYWN0ZXJpc3Rp&amp;#xD;
YyB0eXBlPSI1QjJFNURBNzE3MEI2REEwRTYwMTNEOTgyQ0IyODdDQjFEREVEQ0Y2Ij4NCiAgICAg&amp;#xD;
ICAgICA8cGFybSBuYW1lPSJFbmNvZGVkQ2VydGlmaWNhdGUiIHZhbHVlPSJNSUlFRXpDQ0F2dWdB&amp;#xD;
d0lCQWdJUUJZbCtCc1QyeGI5TEZvRmdBU2ZaRWpBTkJna3Foa2lHOXcwQkFRc0ZBREI2TVhnd0VR&amp;#xD;
WUtDWkltaVpQeUxHUUJHUllEYkdGaU1CY0dDZ21TSm9tVDhpeGtBUmtXQ1cxaGQyVmxjbUZ6TWpB&amp;#xD;
ZEJnTlZCQU1URmsxVExVOXlaMkZ1YVhwaGRHbHZiaTFCWTJObGMzTXdLd1lEVlFRTEV5UmlNelZq&amp;#xD;
TnpsaE1pMDFZek0zTFRSbU1HWXRZV1l4TkMwd09HVXdZVGRoTlRSbU4yRXdIaGNOTVRVeE1qQTFN&amp;#xD;
VE13TURJMFdoY05NalV4TWpBeU1UTXdOVEkwV2pBdk1TMHdLd1lEVlFRREV5UXlaVGhrWWpFeE1p&amp;#xD;
MWlaR1JsTFRRM09UUXRZbVl3TUMxallXUmlabVU0TkRRek5ERXdnZ0VpTUEwR0NTcUdTSWIzRFFF&amp;#xD;
QkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDYlY0Zzg1Vkx2RUo3WVd5b0hzWW9aOFJpWVBaRjdBSE9K&amp;#xD;
aHJmMWRBV0xQbnJuekRqVGZsQlkvR3dmY3ZGbU9BdUhFUFZpZEEvZEdiSnNTQVl0dlJvc0w1aUl1&amp;#xD;
Q25qVlZmS0ZZU0RXdlZDbVFjMHdjWWVmemV2dHdCUDFmaURlM2UwUUdYclVrYWRlZVI4Z3Exb1Rj&amp;#xD;
WU01RGhzbnFZUnZSbW1jQWlKVkhOV1d5OUVjU2xCeGtmVk10MW9kdzM3clF2YlllT3crRWxvYUFi&amp;#xD;
NzZqWW1UYllGYVFUQmN0VTNVdVBqOEM0S0c3am11TjcwdW5tcFk3Ti81enljblROVlhjTUxHUWVs&amp;#xD;
dFMxS0J5a0JYQndLUFU4OStJMlZCVHM5akV1SnB2VmlnOW5SVFlxdjA3bjRBUFJzbGw3Mmd6MWY0&amp;#xD;
b1ZpSEhhd3diZUhuaTZlRXZrcThvSW5BZ01CQUFHQkVRRHh2Mk5ZRytMZVFxbXI0REY2Qm5ZUmdo&amp;#xD;
RUFFckdOTHQ2OWxFZS9BTXJiL29SRFFhT0J1VENCdGpBTUJnTlZIUk1CQWY4RUFqQUFNQ0lHQ3lx&amp;#xD;
R1NJYjNGQUVGZ2h3REJCTUVnUkRUa0tXQjE0bG1TSmpZc0pQKzVJWmNNQ0lHQ3lxR1NJYjNGQUVG&amp;#xD;
Z2h3Q0JCTUVnUkFTc1kwdTNyMlVSNzhBeXR2K2hFTkJNQ0lHQ3lxR1NJYjNGQUVGZ2h3RUJCTUVn&amp;#xD;
UkN4VFluNkpNMDdSSWRRUjc2WEpwTGRNQllHQTFVZEpRRUIvd1FNTUFvR0NDc0dBUVVGQndNQ01D&amp;#xD;
SUdDeXFHU0liM0ZBRUZnaHdCQkJNRWdSQllrak91bDcrTlRvZ0RqWW84Q3I4YU1BMEdDU3FHU0li&amp;#xD;
M0RRRUJDd1VBQTRJQkFRQ29LSVlQa2QrTG5GWVBad2ZmejZ3R0hGam5DcmM2NzB6YjAxMHhaU1o3&amp;#xD;
ckR3V1dSWXVZZWVXKzcvOTRsbFRJdjk2OWhMd0NXN20ybUIrWXBZYzlPTEpLTFowYmV2Y3Z6dFNT&amp;#xD;
NUxHUThZRSt2R25CUHdoT2NlNnp3SGhRT1VyczE0UmwvY1lSSTZmRXVlTUxueDJmaXhVOC85NE9u&amp;#xD;
eTljU1p1V1JWa1hGdzFHek1IYmZMaGIzRVA5Mzcray9RcEZvYmQrSkdFWjRneWhxbmF4cktMUkFR&amp;#xD;
V2tDYWJlUjgweXBUNUFzQnZTN3N5akdaT0c0ZGJwb09LMDYvV3EvY0h0OHp6V2xLbkJEdjRTUkcz&amp;#xD;
OTVJSnBzZW9lNFZTK2JKOXlKUEdNNCtOSHF2aDlFK2x1Q3ozTVllMTBYR2t6MVM1bmZRRytrNC9n&amp;#xD;
bkhXdVBnakJNSzJBQlB4IiAvPg0KICAgICAgICA8L2NoYXJhY3RlcmlzdGljPg0KICAgICAgPC9j&amp;#xD;
aGFyYWN0ZXJpc3RpYz4NCiAgICA8L2NoYXJhY3RlcmlzdGljPg0KICA8L2NoYXJhY3RlcmlzdGlj&amp;#xD;
Pg0KPC93YXAtcHJvdmlzaW9uaW5nZG9jPg==&lt;/BinarySecurityToken&gt;&lt;/RequestedSecurityToken&gt;&lt;RequestID xmlns=”http://schemas.microsoft.com/windows/pki/2009/01/enrollment”&gt;0&lt;/RequestID&gt;&lt;AdditionalContext xmlns=”http://schemas.xmlsoap.org/ws/2006/12/authorization”&gt;&lt;ContextItem Name=”UserPrincipalName”&gt;&lt;Value&gt;mw@maweeras2.lab&lt;/Value&gt;&lt;/ContextItem&gt;&lt;/AdditionalContext&gt;&lt;/RequestSecurityTokenResponse&gt;&lt;/RequestSecurityTokenResponseCollection&gt;&lt;/s:Body&gt;&lt;/s:Envelope&gt;</Data>
<Data Name=”RegistrationServiceUri”>https://sts.maweeras2.lab/EnrollmentServer/DeviceEnrollmentWebService.svc</Data&gt;
</EventData>
</Event>

 

This cert is installed in the user store for the requesting user (mw@maweeras2.lab). You can see it via certmgr.msc .

or PowerShell like so.

PS C:\Users\mw.MAWEERAS2> dir Cert:\CurrentUser\My | Where-Object {$_.issuer -match ‘ms-org’} | fl
Subject : CN=2e8db112-bdde-4794-bf00-cadbfe844341
Issuer : DC=lab + DC=maweeras2 + CN=MS-Organization-Access + OU=b35c79a2-5c37-4f0f-af14-08e0a7a54f7a
Thumbprint : 5B2E5DA7170B6DA0E6013D982CB287CB1DDEDCF6
FriendlyName :
NotBefore : 05/12/2015 13:00:24
NotAfter : 02/12/2025 13:05:24
Extensions : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid,
System.Security.Cryptography.Oid…}

 

We can now look in AD to see the object representing this device.

Here is the object’s dump from ldp.exe.

Expanding base ‘CN=2e8db112-bdde-4794-bf00-cadbfe844341,CN=RegisteredDevices,DC=maweeras2,DC=lab’…
Getting 1 entries:
Dn: CN=2e8db112-bdde-4794-bf00-cadbfe844341,CN=RegisteredDevices,DC=maweeras2,DC=lab
altSecurityIdentities: X509:<SHA1-TP-PUBKEY>5B2E5DA7170B6DA0E6013D982CB287CB1DDEDCF6td6Sl8QssMQnIgD5mao8GPWQtL36xeBB80Gxpm4GFIY=;
cn: 2e8db112-bdde-4794-bf00-cadbfe844341;
displayName: PC1;
distinguishedName: CN=2e8db112-bdde-4794-bf00-cadbfe844341,CN=RegisteredDevices,DC=maweeras2,DC=lab;
dSCorePropagationData: 0x0 = ( );
instanceType: 0x4 = ( WRITE );
msDS-ApproximateLastLogonTimeStamp: 130937943261311661;
msDS-CloudIsManaged: FALSE;
msDS-DeviceID: <ldp: Binary blob 16 bytes>;
msDS-DeviceObjectVersion: 1;
msDS-DeviceOSType: Windows;
msDS-DeviceOSVersion: 6.3.9600.0;
msDS-IsEnabled: TRUE;
msDS-IsManaged: FALSE;
msDS-RegisteredOwner: S-1-5-21-194226691-3252264409-2149212596-1109;
msDS-RegisteredUsers: S-1-5-21-194226691-3252264409-2149212596-1109;
name: 2e8db112-bdde-4794-bf00-cadbfe844341;
objectCategory: CN=ms-DS-Device,CN=Schema,CN=Configuration,DC=maweeras2,DC=lab;
objectClass (2): top; msDS-Device;
objectGUID: 95ade505-4d65-4dd6-b8ca-efda9c235053;
showInAdvancedViewOnly: TRUE;
uSNChanged: 40325;
uSNCreated: 40325;
whenChanged: 05/12/2015 13:05:25 GMT Standard Time;
whenCreated: 05/12/2015 13:05:25 GMT Standard Time;

 

And if we convert the SID of the owner using ldp.exe’s Sid Lookup functionality (accessible via utilities menu)

———–
***Calling SidLookup…
MAWEERAS2\mw [S-1-5-21-194226691-3252264409-2149212596-1109]
———–

mw@maweeras2.lab is indeed the user that registered the device. 🙂

If you want to view the fiddler trace yourself you can get it from here.