GithubHelp home page GithubHelp logo

Wrongly enforces getAssertion credential (0x01) member presence in the authenticator response, which is optional in FIDO2 about authenticator-rs HOT 10 CLOSED

xchapron-ledger avatar xchapron-ledger commented on June 24, 2024
Wrongly enforces getAssertion credential (0x01) member presence in the authenticator response, which is optional in FIDO2

from authenticator-rs.

Comments (10)

msirringhaus avatar msirringhaus commented on June 24, 2024

I haven't disassembled the responses from your ledger, so I can't give a full breakdown of what happened. See my answer to your question 2, so we can get a more detailed log.

But one step or rather one question at a time:

  1. Using this tracking-bug https://bugzilla.mozilla.org/show_bug.cgi?id=1828974 you should be able to find which version was going into which milestone.
  2. You can start Firefox from the commandline with RUST_LOG=authenticator=debug to get the logs for auth-rs.
  3. "make.me.blink"-requests are sent in two scenarios: First, if multiple devices are plugged in and the user has to select which to use. For this, we make all devices blink and let the user touch the one that should be used. Second, in cases where a register() call was made, but the credential was already registered previously. The spec mandates that the device has to blink anyways, even if we have the opportunity to determine this without user interaction. Or a sign() call was made, and an allow-list was provided that contained no valid credential. Again, we have to blink anyways and collect a user interaction. If the call succeeds or fails with e.g. 'no pin set' should make no difference here.
  4. Not really relevant, see 3.
  5. There is only one implementation of authenticator-rs, the only OS-dependent part of the code is how to discover and interact with the raw USB-devices, which obviously differs for each OS. The business-logic is the same for all. However on newer Windows-machines "Windows Hello" is used instead of authenticator-rs. And I think the same is true for MacOS. But given that your logs show the "make.me.blink"-request, it's pretty obvious that in your case auth-rs is used. So, I'm also not sure what the difference is. Hopefully more detailed logs will help.

Hope that helps!

from authenticator-rs.

xchapron-ledger avatar xchapron-ledger commented on June 24, 2024

Hello @msirringhaus ,
First thanks for your help!

1/

Using this tracking-bug https://bugzilla.mozilla.org/show_bug.cgi?id=1828974 you should be able to find which version was going into which milestone.

If I get it correctly, this shows that v0.4.0-alpha.22 is included in firefox119 while this show that v0.4.0-alpha.23 will be included in firefox120?

2/

You can start Firefox from the commandline with RUST_LOG=authenticator=debug to get the logs for auth-rs.

I gave it a try with both export RUST_LOG=authenticator=debug and then launching Firefox with /Applications/Firefox.app/Contents/MacOS/firefox but I didn't see any additional logging, even in the developer console. I'm sorry I have never debugged anything on Firefox and or Mac, and will therefore require a bit more indication here :/ Maybe I need a Firefox debug build? Or I should look somewhere else for logs?

3/

"make.me.blink"-requests are sent in two scenarios: First, if multiple devices are plugged in and the user has to select which to use. For this, we make all devices blink and let the user touch the one that should be used.

I was wondering how other browser do that, and therefore gave it a try on Google Chrome. It appears it sends the request to every authenticator, and once authenticator respond with a success it cancel the other request. I found that more intuitive and maybe more spec compliant, is there any reason not to do that?

Second, in cases where a register() call was made, but the credential was already registered previously. The spec mandates that the device has to blink anyways, even if we have the opportunity to determine this without user interaction.

I'm not sure to understand which part of the spec you are referring? In the FIDO2.1 spec I found this but this specify the behavior of the authenticator which should be done without any "make.me.blink"-requests. Are you referring to another part of the spec, or another spec maybe?

Or a sign() call was made, and an allow-list was provided that contained no valid credential. Again, we have to blink anyways and collect a user interaction.

In both FIDO2.0 and FIDO2.1 spec I can see requirements for authenticators to collect user presence or user verification before responding to a sign call with an allow-list without valid credential, but again, that should be done on authenticator side, without any "make.me.blink"-requests. Are you referring to another part of the spec, or another spec maybe?

Thanks!

Xavier

from authenticator-rs.

msirringhaus avatar msirringhaus commented on June 24, 2024

Hi,
no problem.

\1. Yes, I think thats correct.

\2. Hm, this is weird. I don't have a Mac, so I can't reproduce this. I just asked somebody else and it worked for them (although, AFAIK for released versions the log-levels are capped at "INFO", and "DEBUG" can't be chosen any more). Maybe the problem is the selector for authenticator=. Please try with RUST_LOG=trace /Applications/Firefox\ Beta.app/Contents/MacOS/firefox, although this will print a lot.
On the other hand, you could also just download this repository and run RUST_LOG=debug cargo run --example ctap2. This will cut out the middle-man (Firefox), and make debugging easier.

\3.1.

It appears it sends the request to every authenticator, and once authenticator respond with a success it cancel the other request.

We have to be careful here, as there are multiple different variations, that all have a different outcome. E.g. Chrome checks, if the device also speaks the old CTAP1 protocol and then downgrades the request to that. This is to get around the PIN-stuff. Then it can send the actual request to all devices instead of selection-requests, followed by the actual request. We currently don't do this (and I'm still not 100% convinced we should be). But Chrome does also use dummy requests to select devices in certain cases, see #155 .

\3.2.

In both FIDO2.0 and FIDO2.1 spec I can see requirements for authenticators to collect user presence or user verification before responding to a sign call with an allow-list without valid credential, but again, that should be done on authenticator side, without any "make.me.blink"-requests.

As mentioned Chrome does this, too: https://github.com/chromium/chromium/blob/6aaa00ad13642255e207e1c4893463f31c5ecf68/device/fido/make_credential_task.cc#L126-L156
and
https://github.com/chromium/chromium/blob/6aaa00ad13642255e207e1c4893463f31c5ecf68/device/fido/get_assertion_task.cc#L366-L381

There may be some constellations were we could use the actual request instead of the dummy to make the device fail, but it doesn't really matter what we send, if all we want to do is collect a user-interaction and fail.

As far as I remember, the spec doesn't explicitly mention this, except for the old CTAP1-compatibility section:

If the excludeList is not empty, the platform MUST send signing request with check-only control byte to the CTAP1/U2F authenticator using each of the credential ids (key handles) in the excludeList. If any of them does not result in an error, that means that this is a known device. Afterwards, the platform MUST still send a dummy registration request (with a dummy appid and invalid challenge) to CTAP1/U2F authenticators that it believes are excluded. This makes it so the user still needs to touch the CTAP1/U2F authenticator before the RP gets told that the token is already registered.

from authenticator-rs.

xchapron-ledger avatar xchapron-ledger commented on June 24, 2024

Hello :)

\2. Hm, this is weird. I don't have a Mac, so I can't reproduce this. I just asked somebody else and it worked for them (although, AFAIK for released versions the log-levels are capped at "INFO", and "DEBUG" can't be chosen any more). Maybe the problem is the selector for authenticator=. Please try with RUST_LOG=trace /Applications/Firefox\ Beta.app/Contents/MacOS/firefox, although this will print a lot.

Using Firefox Beta, I managed to get some logs, but it was really noisy, and didn't contains interesting logs as far as I know.

On the other hand, you could also just download this repository and run RUST_LOG=debug cargo run --example ctap2. This will cut out the middle-man (Firefox), and make debugging easier.

I therefore went this path, but what a nightmare. I went from one issue to another during the installation of nss.
I eventually managed to make it works by switching to openssl in the cargo.toml with this diff:

diff --git a/Cargo.toml b/Cargo.toml
index 554ea1c..8e60540 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,7 +14,7 @@ travis-ci = { repository = "mozilla/authenticator-rs", branch = "master" }
 maintenance = { status = "actively-developed" }
 
 [features]
-default = ["crypto_nss"]
+default = ["crypto_openssl"]
 binding-recompile = ["bindgen"]
 # Crypto backends
 # NOTE: These are mutually exclusive, but cargo does not support that.
@@ -22,8 +22,8 @@ binding-recompile = ["bindgen"]
 # Default: NSS
 crypto_dummy = []
 crypto_openssl = ["openssl", "openssl-sys"]
-crypto_nss = ["nss-gk-api", "pkcs11-bindings"]
-gecko = ["nss-gk-api/gecko"]
+#crypto_nss = ["nss-gk-api", "pkcs11-bindings"]
+#gecko = ["nss-gk-api/gecko"]
 
 [target.'cfg(target_os = "linux")'.dependencies]
 libudev = "^0.2"
@@ -67,7 +67,7 @@ cfg-if = "1.0"
 # Crypto backends
 openssl-sys = { version = "0.9", optional = true}
 openssl = { version = "0.10", optional = true}
-nss-gk-api = { version = "0.3.0", optional = true }
+#nss-gk-api = { version = "0.3.0", optional = true }
 pkcs11-bindings = { version = "0.1.4", optional = true }
 
 [dev-dependencies]

I've attached the log below, I hope this help understanding the issue.
ledger_authenticator_ctap2_failure.txt

Regarding dummy request, first thanks for the links on Google Chrome code, that's interesting.
I guess I should look at implementing the FIDO2.1 spec, this might improve some behavior as it seems implemented (and even expected) in browser.

There may be some constellations were we could use the actual request instead of the dummy to make the device fail, but it doesn't really matter what we send, if all we want to do is collect a user-interaction and fail.

I still don't get why you want a user-interaction at that point. From my point of view, if the authenticator respond to the request with a failure without requesting UV or UP it's already an issue, as one could then design a rogue client which could then try to get information on known credentials. that's why the authenticator has to do this, and this is specified in both FIDO2 and FIDO2.1 spec:

  • FIDO2: The step 7 (collecting UV or UP) should be done before step 8 (responding if no credential is present): "Collect user consent if required. This step MUST happen before the following steps due to privacy reasons (i.e., authenticator cannot disclose existence of a credential until the user interacted with the device):"
  • FIDO2.1 : UV verification should be done in step 6 before maybe responding in step 7 and credentials can be protected to request UV for access.

Thanks,
Xavier

from authenticator-rs.

xchapron-ledger avatar xchapron-ledger commented on June 24, 2024

Hello @msirringhaus I found a way to work around the problem.

I think it is because in the getAssertion response, the authenticator doesn't add the credential (0x01) member.
This is allowed by the FIDO2 spec in some situation, which this one is:

Optional PublicKeyCredentialDescriptor structure containing the credential identifier whose private key was used to generate the assertion. May be omitted if the allowList has exactly one Credential.

However, it's seems that your implementation enforces it, I try adding it in my authenticator response, and after that, the ctap2 example run successfully.

Do you think this is something you could change to be compatible with more devices that respect the FIDO2 spec?
I guess this should require some changes around here: https://github.com/mozilla/authenticator-rs/blob/ctap2-2021/src/ctap2/mod.rs#L661-L673

I still don't get why it works on Firefox on Linux and on Windows, but not on Firefox on Mac nor when directly using authenticator-rs (on Mac or Linux), do you know?

Edit: looking at the FIDO2.1 spec, this credential (0x01) member is required, so I guess I will change the authenticator behavior to always include it.

Also, I now see that in such situation, your authenticator code make a first silent getAssertion request (with up=false and uv=false) and then a second requiring user presence and verifiation. So now behaving mainly as I expected it in working cases.

So if it's ok for you, I'm going to change the title of this issue to:
Wrongly enforces getAssertion credential (0x01) member presence in the authenticator response, which is optional in FIDO2

Thanks
Xavier

from authenticator-rs.

msirringhaus avatar msirringhaus commented on June 24, 2024

Ok, this makes no sense to me. We do not enforce user to be present anywhere, as far as I can tell.

What I've noticed, though, is that you do not send the credentialID in your GetAssertion response. This is fine for CTAP2.0 devices (although not allowed anymore for 2.1), but it looks to me that our code may have a bug there, and disregard your token because this is missing.
The only situation the omission is allowed for CTAP2.0 is, if the allowList has length 1. This may explain why it sometimes works, and sometimes doesn't. You could try to add a dummy credential to the allowList in examples/ctap2.rs, and see if it works then?

from authenticator-rs.

xchapron-ledger avatar xchapron-ledger commented on June 24, 2024

Ok sorry, I was editing my response. Indeed, the issue is due to the absence of credential (0x01) member in the response.

from authenticator-rs.

xchapron-ledger avatar xchapron-ledger commented on June 24, 2024

Here is what I have added in my response:

looking at the FIDO2.1 spec, this credential (0x01) member is required, so I guess I will change the authenticator behavior to always include it.

Also, I now see that in such situation, your authenticator code make a first silent getAssertion request (with up=false and uv=false) and then a second requiring user presence and verifiation. So now behaving mainly as I expected it in working cases.

So if it's ok for you, I'm going to change the title of this issue to: Wrongly enforces getAssertion credential (0x01) member presence in the authenticator response, which is optional in FIDO2

from authenticator-rs.

msirringhaus avatar msirringhaus commented on June 24, 2024

Ah, mid-air collision :) Yes, now it makes sense to me.

The problem is in our pre-flighting code here: https://github.com/mozilla/authenticator-rs/blob/ctap2-2021/src/ctap2/preflight.rs#L168-L171

I'll see, if I can come up with a fix (that doesn't introduce 10 additional bugs).

from authenticator-rs.

jschanck avatar jschanck commented on June 24, 2024

Resolved by #320

from authenticator-rs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.