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.61k stars 136 forks source link

Error in verifyAttestationResponse when using apple format and FaceID/TouchID sometimes not showing up #61

Closed P4sca1 closed 3 years ago

P4sca1 commented 4 years ago

There is an error thrown in verifyAssertionOptions when using apple FaceID to solve the attestation request.

Attestation options:

{
  challenge: 'VNT_3_E2tFGe4NUoLRdJhsztnVMbI_98Vr3GgMmRVlg',
  rp: { name: 'IPS Hosting', id: 'ips-hosting.eu.ngrok.io' },
  user: { id: '21', name: 'P4sca1', displayName: 'P4sca1' },
  pubKeyCredParams: [
    { alg: -7, type: 'public-key' },
    { alg: -8, type: 'public-key' },
    { alg: -36, type: 'public-key' },
    { alg: -37, type: 'public-key' },
    { alg: -38, type: 'public-key' },
    { alg: -39, type: 'public-key' },
    { alg: -257, type: 'public-key' },
    { alg: -258, type: 'public-key' },
    { alg: -259, type: 'public-key' }
  ],
  timeout: 60000,
  attestation: 'direct',
  excludeCredentials: [],
  authenticatorSelection: { userVerification: 'discouraged' },
  extensions: undefined
}

Attestation response (SimpleWebAuthn Debugger link)

{
  id: '24qeQ_g9SbjwmEdgagzhrzhN_DI',
  rawId: '24qeQ_g9SbjwmEdgagzhrzhN_DI',
  response: {
    attestationObject: 'o2NmbXRlYXBwbGVnYXR0U3RtdKJjYWxnJmN4NWOCWQJIMIICRDCCAcmgAwIBAgIGAXUUh_QAMAoGCCqGSM49BAMCMEgxHDAaBgNVBAMME0FwcGxlIFdlYkF1dGhuIENBIDExEzARBgNVBAoMCkFwcGxlIEluYy4xEzARBgNVBAgMCkNhbGlmb3JuaWEwHhcNMjAxMDA5MjIwMDU1WhcNMjAxMDEyMjIwMDU1WjCBkTFJMEcGA1UEAwxANjEyMTQyMmNmNWY1MWNhMWQ4NTIyZDEwZDlhYzY3OGYxZjNjNTRhYjBmZDk5M2ViZWI2NDI3NzY4NDY2NjNhNjEaMBgGA1UECwwRQUFBIENlcnRpZmljYXRpb24xEzARBgNVBAoMCkFwcGxlIEluYy4xEzARBgNVBAgMCkNhbGlmb3JuaWEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ7qQ-_z-C1n5CYXuYzYNrWt9NCPpfO2i7Kisiu-5IHwyFFwOTpEmCIoNvlHZnBnKeLmTJ8zQh85cv0gI7iKNRWo1UwUzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB_wQEAwIE8DAzBgkqhkiG92NkCAIEJjAkoSIEIO3z3p0sNCSsTheri1FqVoEfQ9uLJGXnsrfHile9fwgjMAoGCCqGSM49BAMCA2kAMGYCMQD6TBLDKVkZBicGfFjk44cq_ZbnaW9blEdt3w0Auk4RDDt4HCK70iQFg2_DbmSP3RECMQDJDtmxXuTM-RljP2H50AOAbLKbLvSQNMHLbEe9TqAQe1Yq-D0uqf_l5CuCE04pVJVZAjgwggI0MIIBuqADAgECAhBWJVOVx6f7QOviKNgmCFO2MAoGCCqGSM49BAMDMEsxHzAdBgNVBAMMFkFwcGxlIFdlYkF1dGhuIFJvb3QgQ0ExEzARBgNVBAoMCkFwcGxlIEluYy4xEzARBgNVBAgMCkNhbGlmb3JuaWEwHhcNMjAwMzE4MTgzODAxWhcNMzAwMzEzMDAwMDAwWjBIMRwwGgYDVQQDDBNBcHBsZSBXZWJBdXRobiBDQSAxMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEgy6HLyYUkYECJbn1_Na7Y3i19V8_ywRbxzWZNHX9VJBE35v-GSEXZcaaHdoFCzjUUINAGkNPsk0RLVbD4c-_y5iR_sBpYIG--Wy8d8iN3a9Gpa7h3VFbWvqrk76cCyaRo2YwZDASBgNVHRMBAf8ECDAGAQH_AgEAMB8GA1UdIwQYMBaAFCbXZNnFeMJaZ9Gn3msS0Btj8cbXMB0GA1UdDgQWBBTrroLE_6GsW1HUzyRhBQC-Y713iDAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIxAN2LGjSBpfrZ27TnZXuEHhRMJ7dbh2pBhsKxR1dQM3In7-VURX72SJUMYy5cSD5wwQIwLIpgRNwgH8_lm8NNKTDBSHhR2WDtanXx60rKvjjNJbiX0MgFvvDH94sHpXHG6A4HaGF1dGhEYXRhWJgBpwTFUgYt_G45iIlHM9dA5ir7lBILi7_AbJl0nYyG-UUAAAAAAAAAAAAAAAAAAAAAAAAAAAAU24qeQ_g9SbjwmEdgagzhrzhN_DKlAQIDJiABIVggO6kPv8_gtZ-QmF7mM2Da1rfTQj6XztouyorIrvuSB8MiWCAhRcDk6RJgiKDb5R2ZwZyni5kyfM0IfOXL9ICO4ijUVg',
    clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiVk5UXzNfRTJ0RkdlNE5Vb0xSZEpoc3p0blZNYklfOThWcjNHZ01tUlZsZyIsIm9yaWdpbiI6Imh0dHBzOi8vaXBzLWhvc3RpbmcuZXUubmdyb2suaW8ifQ'
  },
  type: 'public-key'
}

Error:

Error: Cannot get schema for 'Certificate' target
    at AsnSchemaStorage.get (/Users/pascal/code/ips-hosting/node_modules/@simplewebauthn/server/node_modules/@peculiar/asn1-schema/build/cjs/schema.js:17:19)
    at Function.fromASN (/Users/pascal/code/ips-hosting/node_modules/@simplewebauthn/server/node_modules/@peculiar/asn1-schema/build/cjs/parser.js:38:52)
    at Function.parse (/Users/pascal/code/ips-hosting/node_modules/@simplewebauthn/server/node_modules/@peculiar/asn1-schema/build/cjs/parser.js:28:26)
    at Object.verifyApple [as default] (/Users/pascal/code/ips-hosting/node_modules/@simplewebauthn/server/src/attestation/verifications/verifyApple.ts:40:36)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at Object.verifyAttestationResponse (/Users/pascal/code/ips-hosting/node_modules/@simplewebauthn/server/src/attestation/verifyAttestationResponse.ts:198:16)
    at Function.verifyAttestationResponse (/Users/pascal/code/ips-hosting/apps/api/src/controllers/auth/two-step-verification/web-authn.ts:72:47)
    at /Users/pascal/code/ips-hosting/apps/api/src/router/auth/two-step-verifiation/web-authn.ts:85:24

Also I noticed that you need to start the attestation 2 times to be able to use FaceID. In the first attempt, Safari only asks for a security key. Only when you cancel and restart the attestation, you can select from security key and FaceID. I don`t know whether this is an issue with the attestation options or with Safari.

MasterKale commented 4 years ago

At first blush, userVerification: 'discouraged' may not work with FaceID since it's a user-verifying authenticator by design. I'll investigate further but in the meantime can you try attestation without that option?

MasterKale commented 4 years ago

Hmm, I'm having trouble reproducing this on my end. I duplicated your exact attestation options via the example server I provide in this monorepo with server@0.10.1, but everything is working as expected. Safari prompted for Face ID on the first registration attempt, and the attestation verified correctly:

IMG_0793

On a lark I tried downgrading to server@0.10.0 and it errored out as expected (this is what prompted the release of v0.10.1):

IMG_0792

There's one more thing I can try...

MasterKale commented 4 years ago

I have no idea what's going on. I tried installing v0.10.0, confirmed it was broken, then upgraded in-place to v0.10.1. After upgrading (previously I had been running rm -rf node_modules before trying installing either version), attestation verification for Face ID worked no problem. I have never experienced Safari requiring me to initiate attestation twice, either, so I have no advice for that problem.

Can you try clearing out node_modules, re-running npm install, then retry attestation? Maybe you're suffering from JS package management oddities 😅

P4sca1 commented 4 years ago

Also I noticed that you need to start the attestation 2 times to be able to use FaceID. In the first attempt, Safari only asks for a security key. Only when you cancel and restart the attestation, you can select from security key and FaceID. I don`t know whether this is an issue with the attestation options or with Safari.

This issue can be fixed by not using userVerification: 'discouraged'. The problem is that I dont want YubiKeys to ask for a pin, because WebAuthn is a second factor in my authentication flow. Requiring a pin would result in 3 factors being required (password, physical key and pin), which would be too much. Do you know a solution to this problem?

Turning userVerification back on does not fix the error. I am using @simplewebauthn/server version 0.10.1:

"@simplewebauthn/server@0.10.1":
  version "0.10.1"
  resolved "https://registry.yarnpkg.com/@simplewebauthn/server/-/server-0.10.1.tgz#b31c8f9a0c74be43113b5fc7ae691b743301b11e"
  integrity sha512-f0SZ/pRU+MyjLlLmY8epo+F5YFgSyMkyhRUZKxErkDrcpnOF5x3eFFkz0XKLFsqApUK4K/aqcs6k3VtRPhZTuA==
  dependencies:
    "@peculiar/asn1-android" "2.0.8"
    "@peculiar/asn1-schema" "2.0.8"
    "@peculiar/asn1-x509" "2.0.10"
    "@simplewebauthn/typescript-types" "^0.10.0"
    base64url "3.0.1"
    cbor "5.0.2"
    elliptic "6.5.3"
    jsrsasign "8.0.20"
    jwk-to-pem "2.0.4"
    node-fetch "2.6.0"
    node-rsa "1.1.1"

iOS Version: 14.0.1 (iPhone XR)

madwizard-thomas commented 4 years ago

For face/touch ID to show up in the dialog, the webauthn create/get methods need to be called in a handler that is user initiated, e.g. in a click handler. If you call these methods automatically (on load) it will only show the security key option.

P4sca1 commented 4 years ago

Thanks for the info, that’s good to know. I call them inside a vue @click handler. It also does not show up in the list when you discourage user verification.

P4sca1 commented 4 years ago

It also does not show up in the list when you discourage user verification.

This assumption was wrong. I have set userVerification: 'discouraged' and it shows FaceID everytime. The issue was that I was using the vue @click handler on my button and it seems like Safari was not always considering this as a user action. Changing the listener to @click.native fixes the issue. Thanks for giving the hint @madwizard-thomas.

P4sca1 commented 4 years ago

Using TouchID on iPad 6 (2018) or FaceID on iPhone xR both result in the error Cannot get schema for 'Certificate' target. However I can confirm that it works fine with the example project in this repo. I will continue to find out what causes the issue in my codebase and get back here.

P4sca1 commented 4 years ago

Another reason why FaceID was not showing up in the list was because Apple does not support async event handlers completely. They added support for asynx XHR / fetch requests in the listener though. More details can be found here: https://bugs.webkit.org/show_bug.cgi?id=213595 Because of that you cannot await promises other than XHR / fetch requests in the button event listener. I was using dynamic imports to only load @simplewebauthn/browser when the button was clicked which caused Sign in with FaceID to only show up in the list after the 2nd time the button was pressed (as the import is no longer async then, because it has already been loaded).

P4sca1 commented 4 years ago

After hours of debugging @MasterKale and I figured out that the root cause of the issue is using the yarn package manager instead of npm. This is because @simplewebauthn/server requires @peculiar/asn1-schema version 2.0.8 while @peculiar/asn1-x509 (which is also a dependency of @simplewebauthn/server) uses version ^2.0.8 (2.0.23 as of now). Those 2 versions seem to be incompatible. The npm and yarn resolution algorithms differ in some way that causes this issue. A temporary fix is to add a yarn resolution.

So to sum things up

Issue 1 (Error: Cannot get schema for 'Certificate' target)

This is a dependency issue when using the yarn package manager. For a temporary fix, add the following to your package.json and then run yarn.

"resolutions": {
  "@peculiar/asn1-schema": "2.0.8"
},

Issue 2 (FaceID / TouchID not showing up in list)

Maybe it is worth adding those hints to the docs? @MasterKale

MasterKale commented 4 years ago

I don't use Yarn myself so this was certainly an interesting error to debug.

Regarding the "resolutions" fix, I'm trying to figure out how to handle this in a dev-friendly manner. From what I'm reading on https://classic.yarnpkg.com/en/docs/selective-version-resolutions/#toc-limitations-Caveats, resolutions need to be declared in the root-level package.json and such declarations in third-party packages may not be respected:

  • Nested packages may not work properly.

So maybe this becomes a documentation update? I'm still investigating.

As for the Safari issues, that knowledge can probably be captured in the docs site as you suggested @P4sca1. I'll start drafting something.

MasterKale commented 4 years ago

Issue 1 should be fixed with the new server@0.10.2 I just published. I went ahead and updated the ASN.1 parsing libraries so everything is using the same version, sub-dependencies included. No one should have to add "resolutions" to their Yarn projects (for now).

Issue 2 will be addressed with an eventual docs update to the homepage.

MasterKale commented 4 years ago

The Safari-specific gotchas captured in @P4sca1's Issue 2 have been captured here: https://simplewebauthn.dev/docs/advanced/safari-browser

P4sca1 commented 4 years ago

Thanks! Great new docs by the way :)

Ponjimon commented 3 years ago

https://github.com/MasterKale/SimpleWebAuthn/pull/62#issuecomment-707351356

Unfortunately, this happened again. I'm getting the issue 1 error again, but I was able to solve it by adding a resolution and force it to install @peculiar/asn1-schema@2.0.26

MasterKale commented 3 years ago

@Ponjimon PR #68 restored the use of carets in versions in server's package.json, which means future versions of the asn1- packages should now get updates without me having to update server . I haven't cut a release with that fix, though - once #67 gets in I'll publish a new release to NPM.

MasterKale commented 3 years ago

@Ponjimon (and maybe @P4sca1 too) I just published @simplewebauthn/server@v0.10.4 that un-pins its dependencies including the @peculiar/asn1- packages. This should allow your projects to pick up the latest versions of these packages:

"@peculiar/asn1-android": "^2.0.26",
"@peculiar/asn1-schema": "^2.0.26",
"@peculiar/asn1-x509": "^2.0.26",

Can you try out your projects with this latest release and see if this more completely resolves Issue 1 without needing to resort to "resolutions"?

MasterKale commented 3 years ago

I'm assuming no news is good news so I'm closing this issue.

P4sca1 commented 3 years ago

Sorry, didn’t had time to test this. I will open a new issue if the issue occurs again. Thanks for your effort!