Open iayanpahwa opened 11 months ago
Hi, thanks for the report!
Could you provide the following information to help debug further:
Thanks!
Thank you for swift response @ia0 ,
How did you compile, flash, and configure OpenSK on the dongle?
I followed exact steps mentioned in install.md and nrf52840_dongle.md i.e DFU flashing
How do you connect the dongle to your phone?
Using Lightning to USB A adaptor
Does it work with iOS 16?
No, just checked on iPad running ios16 with USB C to USB A dongle
FYI, my Yubikey 5 worked flawlessly on both.
Thanks! We will need to find a way to reproduce to be able to debug (unless you happen to also have a dev-board). This may take some time.
I do have a NRF52840DK dev board. But it’s not handy atm. If you could guide me thru the process I could give it a try next week.
That would be great!
cd /tmp
git clone -b develop https://github.com/google/OpenSK.git
cd OpenSK
./setup.sh
./deploy.py --board=nrf52840dk_opensk --opensk --debug --panic-console --clear-storage
./tools/configure.py --certificate=crypto_data/opensk_cert.pem --private-key=crypto_data/opensk.key
JLinkExe -device nrf52 -if swd -speed 1000 -autoconnect 1
.JLinkRTTClient
. Make sure you have infinite scrolling, there will be a lot of input.Thanks!
Hi @ia0 , I tried this today. Unfortunately getting some errors during flashing. Please note I've copied udev rules and replugged the device. Any idea what else can I do ?
info: Generating Tock TAB file for application/example ctap2
info: Erasing the persistent storage
info: Erasing all installed applications
WARNING:root:Unknown TLV block in TBF header.
WARNING:root:You might want to update tockloader.
info: Flashing padding application
info: Installing Tock application ctap2
WARNING:root:Unknown TLV block in TBF header.
WARNING:root:You might want to update tockloader.
WARNING:root:Unknown TLV block in TBF header.
WARNING:root:You might want to update tockloader.
info: Configuring device.
info: Your device is not yet configured, and lacks some functionality. You can check its configuration status with:
./tools/configure.py
If you run into issues, this command might help:
./tools/configure.py \
--certificate=crypto_data/opensk_cert.pem \
--private-key=crypto_data/opensk.key
Please read the Certificate considerations in docs/customization.md to understand the privacy trade-off.
fatal: No device to configure found.
lsusb output shows SEGGER J-Link connected
That's the expected output. You may ignore those warnings. I have them too and it's not a problem.
You should be able to follow up with the instructions continuing from ./tools/configure.py
.
Note that the device is extremely slow with debug enabled, so you may have to wait longer than expected for some steps.
Thanks @ia0 , I was able to reproduce this issue using the NRF52840 DK dev board. You can find the logs in public gist here. I'm looking forward to learn from your diagnosis, many thanks!
Thanks a lot! So it looks like we send a MakeCredential response which makes me believe that iOS is probably refusing our AAGUID or certificate. @jmichelp what do you think?
Apple has a page talking about Keys specifications : https://support.apple.com/en-in/HT213154
It's possible that they whitelist AAGUID to the FIDO certified ones. But my first guess would be to say that they're simply more pedantic about the attestation certificate. IIRC I haven't patched the certificate generation to include the x509v3 extensions they need (it needs to embed the AAGUID, the supported transports, etc.). It works 99% of the cases because nobody cares about it, but with CTAP2.1 they seem to do more checks :)
I'm happy to work on a PR if you could guide me thru.
Sorry for the wait (and more waiting is to be expected, see below). A few observations:
metadata/metadata.json
in our repository should be contained.So if we are indeed rejected because of attestation problems, then this could be related. I'll reach out to FIDO.
Turns out I missed a step to submit an OpenSK entry to the MDS. So we likely have to fix #457 and / or add register OpenSK correctly to FIDO.
Thanks for the update @kaczmarczyck , happy to test it over once we've the fix.
Update: OpenSK is now listed in the MDS with
AAGUID 664d9f67-84a2-412a-9ff7-b4f7d8ee6d05
For some reason, it still lists the status as NOT_FIDO_CERTIFIED
.
We could test if this already satisfies Apple. I am sceptical it does, but if you want to try, open the file crypto_data/aaguid.txt
and paste the above AAGUID into it. Note that the MDS entry lists the properties from our 2.0 version, not sure if that causes problems.
If that does not work, the next 2 tests would be: A) Activate batch attestation. B) Wait for the MDS to acknowledge our certification status, and that to propagate to Apple.
To try A), you can edit libraries/opensk/src/api/customization.rs
so that DEFAULT_CUSTOMIZATION
says:
use_batch_attestation: true,
You will have to configure after deploying to enable batch attestation:
./tools/configure.py \
--certificate=crypto_data/opensk_cert.pem \
--private-key=crypto_data/opensk.key
Note: Our documentation has some info on privacy implications of batch attestation if you want to use that key outside of experimentation. The attestation certificate you are going to use doesn't match the MDS entry though. That is because you just generated it, and you can't attest yourself. This is basically the open source nature of OpenSK.
If Apple does require batch attestation and checking them through the MDS, then there is intentionally no way you can build your own security key and make it work with them I think.
The MDS blob (downloaded here) still lists us as not certified. We merged #668 , so anyone with a Mac could try Apple ID with OpenSK. Steps:
develop
and pull./reset.sh && ./setup.sh
(save pending changes before this step)crypto_data/aaguid.txt
and change it to 664d9f67-84a2-412a-9ff7-b4f7d8ee6d05
DEFAULT_CUSTOMIZATION
in libraries/opensk/src/api/customization.rs
as explained aboveFor debugging purposes, if that works, we coud also try with a random AAGUID (write something else in step 3). That should inform us whether Apple supports self-made security keys.
@iayanpahwa If you are interested in trying, feel free to report all observations here!
I’ll try and test it in soon.
Hi,
I just started evaluating your great project with a pair of nRF52840 dongles and OSX, which might be of interest to you for this issue:
aaguid
aaguid
change and turning on batch attestationResults on an Apple MacBook Air:
So I'd assume that changing the aaguid
and activating batch attestation works.
I don't have a Lightning to USB adapter here so unfortunately I can't test on my iPad / iPhone.
Thanks for checking! I got a response from FIDO last week that they updated their MDS to include OpenSK as certified. When I downloaded their blob then, it didn't reflect that yet, but today, I tried again and it says:
'status': 'FIDO_CERTIFIED_L1'
With the timing of @JohannesBloecker , I don't think we can find out whether that was necessary for OpenSK to work. But it does mean that OpenSK is now usable on iOS with batch attestation and the right AAGUID! I wonder if we should make it more accessible with a deploy option. Do you know if just one batch attestation or the AAGUID change already works?
I'll dig a bit deeper into this matter, let me make some tests adding additional dongles, I'll check the following:
That should give some more hints.
It would be weird for Apple to validate the AAGUID against the MDS and not validate the associated certificates. At least I am aware that some companies start to validate the attestation certificate against the MDS too. Spoofing the AAGUID without using the same root and intermediate CA we used for the FIDO certification might fail.
Ok, tonight I did a combination test to find out what exactly works and what not on Apple MacBook Air M1 macOS Sonoma 14.3.1 (23D60) and iOS 17.2 (21C62).
Summary
The AAGUID does not seem to matter, use_batch_attestation: true
is what makes the dongle work on macOS and iOS.
Full test setup
develop
branch./setup.sh
./deploy.py --board=nrf52840_dongle_dfu --erase_storage --programmer=nordicdfu_nrfutil_binary --rust-crypto
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu_nrfutil_binary --rust-crypto
--> Adding key fails on MacBook Air: HTTPError: 500
./deploy.py --board=nrf52840_dongle_dfu --erase_storage --programmer=nordicdfu_nrfutil_binary --rust-crypto
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu_nrfutil_binary --rust-crypto
--> Adding key fails on MacBook Air: HTTPError: 500
use_batch_attestation: true
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu_nrfutil_binary --rust-crypto
--> Test succeeds on MacBook Air, security added
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu_nrfutil_binary --rust-crypto
--> Test succeeds on MacBook Air, security key added
Revalidate with full vanilla build on iPad Pro 12.9 Gen 4
./deploy.py --board=nrf52840_dongle_dfu --erase_storage --programmer=nordicdfu_nrfutil_binary --rust-crypto
develop
branchuse_batch_attestation: true
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu_nrfutil_binary --rust-crypto
--> Test succeeds on iPad Pro 12.9 Gen 4, security key added
(nordicdfu_nrfutil_binary
I patched the deploy.sh
to work with the nrfutil
binaries from Nordic. See comment in #588.)
Cool, thanks for investigating! Probably means we should have a feature flag for batch attestation then.
Yes, the AAGUID is randomly generated. And interesting to see that people like RustCrypto.
By the way, privacy warning: Since your batch will likely have size < 10, these keys are uniquely identifyable by any relying party you use them with. So if you sign up at a.com
and b.com
, then they could compare notes and realize that both accounts were made by you or someone you created a key for. There is inherently no good way to work around it, if you allow batch attestation. The non-standard ones I see are:
Opinions? @jmichelp @ia0
I'm not familiar enough with FIDO to tell whether a public batch attestation is something they expect. If yes, then publishing a public AAGUID and batch attestation, and using it by default (or with a compilation flag) in OpenSK sounds good to me.
Regarding disabling batch attestation for Apple, why not do it in the firmware directly? This would be more convenient. AFAICT (not familiar with FIDO enough to be sure), batch attestation is only checked in MakeCredential at which point we know the RP. So we could have a configurable list of RPs that needs batch attestation and only use batch attestation for those. That said, if that list is larger than one element, then we're back to the privacy issue, which is why going with a public AAGUID and batch attestation seems like the best option if it's something FIDO would permit or agree with.
The idea of an allowlist for batch attestation is interesting. (Maybe unintentional in your message, but we want to enable batch attestation for Apple, and disable it for everyone else.)
Such a list would need to be user configurable, because OpenSK shouldn't be biased in favor of certain RPs. Which would make it a different UX than toggling batch attestation, but practically the same idea.
Compared to publishing an AAGUID and batch attestation key pair, the advantage is that we don't just increase the anonymity set, we enforce it for all RPs not on the allowlist. In fact, both measures are orthogonal, and we can consider them independently.
Whether or not FIDO has an opinion on either of these, I don't know. But it should be a user's freedom to decide. For example, Chrome asks for permission to forward the batch attestation to the RP.
Yes that's exactly what I meant. And indeed it's orthogonal except if the list is a singleton (like in this example), because then the second option is almost strictly better (the only difference being that your batch attestation is still unique, but the RP should have no way to correlate it to anything unless you published the public part somewhere).
Wouldn't it be quite impractical for the user to switch batch attestation on and off? I would also assume that you'd then need a kind of CLI tool to add sites to a flashed key in use. Or implement a double or triple click feature on the approve button to turn it on or off.
For TLDR;
Maybe provide compiled versions via a CI/CD approach for your releases, 2.0,
2.1
including standard AAGUID and standard certificates? Then you could leave batch attestation safely enabled.
In more detail:
I just read some more details on what the AAGUID and the batch attestation are really intended for by FIDO. What I understood:
Now with the OpenSK approach, having a programmable device as key, this approach does not work as intended. With the user compiling the sources but reusing a certificate and AAGUID it makes no sense anymore for an RP to actually take any conclusions regarding version and security, maybe only "uses a self-built OpenSK key".
What came to my mind as an idea, especially regarding accessibility of the OpenSK key:
Provide compiled versions via a CI/CD approach for your releases, 2.0,
2.1
. And in the binary, issue a certificate and AAGUID for this version. Leave develop
as-is and use a development AAGUID.
For the AAGUID, I don't see a problem with keeping it stable for a branch. The batch attestation is the problem: It needs a private key that is baked into the (protected) hardware. For example, if the private batch key for a Yubikey would leak, than anyone could pretend to be a Yubikey. So if we published the private key that OpenSK used during certification, it would be worthless, because its possession wouldn't prove that you are a certified key.
Which is why our setup creates random key material. And that is the source of the privacy issue. For closed-source authenticators, the RP only learn that you one of hopefully many Yubikeys. For a self-built OpenSK, you don't have that many people to share you batch key with.
Which is why I proposed workarounds like disabling batch attestation. Thinking about it, another workaround is to automatically generate a new random batch private key each time you register anywhere. This would defeat the purpose of batch attestation. But requiring batch attestation without actually checking if the batch key is registered with FIDO might make this a viable hack. At least, it wouldn't need user intervention, and would let OpenSK work with more RPs.
Downside is that we'd have to implement some code to generate certificates. If we indeed need them. Maybe we can send empty certificates and Apple is still happy? We don't know yet whether they get checked. Opinions?
I like the idea of creating random batch attestation for RPs requiring batch attestation without actually doing any check. However, this seems to me that it's just shifting the problem a bit. Some RPs might check more than others (up to check whether the batch attestation is registered by FIDO). So it looks that for custom-built OpenSK (i.e. with a generated and thus unregistered batch attestation), there will be RPs refusing the key. If we decide to provide a solution, we should decide which RPs we want to support for those custom-built OpenSK:
If we believe Apple is the most common problematic RP, then we could indeed check what Apple actually checks, and do the minimum to pass those checks.
Generating a certificate will need some code, but using templates we may get away with simple byte sequence manipulation.
@kaczmarczyck, I thought to neither use randomly generated certificate / private key for batch attestation nor expose the private key you received the FIDO2 L1 certification with, as you state would be equally worthless for an RP to trust knowing it could be used with any software / hardware combination.
What I propose is to provide a "common random" certificate, e.g. per branch and tag, reusable by any user to circumvent the privacy issue you mentioned. My tests with a random certificate worked, so a reusable random certificate solving the privacy issue will also work. Batch attestation trust for the RP in terms of "uses a certain hardware/firmware" can anyways not be achieved due to the openness of the approach.
And this would also enable to provide packages / images for each tag with baked in common (random) certificate to gain a better accessibility to self-build vanilla OpenSK dongles without software compilation.
Not sure I understand the first paragraph, so let me summarize what I think.
A) I agree that receiving a random batch attestation shouldn't matter to RPs, and any RP that accepts them should accept us without any attestation. So this is not about increased security, it is about making OpenSK work with more RPs.
B) We will not publish the one meaningful batch private key that was used during certification.
C) Our goal is to protect user privacy by increasing the anonymity set, meaning the number of people they are indistinguishable with through fingerprinting. Without attestation, this would ideally be all security keys with the same feature set. With attestation, if you are not a manifacturer and issue your own batch, this would ideally be all other fully open source users.
D) By the way, U2F requires the batch certificate, so if you want to use U2F, all of the above applies. This has been a source of confusion before, when people expected OpenSK to work, but forgot to configure it.
Let me explain my proposed change to how we handle batch attestation with an overview on how we behave with respect to its boolean customization flag, and how we could change that.
false
(default)U2F works after you configure, batch attestation is never used.
true
U2F fails until configure, batch attestation is used after configure, otherwise not used.
never
Implies with_u2f
feature flag is disabled, U2F never works, batch attestation is never used
random
(default)Uses a random batch private key and certificate for both U2F and batch attestation, batch attestation is usable, U2F is usable if compiled with with_u2f
.
Random here can mean two things that have similar functionality and privacy implications:
This gives people privacy by default, if they just want all features to work. In both cases, other open source users could copy our approach and join OpenSK's anonymity set.
Also I want to remark that the current default self attestation is what we should be doing, if RPs would let us. However, the new approach makes U2F more privacy friendly by default, so it is an improvement in that sense, which inspires the conform
mode.
conform
Uses self attestation on MakeCredential, and a random batch key and certificate for U2F, if compiled with with_u2f
.
Fails with Apple, but this is the idealistic approach that FIDO imagined.
configured
Uses the configured batch private key and certificate for both U2F and batch attestation. MakeCredential fails until configured. U2F fails until configured, or always fails if compiled without with_u2f
.
@kaczmarczyck still trying to fully follow you and A,B,C,D, yes, you understood what I meant.
Regarding D I read in the Fido alliance U2F overview chapter 8 Verifying That a U2F Device Is 'genuine' §3: "Every public key output by the U2F device during the registration step is signed with the attestation private key." So U2F implies batch attestation, got it.
I also conclude that it's best to "simulate" the batch attestation with a certificate uploaded in the repository and change it for every major.minor OpenSK version. random
mode 2 as with the current tests I think would also work regarding registration.
Knowledge gap on my side: Is the randomly generated certificate also used during authentication? Then you'd need to store the random certificates together with the key pair. Otherwise an RP might refuse to authenticate if the challenge response is correct, but suddenly signed with a different batch attestation certificate that got newly generated during the authentication process.
And conform
equals Before (bool) false
and configured
equals Before (bool) true
, correct?
Attestation is for MakeCredential
only, and doesn't happen during GetAssertion
(or the U2F equivalents). So throwaway certificates are possible.
configured
behaves like true
, but there is a difference between conform
and false
: U2F uses the random batch key in conform
, and needs the configure command to work in false
. So conform
is a privacy and usability upgrade. It should probably be called something else. The intention is that it keeps U2F as a working fallback to CTAP2 without privacy compromises.
When I think about it, never
and conform
are the same if U2F is disabled, so with_ctap1
could also function as a switch between these two options.
I checked the logic table based on the batch attestation flags and the proposed with_ctap1
flag.
@kaczmarczyck mentioned that users also have a misunderstanding that batch attestation is required for U2F/CTAP1. How about structuring the parameter settings on the usage per protocol?
self
Self-attestation is used for CTAP2
random
Random certificate is used for CTAP2 batch attestation
user
Provided user certificate in ./configure
is used for batch attestation
never
/ off
/ disabled
CTAP1 / U2F disabled (as it's mandatory in U2F)
random
Random certificate is used for CTAP1 / U2F
user
Provided user certificate in ./configure
is used for batch attestation
Alternatively providing additional switches for on
and off
first and then define the batch attestation mode would also work:
with_ctap2: true
and false
ctap2_batch_attestation: self
,random
,user
with_u2f / with_ctap1: true
and false
ctap1_batch_attestation: random
, user
Defaults to true
and random
for privacy protection.
If for the random mode the certificates and keys can be generated on the device, additional settings could enhance the security to not rely on the ./configure at all but add the option to completely handle all key generation as an init procedure on the device making each device unique and keys are never touching the laptop. Then combine this with APPROTECT as you discussed in this comment.
Expected Behavior
I tried adding my OpenSK NRF52840 dongle key with Apple. Since the implementation is FIDO certified it should work with Apple ID
Actual Behavior
Steps to Reproduce the Problem
Specifications