fmeum / WearAuthn

Use your Wear OS watch as a FIDO2 security key via Bluetooth and NFC.
https://play.google.com/store/apps/details?id=me.henneke.wearauthn.authenticator
MIT License
183 stars 7 forks source link

Is it compatible with Microsoft? (Spec UserVerification==Required) #5

Closed kyriakopoulosd closed 4 years ago

kyriakopoulosd commented 4 years ago

Hi @FabianHenneke ! I'm currently waiting for my Wear OS watch to come and after checking your code I'd like to ask you a question. Does your app support the case where the server responds back to the authenticator with UserVerification option --> ### Required? So it isgoing to be functional in this case with a Microsoft account (which supports FIDO2 Strong Authentication)? How (and where) do you handle this case in your code?

fmeum commented 4 years ago

Yes, WearAuthn has full support for user verification and resident keys. It is Microsoft compatible and I have successfully used it as a single factor on live.com. It does also support the hmac-secret extension, but for some unknown reason cannot be used for AAD offline logins at the moment.

Due to the lack of biometrics on watches, WearAuthn considers the user to be verified if they have confirmed their screen lock within the last five minutes. This is tracked via a KeyStore key with userAuthenticationRequired set to true. Most of the relevant code is in https://github.com/FabianHenneke/WearAuthn/tree/master/authenticator/src/main/java/me/henneke/wearauthn/fido/context/AuthenticatorContext.kt.

kyriakopoulosd commented 4 years ago

@FabianHenneke thanks for the reply ! I have one more question! So WearAuthn isn't compatible to use with Microsoft Azure Active directory as fido2 key? You can find on the link below about the features that are needed to be supported by the key, in order the security key be fido2 compatible with Microsoft's Azure Active Directory : https://docs.microsoft.com/bs-latn-ba/azure/active-directory/authentication/concept-authentication-passwordless#fido2-security-keys

kyriakopoulosd commented 4 years ago

It mentions the features : -resident key -client pin -hmac secret -multiple accounts per rp

fmeum commented 4 years ago

WearAuthn has all these features (except for client pin, but at least on paper this is not necessary if the authenticator supports internal user verification). But last time I checked, AAD just gave a non-descriptive error message after I registered the key with it. This may be due to some bug in WearAuthn I haven't found or due to it not being on some whitelist. If you find the time to try it out, please let me know how it went.

kyriakopoulosd commented 4 years ago

I just tried it and found the following info that might be helpful.

First of all I tried, WearAuthn with my personal microsoft account. It seems to be working . --Scenario : Personal Microsoft Account-- The steps I followed were : 1.Open on my win10 laptop v.1909 chrome 2.visit outlook.com and log in my ms account 3.on sign in methods I choose set up security key 4.The Browser prompts to use security key 5.I'm forwarded to Microsoft's Page to enter a Name for my security key. 6.I enter security key name, click ok and everything is working !

After that, I tried with AAD Account, where something wrong. The steps that I followed here were :

1.Open on my win10 laptop v.1909 chrome 2.visit my microsoft ad portal and log in my account 3.on sign in methods I choose set up security key 4.The Browser prompts to use my security key 5.I'm forwarded to a Page to enter a Name for my security key. 6.I enter security key name, pressing ok and BOOM , it did NOT work.

What I found here (and currently I did not find any documentation on the web about it) was :

On the screen that Microsoft AAD prompt asks to enter a name for the security key (step 6), when entering a KeyName and clicking "Next" it executes a POST Request named VerifySecurityInfo with the following request payload :

{"Type":12,"VerificationData":"{\"Name\":\"theKeyNameSubmittedviaUI\",\"Canary\":\"xxxxxx\",\"AttestationObject\":\"xxxxxxxx\",\"ClientDataJson\":\"xxxxxxxx\",\"CredentialId\":\"xxxxxxxx\",\"ClientExtensionResults\":\"xxxxxxxx\",\"PostInfo\":\"\"}"}

(where xxx there were long strings generated)

So, the response from the POST Request that is being returned when using WearAuthn as a security key is :
)]}', {"Type":12,"VerificationState":3,"DataUpdates":null,"ErrorCode":4}

Being curious about what goes wrong, I tried the same process with a physical security key to check what a response should look like in that case :

Again the same POST Request is being executed on that step with a request payload with previous format and the response was different that time :

)]}',
{"Type":12,"VerificationState":2,"DataUpdates":{"FidoDevices":{"CredentialId":"thenameKeyIsubmittedviaUI","DisplayName":"mysecurityKeyname","CreationTime":"generatedTimeHere","AaGuid":"00000000-0000-0000-0000-000000000000","isDisabled":false}},"ErrorCode":0}

So, comparing those 2 responses it seems that in the first case (WearAuthn) , I get VerificationState ->3 and DataUpdates object null instead of the second case where VerificationState -> 2 and DataUpdates includes data about the key (and obviously errorcode here is set to 0).

I understand that this is a mechanism by Microsoft to some additional Security Check (for example the AAD Administrator has the privilege to enforce fido2 Key Restrictions for specific AAGUIDs (you can find out here more : https://www.petervanderwoude.nl/post/configure-fido2-security-key-restrictions/) but in my case, I dont have enabled this option.I suppose it doesnt have to do with that because I dont have this option enabled, so any AAGUID can be used.)

I'm going to investigate it more, if you have any progress or need additional info to troubleshoot this, please let me know.

fmeum commented 4 years ago

Thank you very much for digging that deep! When I tried this with an AAD test account, I hit the exact same problem you are describing, even when I manually added WearAuthn AAGUID to the list. I did not notice the POST request, which does indeed strongly hint at a whitelist.

Unfortunately, I do not have access to an AAD account anymore. After my initial test, I had already been in contact with Microsoft regarding the error, but they (understandably) made it clear that they would prioritize supporting more established security keys.

kyriakopoulosd commented 4 years ago

At a first glance I thought as you said that it would be something with the AAGUID.

However I've tested it on AAD without Enforce Attestation being enabled (which feature is supposed to require checking the device AAGUID and other things) and the problem still remains.

To be more specific, I still also see the prompt from Chrome that requires to give it an "Allow" --> " login.microsoft.com wants to see the make and the model of your security key". With Enforce Attestation feature disabled on AAD, as I've read this shouldn't happen.

Also, I would like to mention that all this process on AAD is being done via NFC. Bluetooth Security Keys are not allowed at the moment on Microsoft's AAD and it did not work for me to pair with Bluetooth.

-----------However, I found something that may cause the problem on AAD :

I tried the debugger for fido2 registration on : https://webauthn.me/debugger.

What I tried to do, was to register the Watch with attestation field set to "direct". First via NFC and secondly via Bluetooth.

Surprisingly, via NFC the "fmt" inside attestationObject is mentioned as "packed" and the "attStmt" includes only 2 fields which are "alg" and "sig".

When I registered via Bluetooth, the "fmt" inside attestationObject is mentioned (correctly now) as "android-key" and includes 3 fields which are alg, sig and x5c.

So after reading all these, I think there might be a bug -on the code of WearAuthN in NFC and -secondly probably a Microsoft Problem which requires the Attestation everytime

@FabianHenneke can you check what do you take as a response in the case of choosing the NFC protocol?

kyriakopoulosd commented 4 years ago

one more update-clue

When trying to set-up WearAuthN as fido2 security key for PERSONAL MICROSOFT ACCOUNT, after recognizing the key, the browser will ask you via a prompt "login.microsoft.com wants to see the make and the model of your security key". If you deny, the process doesn't abort!!! It continues. That means you can name then your key, save it successfully and use it even if no attestation data actually provided (by declining the prompt the browser gets no attestation data from Authenticator). So here it is clear to me that microsoft doesnt care/check about attestation data at this point (I can understand that it doesnt store/check AAGUID here even if the browser prompts to allow or not).

Instead, on Microsoft AAD if you deny the dialog of providing the Security Key Name and Model info, you are unable to continue because no attestation data have been passed. For example, I tried to set up a yubikey, I denied the specific prompt of allowing to provide Security Key and Model info and I was not able to save it. All the work again is being done by the same POST Request (mentioned in my previous reply) that Microsoft calls when you give a name your key and hit OK.

So from my point of view, attestionObject is the issue where the user is not able to successfully register wearauthn as security key in AAD.

fmeum commented 4 years ago

To be more specific, I still also see the prompt from Chrome that requires to give it an "Allow" --> " login.microsoft.com wants to see the make and the model of your security key". With Enforce Attestation feature disabled on AAD, as I've read this shouldn't happen.

I suspect that Microsoft uses attestation twice: Once to detect supported authenticators based on a whitelist and second to allow the admin to limit the AAGUID to a particular list. WearAuthn may already fail the first step.

Also, I would like to mention that all this process on AAD is being done via NFC. Bluetooth Security Keys are not allowed at the moment on Microsoft's AAD and it did not work for me to pair with Bluetooth.

Note that WearAuthn is not actually a Bluetooth/BLE security key, rather it emulates a USB (more precisely: CTAPHID) security key via Bluetooth HID. For any browser using the Windows WebAuthn API, WearAuthn in Bluetooth mode should be indistinguishable from a USB security key (unless of course attestation is involved).

Surprisingly, via NFC the "fmt" inside attestationObject is mentioned as "packed" and the "attStmt" includes only 2 fields which are "alg" and "sig".

When I registered via Bluetooth, the "fmt" inside attestationObject is mentioned (correctly now) as "android-key" and includes 3 fields which are alg, sig and x5c.

I agree this is weird, but it's actually a feature: Generating KeyStore keys on watches is rather slow (500-1000 ms). While this is not an issue if WearAuthn is used via Bluetooth, it would make registration error-prone over NFC.  To prevent this, WearAuthn always keeps a pregenerated KeyStore key around that is used for NFC registrations and refreshed after every registration. This has the downside of not being compatible with the Android KeyStore attestation scheme, hence WearAuthn falls back to standard self-attestation in this case, which is what you are seeing.  If you request any of the FIDO2 features such as user verification or resident key during the registration, WearAuthn will always generate a fresh key with KeyStore attestation even over NFC. I hope this makes sense, let me know if you have any questions!

All the work again is being done by the same POST Request (mentioned in my previous reply) that Microsoft calls when you give a name your key and hit OK.

It would be interesting to see what happens if one changes the response to the POST request with a proxy. It is surprising to me that these checks are done client-side.

kyriakopoulosd commented 4 years ago

Im currently checking to find out and clarify the exact point where we get the error. I think that I've found the problem. After using the "verify android keystore" script (found on https://medium.com/@herrjemand/webauthn-fido2-verifying-android-keystore-attestation-4a8835b33e9d) with the attestation object that is being generated I get the following error : "Error: Attestation root is not invalid!" @FabianHenneke can you check the script and what response it produces for your attestation object?

fmeum commented 4 years ago

If it hasn't been fixed since, the script you linked to uses an incorrect root certificate, see https://gist.github.com/herrjemand/a612608dfbb2bc136aba57c64ff4a04c#gistcomment-2812359 I will give it a try nonetheless and report back with the result.

kyriakopoulosd commented 4 years ago

@FabianHenneke Thanks for the instant response!You're right, this script had the incorrect certificate..I copied the Root Certificate from https://developer.android.com/training/articles/security-key-attestation#root_certificate and now it matches.. However, I get another error now running the script. I'll troubleshoot this and come back with an update.

kyriakopoulosd commented 4 years ago

Well, this script (https://gist.github.com/herrjemand/c5a84de5c04ef41b3ac7fd12d0cbceae#gistcomment-3214024) keeps crashing because of @lapo/asn1js that is being used, for some reason so I'm not able to verify the attestation certificate at the moment. Please let me know if you managed to run it.

@FabianHenneke I also just found out one more clue that made me thinking if it is the AAD who really causes the problem with wearAuthn.

I tried and tested Google's Virtual Authenticator Chrome Extension (https://chrome.google.com/webstore/detail/virtual-authenticators-ta/gafbpmlmeiikmhkhiapjlfjgdioafmja) to check if I am able to register a virtually fido2 key in AAD.

What I found was that AAD accepts those fido2 keys, so that makes me thinking if AAD really applies or not a whitelist for selected AAGUIDs (and manufacturers of course) or another specs of the security key that is being saved in

kyriakopoulosd commented 4 years ago

@FabianHenneke I managed to reveal all the infomation behind google's pem files that are being generated, using Google's Android keystore Attestation sample (https://github.com/google/android-key-attestation/tree/master/server) . The root cerificates seems correct but for some reason fields such as "Trusted User Presence Required,Trusted Confirmation Required,Unlocked Device Required" are set to FALSE. Does this make sense ? Because when in authData I found out that UV (user verification) and UP (user presence) are set to TRUE. Do you know if I have to check something else/more? Below I attach my log :

The root certificate is correct, so this attestation is trustworthy, as long as none of the certificates in the chain have been revoked. A production-level system should check the certificate revocation lists using the distribution points that are listed in the intermediate and root certificates. Attestation version: 3 Attestation Security Level: TRUSTED_ENVIRONMENT Keymaster Version: 4 Keymaster Security Level: TRUSTED_ENVIRONMENT Attestation Challenge: .{?-F?&??????%[???6??;???Q Unique ID: [] <-- it was empty!!! Software Enforced Authorization List: Rollback Resistance: false Active DateTime: 2020-03-14T19:06:37.761Z No Auth Required: false Allow While On Body: false Trusted User Presence Required: false Trusted Confirmation Required: false Unlocked Device Required: false All Applications: false Creation DateTime: 2020-03-15T19:06:37.771Z Rollback Resistant: false Attestation Application ID: Package Infos (, ): androidpackagehere, 1 Signature Digests: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Attestation Application ID Bytes: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx TEE Enforced Authorization List: Purpose(s): [2] Algorithm: 3 Key Size: 256 Digest: [4] EC Curve: 1 Rollback Resistance: false No Auth Required: true Allow While On Body: false Trusted User Presence Required: false Trusted Confirmation Required: false Unlocked Device Required: false All Applications: false Origin: 0 Rollback Resistant: false Root Of Trust: Verified Boot Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Device Locked: true Verified Boot State: VERIFIED Verified Boot Hash: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx OS Version: 90000 OS Patch Level: 201911 Vendor Patch Level: 0 Boot Patch Level: 0

fmeum commented 4 years ago

These features are all KeyStore features and are not directly related to UP and UV in the sense of CTAP2/WebAuthn. It would be nice if these could be used, but Trusted Confirmation/Trusted User Presence are afaik only available on certain Pixel handsets. Unlocked Device Required is available as of API level 28 and should be used by WearAuthn for resident keys if possible.

With the information you have collected I find it most likely that Microsoft does not support self-attestation and Android KeyStore attestation. Most other keys, including the virtual authenticator, will probably use batch attestation, although the latter would need to be confirmed. If this turns out to be the case, I may switch to batch attestation in a future release.

kyriakopoulosd commented 4 years ago

@FabianHenneke based on these results, self attestation probably is disabled/not accepted on AAD at the moment.

I also tried pyWebAuthN (https://github.com/duo-labs/py_webauthn) for some experiments.. pyWebAuthN gives you the opportuntity to register fido2 with the following attestation status : 1.none 2.self attestation 3.trusted_root_certificate

With None and Self_attestation set to TRUE I was able to register sucessfully WearAuthN via NFC. With those 2 (none,self_attestation) set to FALSE and the 3.trusted_root_certificate set to TRUE I was not able to register wearAuthN via NFC even if I had added on the directory of trusted root certificates Google's PEM.

**To be more specific the prompt "Tap or insert your security key" on this case never left the screen**

So, what I tried to do next was to register on py_webauthn a Physical Security Key (from known vendor), with trusted_root_certificate enabled (& self_attestation disabled) but without its pem to be included on the trusted_root_certificate directory. The result on the console log on this case was to see the following :

"Server validation of credential failed: Registration failed. Error: Registration rejected. Error: Untrusted attestation certificate.."

So what I see here, is that when security key is not trusted, console logs the following message. So, I can think of 2 cases why WearAuthN didn't have similar response to this. Either fmt: android-key is not supported or something is missing probably in the communication via wearAuthN's NFC implementation. And why am I mentioning this? After seeing, that the "Insert/Tap your security key" prompt for fido2 never left the screen in the case of WearAuthN, I built the project on android studio and checked the logs while trying to register via NFC.

Here @FabianHenneke i'm going to need your help. I added on NFCAuthenticatorService inside processCommandApdu after launch (https://github.com/FabianHenneke/WearAuthn/blob/25aee91503efbfa394822ffe8fac4fbf4bfd7e71/authenticator/src/main/java/me/henneke/wearauthn/fido/nfc/NfcAuthenticatorService.kt#L86) to log everything that is being received with the following commands :

System.out.println("CommandApdu: "+commandApdu);
System.out.println("CommandApdu Hex to Bytes"+Hex.bytesToStringUppercase(commandApdu.asByteArray().sliceArray(0..3)));

On first execution via NFC I got the following logs :

I/System.out: CommandApdu: UByteArray(storage=[-128, 16, 0, 0, 1, 4, 0]) I/System.out: CommandApdu Hex to Bytes80100000 I/Ctap2Authenticator: GetInfo called I/Keystore: User verification state is: true I/System.out: CborLongMap(value={1=CborArray(value=[CborTextString(value=FIDO_2_0), CborTextString(value=U2F_V2)]), 2=CborArray(value=[CborTextString(value=hmac-secret), CborTextString(value=exts), CborTextString(value=uvm)]), 3=CborByteString(value=[43, 33, 49, -90, -119, 1, 77, 45, -114, 119, -23, -112, -90, 43, -3, 65]), 4=CborTextStringMap(value={plat=CborBoolean(value=false), rk=CborBoolean(value=true), up=CborBoolean(value=true), uv=CborBoolean(value=true)}), 5=CborLong(value=4096), 7=CborLong(value=5), 8=CborLong(value=257)}) I/System.out: CommandApdu: UByteArray(storage=[-112, 16, 0, 0, -16, 1, -91, 1, 88, ... big array here...]) I/System.out: CommandApdu Hex to Bytes90100000 I/System.out: CommandApdu: UByteArray(storage=[-128, 16, 0, 0, 8, 101, 121, 7, -95, 98, 117, 118, -11, 0]) I/System.out: CommandApdu Hex to Bytes80100000 I/Ctap2Authenticator: MakeCredential called I/Keystore: User verification state is: true I/Keystore: User verification state is: true W/KeyStore: get() : not found key : CACERT_oCEkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx W/KeyStore: get() : not found key : CACERT_oCEkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx I/System.out: CommandApdu: UByteArray(storage=[-128, -64, 0, 0, 62]) I/System.out: CommandApdu Hex to Bytes80C00000 I/System.out: CommandApdu: UByteArray(storage=[-128, 18, 1, 0, 0]) I/System.out: CommandApdu Hex to Bytes80120100 E/NfcAuthenticatorService: Unable to handle APDU with header 80120100; returned INS_NOT_SUPPORTED V/Vibrator: Called cancel() API - PUID: 10256, PackageName: me.henneke.nfctestonlyfido2, token: android.os.Binder@472b655 V/Vibrator: Called cancel() API - PUID: 10256, PackageName: me.henneke.nfctestonlyfido2, token: android.os.Binder@472b655

The Log on the browser this time showed :

Server validation of credential failed: Registration failed. Error: Registration rejected. Error: Self attestation is not permitted..

On a second execution/try again via NFC the the prompt "Tap or insert your security key" never left the screen and wearAuthn got into infinite loops!!!

I/System.out: CommandApdu: UByteArray(storage=[-128, 16, 0, 0, 1, 4, 0]) I/System.out: CommandApdu Hex to Bytes80100000 I/Ctap2Authenticator: GetInfo called I/Keystore: User verification state is: true I/System.out: CborLongMap(value={1=CborArray(value=[CborTextString(value=FIDO_2_0), CborTextString(value=U2F_V2)]), 2=CborArray(value=[CborTextString(value=hmac-secret), CborTextString(value=exts), CborTextString(value=uvm)]), 3=CborByteString(value=[43, 33, 49, -90, -119, 1, 77, 45, -114, 119, -23, -112, -90, 43, -3, 65]), 4=CborTextStringMap(value={plat=CborBoolean(value=false), rk=CborBoolean(value=true), up=CborBoolean(value=true), uv=CborBoolean(value=true)}), 5=CborLong(value=4096), 7=CborLong(value=5), 8=CborLong(value=257)}) I/System.out: CommandApdu: UByteArray(storage=[-112, 16, 0, 0, -16, 1, -91, 1, long array here]) I/System.out: CommandApdu Hex to Bytes90100000 I/System.out: CommandApdu: UByteArray(storage=[-128, 16, 0, 0, 8, 101, 121, 7, -95, 98, 117, 118, -11, 0]) I/System.out: CommandApdu Hex to Bytes80100000 I/Ctap2Authenticator: MakeCredential called I/Keystore: User verification state is: true V/Vibrator: Called cancel() API - PUID: 10256, PackageName: me.henneke.nfctestonlyfido2, token: android.os.Binder@d7d40d3 I/System.out: CommandApdu: UByteArray(storage=[-112, 16, 0, 0, -16, 1, -91, 1, 88, 32, 14, 33, -5, long array here again]) I/System.out: CommandApdu Hex to Bytes90100000 I/System.out: CommandApdu: UByteArray(storage=[-128, 16, 0, 0, 8, 101, 121, 7, -95, 98, 117, 118, -11, 0]) I/System.out: CommandApdu Hex to Bytes80100000 I/Ctap2Authenticator: MakeCredential called I/Keystore: User verification state is: true I/System.out: CommandApdu: UByteArray(storage=[-112, 16, 0, 0, -16, 1, -91, 1, 88, 32, 14, 33, -5, long array here again]) I/System.out: CommandApdu Hex to Bytes90100000 I/System.out: CommandApdu: UByteArray(storage=[-128, 16, 0, 0, 8, 101, 121, 7, -95, 98, 117, 118, -11, 0]) I/System.out: CommandApdu Hex to Bytes80100000 I/Ctap2Authenticator: MakeCredential called I/Keystore: User verification state is: true I/System.out: CommandApdu: UByteArray(storage=[-112, 16, 0, 0, -16, 1, -91, 1, 88, 32, 14, 33, -5, long array here]) I/System.out: CommandApdu Hex to Bytes90100000 I/System.out: CommandApdu: UByteArray(storage=[-128, 16, 0, 0, 8, 101, 121, 7, -95, 98, 117, 118, -11, 0]) I/System.out: CommandApdu Hex to Bytes80100000 I/Ctap2Authenticator: MakeCredential called I/Keystore: User verification state is: true I/System.out: CommandApdu: UByteArray(storage=[-112, 16, 0, 0, -16, 1, -91, 1, 88, 32, 14, 33, -5, long array here again]) I/System.out: CommandApdu Hex to Bytes90100000 I/System.out: CommandApdu: UByteArray(storage=[-128, 16, 0, 0, 8, 101, 121, 7, -95, 98, 117, 118, -11, 0])

LOOP DETECTED!and goes on and on until I removed wearauthn from nfc reader so it crashes!!!

*So to sum up I think because of WearAuthn's implementation specific on NFC communication, we also had that result on webauthn.me the previous days, where with attestation option set to direct, the result with NFC was fmt: packed without any x5c in contrast with the registration via Bluetooth where it returned fmt : android-key with x5c in attStmt.

kyriakopoulosd commented 4 years ago

I agree this is weird, but it's actually a feature: Generating KeyStore keys on watches is rather slow (500-1000 ms). While this is not an issue if WearAuthn is used via Bluetooth, it would make registration error-prone over NFC.  To prevent this, WearAuthn always keeps a pregenerated KeyStore key around that is used for NFC registrations and refreshed after every registration. This has the downside of not being compatible with the Android KeyStore attestation scheme, hence WearAuthn falls back to standard self-attestation in this case, which is what you are seeing.  If you request any of the FIDO2 features such as user verification or resident key during the registration, WearAuthn will always generate a fresh key with KeyStore attestation even over NFC. I hope this makes sense, let me know if you have any questions!

So by the time Microsoft acquires during registration for resident key, WearAuthN is going to "give up" self attestation and go for Keystore Attestation. @FabianHenneke this is something because of fido2 spec or some other reason? [This is what we call enforce attestation?]

In addition, please correct me if Im wrong but WearAuthN at the moment doesnt check anywhere in the code from the response from Server about attestation value.. I mean if it is none,indirect or direct..

fmeum commented 4 years ago

So by the time Microsoft acquires during registration for resident key, WearAuthN is going to "give up" self attestation and go for Keystore Attestation. @FabianHenneke this is something because of fido2 spec or some other reason? [This is what we call enforce attestation?]

This is correct, Microsoft's requests for a resident key will always be answered with KeyStore attestation. This is not required anywhere, I just thought that since resident keys are more sensitive (they may be single factors), they should be provided with the strongest kind of attestation available. Since self attestation makes no cryptographic claim other than possession of the key material, it is as good as no attestation at all. KeyStore attestation provides proof that the key material is as well protected as e.g. Google Pay key material. But if it makes WearAuthn incompatible with AAD, I could of course change the mode of attestation since nobody seems to verify it anyway.

In addition, please correct me if Im wrong but WearAuthN at the moment doesnt check anywhere in the code from the response from Server about attestation value.. I mean if it is none,indirect or direct..

This is because it can't - the authenticator is always expected to return full attestation information. Then it is up to the user agent to forward this info to the server or mask it, based on the server's request parameters and the user's choice.

kyriakopoulosd commented 4 years ago

Ok now its more clear to me. So, when a server responds with attestation set to none, this is what refers that the server accepts self attestation? So when it's response is set to direct, actually means that self attestation is not accepted.

fmeum commented 4 years ago

Ok now its more clear to me. So, when a server responds with attestation set to none, this is what refers that the server accepts self attestation? So when it's response is set to direct, actually means that self attestation is not accepted.

Actually, the server has no real say in this: https://www.w3.org/TR/webauthn/#credentialcreationdata-attestationconveyancepreferenceoption Either the client forwards the attestation of the authenticator unchanged or it masks it in some ways, but this is all that is influenced by requesting none/direct/indirect.

I just learned from reviewing this that self attestation seems to require that the AAGUID is zero. I will fix this in a future release, but it should not be relevant to the present AAD issue since the response there relies on KeyStore attestation.

kyriakopoulosd commented 4 years ago

Actually, the server has no real say in this: https://www.w3.org/TR/webauthn/#credentialcreationdata-attestationconveyancepreferenceoption Either the client forwards the attestation of the authenticator unchanged or it masks it in some ways, but this is all that is influenced by requesting none/direct/indirect.

Ok, I made some test on webauthn.me and found out that when none is sent, client forwards to server 0000000 as AAGUID. In case of direct, it forwards the original AAGUID and all the added stuff inside fmt and attSmtm. In case of indirect, if user chooses accept the original AAGUID is being passed.If no, AAGUID to server are zeros... So actually when on create() is taking place where servers responds to Client with PublicKeyCredentialOptions, if attention field is set by server to none or indirect, only then self attestation is allowed and no check is being done by the server for the attestation, right?

I just learned from reviewing this that self attestation seems to require that the AAGUID is zero. I will fix this in a future release, but it should not be relevant to the present AAD issue since the response there relies on KeyStore attestation.

Yes, I think currently that this is not the problem with the AAD. I've opened a ticket to review this and I'll post whats the progress when I have news.

Until then, after reading and trying to understand the flow of the code, I'd appreciate if you can help me with the following :

1a. In case of NFC, what is the flow of registration? GetInfo -> MakeCredential -> ? 1b. Is it possible of MakeCredential to be called twice or more due to a registration? 1c. How does it terminate after the MakeCredential has returned? Does it send/receive specific code?So The Activity exits and doesnt exchange nfc data anymore?

2.When activating Single Sign In Feature, updateUserVerificationPreferencesState is being executed which prompts a Dialog with Yes/No. On Yes,ConfirmDeviceCredentialActivity takes place and if the users confirms then armUserVerificationFuse(context) is being executed. If you would like to have enabled bydefault (e.g. from launching the app) the feature of Single Sign In Feature, could it be enough to execute armUserVerificationFuse onResume? Because Im thinking here that we add 2 steps to the user in order to activate the Single Sign in option (First to choose Yes, Secondly to input his ScreenLock pattern/biometric even if device is actually unlocked). If the user is using the app (so device is unlocked) I don't find any practical-security purpose for requiring via prompting ConfirmDeviceActivity to put his unlock pattern for the screen by the time that the device is unlocked.Is it possible someway to avoid this?

3.Is there kept on the app any list or log of the registered accounts ? both with self attestation and android keystore.

*If you had any update/progress with the verifying script with android key attestation, please let me know!

kyriakopoulosd commented 4 years ago

@FabianHenneke could you might check the issues mentioned on my previous message?

fmeum commented 4 years ago

So actually when on create() is taking place where servers responds to Client with PublicKeyCredentialOptions, if attention field is set by server to none or indirect, only then self attestation is allowed and no check is being done by the server for the attestation, right?

Almost. Self-attestation is allowed when the server requests "direct" attestation, it's just that the server might then decide to not accept the authenticator's registration, but this is not part of the WebAuthn registration ceremony.

Yes, I think currently that this is not the problem with the AAD. I've opened a ticket to review this and I'll post whats the progress when I have news.

Thanks a lot! Do you have a link to the ticket?

1a. In case of NFC, what is the flow of registration? GetInfo -> MakeCredential -> ?

It depends whether your client speaks CTAP2 or U2F via NFC. In the first case, it should simply be GetInfo followed by MakeCredential, in the latter you would of course not see any CTAP2 requests at all. Note though that e.g. Chrome will split the excludeList for MakeCredential and check it via silent GetAssertion calls, so the very simple GetInfo -> MakeCredential flow for registration as per spec is only valid in theory.

1b. Is it possible of MakeCredential to be called twice or more due to a registration?

This should not happen simple because MakeCredential always collects a touch from the user. Multiple required touches would confuse the user.

1c. How does it terminate after the MakeCredential has returned? Does it send/receive specific code?So The Activity exits and doesnt exchange nfc data anymore?

NFC on Android is transaction-based: Whenever the Android system receives an applet selection command via NFC that matches your registered AIDs, it will call your HostApduService's processCommandApdu with the selection command and you are given the chance to reply with a byte array. Until the watch is removed from the reader, processCommandApdu will continue to be called when a new APDU is received and the response returned from it will be sent back to the reader. When the reader disconnects, onDeactivated is called, which is used by WearAuthn to show a message, cancel the vibration and reset timeouts. Since all of this is implemented in a service, there is no need to finish an activity, the entire lifecycle is handled by the system.

2.When activating Single Sign In Feature, updateUserVerificationPreferencesState is being executed which prompts a Dialog with Yes/No. On Yes,ConfirmDeviceCredentialActivity takes place and if the users confirms then armUserVerificationFuse(context) is being executed. If you would like to have enabled bydefault (e.g. from launching the app) the feature of Single Sign In Feature, could it be enough to execute armUserVerificationFuse onResume? Because Im thinking here that we add 2 steps to the user in order to activate the Single Sign in option (First to choose Yes, Secondly to input his ScreenLock pattern/biometric even if device is actually unlocked). If the user is using the app (so device is unlocked) I don't find any practical-security purpose for requiring via prompting ConfirmDeviceActivity to put his unlock pattern for the screen by the time that the device is unlocked.Is it possible someway to avoid this?

This is necessary for usability reasons. As soon as the user activates the fuse, they will need to reconfirm their screen lock on any MakeCredential call to unlock the Android KeyStore key that realizes the fuse. Note that this confirmation is only cached for five minutes, even when the watch itself remains unlocked. Furthermore, the fuse is burned when the user disabled their screen lock and can not be reenabled without resetting the app. This is to ensure that user verification cannot be reenabled by someone who obtains your watch after you have disabled the screen lock.

Because of all these usability restrictions and since armUserVerificationFuse itself requires an unlocked KeyStore key, I have added the prompt.

You may ask why I even require user verification for the KeyStore key and not simply allow using it while the device is unlocked. This has multiple reasons:

3.Is there kept on the app any list or log of the registered accounts ? both with self attestation and android keystore.

WearAuthn is designed such that pure second-factor credentials leave no metadata on the device apart from a random ID value. The association with a certain RP is made via a signed key handle handed to the RP, so without that, no one can confirm that you are registered at a specific RP without obtaining that key handle.

Single-factor credentials (which always use KeyStore attestation) by design require storing the RP. The list can be accessed starting with version 0.9.10 of the app, which is currently in internal testing. If you want to give it a try, send me the Google account you are using on your watch (to wearauthn@henneke.me) and I will invite you to the internal test.

*If you had any update/progress with the verifying script with android key attestation, please let me know!

I have tried to get the script to work, but have failed to provide the correct input format for the attestation. The package issue can be resolved by changing the require to asn1js, I believe.

kyriakopoulosd commented 4 years ago

@FabianHenneke Thanks you so much for your detailed answer! I got in touch with Microsoft, providing them the Correlation ID of the error that occured on the AAD with some extra info that I discovered but unfortunately they weren't able to troubleshoot this as long this feature is in preview mode and not all the engineers have 360 view of the feature, how technically works🙄 It's so dissapointing to have done so much work and for that little extra step, don't have the result. However, I'll try again with a contact I have in Microsoft, to see if I can get some help from there.

Let me get back to this topic, with some extra questions:

This is necessary for usability reasons. As soon as the user activates the fuse, they will need to reconfirm their screen lock on any MakeCredential call to unlock the Android KeyStore key that realizes the fuse. Note that this confirmation is only cached for five minutes, even when the watch itself remains unlocked

Is it possible (& how) to adjust the five minutes to --> x minutes?

Until Microsoft get's back with a response, would it be possible to have a second version of WearAuthN implementing the "packed" fmt instead of android-keystore? So to verify that either is a whitelist of AAGUIDs or an fmt-type restriction causing the error on the AAD...

fmeum commented 4 years ago

I have also been in touch with Microsoft and can now confirm that switching to batch attestation resolves the issue with AAD registration. I may be able to test the offline Windows 10 login feature in the upcoming days as well.

I will prepare an update that switches to batch attestation and push it out (it will be version 0.9.13).

Is it possible (& how) to adjust the five minutes to --> x minutes?

You simply have to change the value of USER_VERIFICATION_TIMEOUT_S in Keystore.kt.

kyriakopoulosd commented 4 years ago

I have also been in touch with Microsoft and can now confirm that switching to batch attestation resolves the issue with AAD registration. I may be able to test the offline Windows 10 login feature in the upcoming days as well.

I will prepare an update that switches to batch attestation and push it out (it will be version 0.9.13).

That's awesome news! If you would like i could help you testing the new batch attestation on AAD by the time I have account there. If you have some beta code or something like this and would like to test it, let me know :)

Is it possible (& how) to adjust the five minutes to --> x minutes?

You simply have to change the value of USER_VERIFICATION_TIMEOUT_S in Keystore.kt.

Nice thanks!

fmeum commented 4 years ago

That's awesome news! If you would like i could help you testing the new batch attestation on AAD by the time I have account there. If you have some beta code or something like this and would like to test it, let me know :)

You can request to join the WearAuthn Google Group and then, once I have added you as a member, use this invite link to join the alpha.

fmeum commented 4 years ago

@kyriakopoulosd Version 0.9.13 is rolling out to the Alpha channel now with batch attestation enabled by default. Please give it a try and see how far you get!

kyriakopoulosd commented 4 years ago

@FabianHenneke thanks! I'm waiting due to covid19 restrictions in my area, to get my watch back from my cousin that I had borrowed to him. By the time I get it back, I'll join the Group so to test WearAuthn new version. Until then, do you have pushed your new code/update here on github? So I can give it a look ?

fmeum commented 4 years ago

The current Alpha version is precisely what's on master here on GitHub. The commit with the switch to batch/basic attestation is here: https://github.com/FabianHenneke/WearAuthn/commit/7dfeea6aa948c81483e39a83182d56b1694129ab.

fmeum commented 4 years ago

AAD support is now included in the latest beta version 0.9.16. Thank you very much for your help and efforts in getting this issue resolved! If you should encounter any new bugs, please open another issue.