MasterKale / SimpleWebAuthn

WebAuthn, Simplified. A collection of TypeScript-first libraries for simpler WebAuthn integration. Supports modern browsers, Node, Deno, and more.
https://simplewebauthn.dev
MIT License
1.63k stars 137 forks source link

Certiticate parse error in verifyAttestationResponse #111

Closed r0kk3rz closed 3 years ago

r0kk3rz commented 3 years ago

I am trying out the webauthn process using Chromes webauthn dev tools with protocol ctap2 and transport internal, and on the server side I am getting the following error

Error: hExtV parse error: 3003010100
    at X509.getExtBasicConstraints (.../node_modules/jsrsasign/lib/jsrsasign.js:249:3670)
    at Object.getCertificateInfo [as default] (.../node_modules/@simplewebauthn/server/dist/helpers/getCertificateInfo.js:41:53)
    at Object.verifyAttestationPacked [as default] (.../node_modules/@simplewebauthn/server/dist/attestation/verifications/verifyPacked.js:53:107)
    at verifyAttestationResponse (.../node_modules/@simplewebauthn/server/dist/attestation/verifyAttestationResponse.js:166:48)
MasterKale commented 3 years ago

Hello @r0kk3rz, can you please provide a sample attestation response from that virtual authenticator that causes this error?

And for good measure can you also include how you're calling generateAttestationOptions()?

r0kk3rz commented 3 years ago

Here is the response i am receiving from the client:

{
    "id":"9HEeR9BWrt7Z7pYJLEuqoSZ69qtIgBqWe8rthIxpIBQ",
    "rawId":"9HEeR9BWrt7Z7pYJLEuqoSZ69qtIgBqWe8rthIxpIBQ",
    "response":{
        "attestationObject":"o2NmbXRmcGFja2VkZ2F0dFN0bXSjY2FsZyZjc2lnWEgwRgIhAOj3W82tCaw04Qy-PYqkPYKHlox2cDd_OHFoZV9foh85AiEA5XsVMN_jUXJidHCy6uu7thhldCuyNct4BVdHKWNHonBjeDVjgVkB4jCCAd4wggGAoAMCAQICAQEwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UEBhMCVVMxETAPBgNVBAoMCENocm9taXVtMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0aW9uMRowGAYDVQQDDBFCYXRjaCBDZXJ0aWZpY2F0ZTAeFw0xNzA3MTQwMjQwMDBaFw00MTAzMjUwNzQ2MzRaMGAxCzAJBgNVBAYTAlVTMREwDwYDVQQKDAhDaHJvbWl1bTEiMCAGA1UECwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEaMBgGA1UEAwwRQmF0Y2ggQ2VydGlmaWNhdGUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASNYX5lyVCOZLzFZzrIKmeZ2jwURmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEBoygwJjATBgsrBgEEAYLlHAIBAQQEAwIDCDAPBgNVHRMBAf8EBTADAQEAMA0GCSqGSIb3DQEBCwUAA0kAMEYCIQDY1rS1fjJp0Cj6n6_Cum8KdD4uTcUzvPag1nATnWUTgAIhAKavHd40jscCBY9k1dwZn2BAcAoW9NpdEfQEyeJjVDakaGF1dGhEYXRhWKRJlg3liA6MaHQ0Fw9kdmBbj-SuuaKGMseZXPO6gx2XY0EAAAABAQIDBAUGBwgBAgMEBQYHCAAg9HEeR9BWrt7Z7pYJLEuqoSZ69qtIgBqWe8rthIxpIBSlAQIDJiABIVggXMH-sW7hiD9ibrXbVn-IM6Xj70Wj_8rxAlLmIAifrhciWCAgTbxE_2lF2pZlhNOmcebcv7KlbMx998ENx8RAVrzqOA",
        "clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoib1k5RGhCNVpEODRUN2VnY2gyeDgyaW9vWm02THNtZjBvUXJjcE4tZGxENCIsIm9yaWdpbiI6Imh0dHBzOi8vbG9jYWxob3N0Ojg0NDQiLCJjcm9zc09yaWdpbiI6ZmFsc2V9"
        },
    "type":"public-key",
    "clientExtensionResults":{},
    "transports":["internal"]
}

These are the options I am setting:

    const options = generateAttestationOptions({
        rpName,
        rpID,
        userID: user,
        userName: user,
        attestationType: 'indirect',
    })
MasterKale commented 3 years ago

I dug deep for this one: it turns out the jsrsasign dependency doesn't know how to handle the Chrome WebAuthn authenticator's thoroughly-implemented X.509 leaf certificate that specifies the byte sequence that represents whether cert is a certificate authority's (I think; I'm not as well-versed on X.509).

I have an idea for a solution in the interim that can handle this case while I submit a PR to that project to add in support for the legitimate value returned by the virtual authenticator. 🤔

MasterKale commented 3 years ago

It turns out Chrome's virtual authenticator feature had a bug in it! They were explicitly defining this basicConstraint value (indicating the cert is not for a certificate authority) when, according to ASN.1 DER encoding rules, it should have been implicitly defined. The bug was logged and fixed here:

https://chromium-review.googlesource.com/c/chromium/src/+/2797998/

I pulled down the latest Chrome Canary v91 today and confirmed the issue no longer exists. This issue will eventually solve itself when this bugfix makes its way into Chrome GA.