Some of those who have done work with U2F before are confused by FIDO2 U2F attestations. Previously U2F attestations were raw buffer, and now it is fancy CBOR structs. How does one verify these attestations, you might ask?
Before we start, we need to look at original U2F attestations:
And now lets look at what you get from WebAuthn:
This is happening, because in FIDO2 we introduced CTAP1(U2F) to CTAP2 mapping. Here is a diagram of the process taken from CTAP2 specification:
So in order to verify signature we need to reconstruct the original signatureBase buffer. To do that we need:
- application parameter — rpIdHash
- challenge parameter — clientDataHash
- keyHandle — credId
- publicKey — a 65 byte ANSI encoded P256 public key
To get rpIdHash, credId and publicKey we need to parse authData as we’ve talked about it in my “Verifying FIDO2 responses” blog. The only problem we have is that in FIDO2 we are working with COSE public keys, where in U2F they are ANSI encode. So to re-encode key, we need to extract x and y coefficients from COSE key and merge them together, prepending 0x04.
With that resolved, we can merge ReserveByte, RPIDHash, ClientDataHash, CredId and PublicKey into signature base. Then we can PEM encode certificate in x5c array, or extract the public key, and use it to verify the signature:
If you are planing to support metadata service, then you can find attestationCertificateKeyIdentifier by calculating the SHA1 of the subjectKey structure as described in method 1 of the section 188.8.131.52 of the RFC5280.
If you like this post, you should read my horror story on verifying TPM2.0 attestation.
This article is licensed under Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0). So you are free to read, share, etc. If you are interested in commercial use of this article, or wish to translate it to a different language, please contact ackermann(dot)yuriy(at)gmail(dot)com.
The code samples are licensed under MIT license.