Attestation verification through trust anchor
Closed this issue · 14 comments
Description
Hello all.
After studying a bit the library and stumbling in this piece of comment, I would like to open a discussion on how could be an interesting way of supporting a trust verification using the library.
My understanding is that up to this point, the library does not export any facility for doing trust assessments on the embedded attestation certificates. I couldn't also find a convenient way through a public method to extract the embedded certificates without having to copy the whole procedure of attestation-object protocol decoding.
I'm opening this feature-request to trigger a discussion around how that could be accomplished. Here are some options that come to my mind, any others would be welcomed:
- Implement in the library the possibility to provide a list of trusted
root certificates
against which the attestation certificate could be verified. - Implement in the library something like
ExportAttestationCertificates
method that would delegate to the client the responsibility to implement the chain-of-trust verification. - Document if there is an existing mechanism to achieve that.
What are your thoughts on that? I would be happy to try to help wherever possible with some code-contributions. 😃
Thank you in advance for your work and support,
Rodrigo
Use Case
Some types of webauthn attestation verification would require verification against an RP policy. This verification is done by verifying the embedded attestation certificate against an RP-trusted set of root certificates
(otherwise called a trust store).
Use cases:
- Allow RP to filter which kinds/types of authenticators to allow. Some RPs might only want to support apple devices. Others only Yubico, and so on and so forth.
- Check the validity and trustworthiness of the provided attestation-certificate
Documentation
No response
Reference for a chain-of-trust verification in go:
https://gist.github.com/devtdeng/4f6adcb5a306f2ae035a2e7d9f724d17
Thanks for posting the FR. I think this is most likely a good move. I will take a deeper look at this area of the library to see if there is an obvious way to handle this. I believe the github.com/go-webauthn/revoke module will be useful here, and performing the chain verification is relatively straight forward.
I suspect we can just add two or three optional fields to the webauthn configuration element that are injected into the relevant areas as needed. A list of trusted device signing certificates, a list of AAGUID's, and a func used to override the default verification method.
Hey @james-d-elliott , I'm glad to hear your thoughts - my intuition was exactly the same (optional field in the Webauthn
config.
Okay @rbroggi I believe that this is nearly already possible. I'll put together an example and the necessary changes to the library.
I believe we do everything needed in this section (except performing the checking against the anchor itself): https://github.com/go-webauthn/webauthn/blob/master/protocol/attestation.go#L111
Looking at the spec more closely, there are a few issues we may have to overcome:
- ECDAA implementation (there's one in java and C that I found, none in go)
- One of the X.509 certificates in the MDS3 blob seem to be invalid (verified in go and python, though openssl is happy with it):
- Authentrend CA 000 (with serial number 1) for AAGUIDs (error decoding basic constraints extension CA value):
- e1a96183-5016-4f24-b55b-e3ae23614cc6
- d41f5a69-b817-4144-a13c-9ebd6d9254d6
- Authentrend CA 000 (with serial number 1) for AAGUIDs (error decoding basic constraints extension CA value):
Interesting findings. I will see if I can understand why that is...
Here is the certificate in question:
-----BEGIN CERTIFICATE-----
MIIBzDCCAXGgAwIBAgIBATAKBggqhkjOPQQDAjBiMQswCQYDVQQGEwJTRTESMBAG
A1UECgwJQVRLZXlDQTAwMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0
aW9uMRswGQYDVQQDExJBdXRoZW50cmVuZCBDQSAwMDAwIBcNMTYwMjI2MDgxMTA2
WhgPMjA1MDAyMjUwODExMDZaMGIxCzAJBgNVBAYTAlNFMRIwEAYDVQQKDAlBVEtl
eUNBMDAxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xGzAZBgNV
BAMTEkF1dGhlbnRyZW5kIENBIDAwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
BAJcWqeCxga9KJbFO2TZdjcgrtZAgfi8TXKu+v5lcR5ceb5GJYxyoCjhueESL3dd
mMIkpGyhsEEtfFUyBwsyFVCjFjAUMBIGA1UdEwEB/wQIMAYBAQECAQAwCgYIKoZI
zj0EAwIDSQAwRgIhAMqIc/Qtr+jZbnrJB7g7W8r/DHmDe+IyFvzwpzdSrxEXAiEA
tXcixZznhcDzlnIqFqkIJRGmvL9Yr6lVoP1ZkDeqmjk=
-----END CERTIFICATE-----
Hey just touching base, I know this has taken a while (I have actually made fairly significant progress but nothing material to show). I wanted to explain why. I'm intentionally underestimating my knowledge regarding WebAuthn and FIDO2 in order to avoid issues. It's easy with such a complex spec to get things wrong. In addition and fairly unrelated I'm fairly busy with work and life, making motivation a fairly scarce resource but this will resolve itself soon or I will resolve it.
I think one of the key things I want to do here is completely rewrite this portion of the library so that users must provide a MDS3 specific interface implementation to the library, with a rudimentary implementation that satisfies basic usage (memory cached, http.Client, etc).
This would allow users to implement it in a way which has a longer life i.e. saved to disk per the FIDO Alliance recommendations or share it with auxiliary micro services relatively easily. It would also potentially allow us to provide implementers a way to have additional checks or completely replace the checking process.
Dear @james-d-elliott , your efforts and transparency are very appropriated. I also find myself in a quite busy moment and have not found the time I would like to help with this. Don't hesitate to drop some details of the rewrite intentions so I can give you feedback.
So good news about this one @rbroggi, I made contact with the FIDO Alliance, explaining the issue and cause in detail. I did a fairly careful investigation into this and it turns out the ASN.1 DER (distinguished encoding rules) booleans were improperly encoded as ASN.1 BER (basic encoding rules) booleans instead for these particular certificates. ASN.1 DER requires booleans have a 0x00 byte when false and 0xff when true, whereas ASN.1 BER stipulates any value other than 0x00 is true (they used 0x01). From my investigation it seems this is rather common, and the error occurs in several major programming languages (Go, Rust, Python, C#).
David Turner from the FIDO Alliance has had the vendor who provided the certificate fix it and it looks like it's made it into the MDS3 blob.
So good news about this one @rbroggi, I made contact with the FIDO Alliance, explaining the issue and cause in detail. I did a fairly careful investigation into this and it turns out the ASN.1 DER (distinguished encoding rules) booleans were improperly encoded as ASN.1 BER (basic encoding rules) booleans instead for these particular certificates. ASN.1 DER requires booleans have a 0x00 byte when false and 0xff when true, whereas ASN.1 BER stipulates any value other than 0x00 is true (they used 0x01). From my investigation it seems this is rather common, and the error occurs in several major programming languages (Go, Rust, Python, C#).
David Turner from the FIDO Alliance has had the vendor who provided the certificate fix it and it looks like it's made it into the MDS3 blob.
Hey James, this sound like a deep rabbit hole! Thank you for investigating and getting to the end of it!
Since it seems to be something quite common, do you have any tips on how to easily diagnose whether a certificate could be suffering from it? This could save a huge amount of hours to many people suffering from the same issue.
Unfortunately the only way to diagnose it is to know it's an issue and identify the field being parsed is a boolean set to a value equal to or above 0x01 and equal to or lower than 0xfe, or to figure this out. It seems OpenSSL just ignores it, many languages will show an error however which can be used to pinpoint it. Alternatively knowing that this is a seemingly common issue with ASN.1 DER due to ASN.1 BER existing is a huge help.
If I had have been more motivated I probably would have found it sooner. However this means I can probably make some progress on this particular issue.
Hi @james-d-elliott May I ask how can I transfer Credential.PublicKey(I belive it's CBOR encoded) into a DER/PEM format PublicKey? And is there any plan to implement the AuthenticatorAttestationResponse interface? thanks.
You can use webauthncbor.Unmarshal to decode it into one of the webauthncose formats. Also AuthenticatorAttestationResponse is already implemented by the type with the same name.
If there is some element you feel is missing that would be useful then please submit a completely separate FR, or if you have questions about the library submit a discussion. This issue is for discussion related to the verification of the attestation statement via the MDS.