2

I am playing with a YubiKey and JavaScript in-browser WebAuthn APIs. I am trying a very minimal "Hello, World!" example which just tries to do a minimal: navigator.credentials.create and then a navigator.credentials.get (with minimal, even hard-coded values to just demonstration.

The create works fine - but the get always results in an error:

This security key doesn't look familiar.

I am having a hard time understanding what even theoretically might cause this. For example, to my knowledge the YubiKey doesn't actually store credentials on it - but rather requires the server to send back an encrypted opaque bundle containing the key.

But the get API only requires a cryptographic challenge. (I think this is just random data from the server, and not the encrypted key?) (I am basically sending all zeros for the challenge, for now).

Examples show the allowCredentails (which is an optional field) sending one (or more) ID's back. It make sense that if the IDs themselves were the encrypted keys, it should use those. (But they're again optional) and I still get this error even if I specify the same Id (in a ByteArray) which was returned from the create, or if I give NO Id's whatsoever.

So what could the problem be? Is it that I'm supposed to be sending something with the challenge? Is my id requried, but perhaps malformed? I've noticed other examples sending many allowCredential IDs (I have no idea where these are coming from, because only one matches the one from it's original enrollment).

Is there something I am fundamentally missing here?

Brad
  • 11,262
  • 8
  • 55
  • 74
  • 1
    Can you include some code samples? It'd be useful to see in particular what you're passing to `navigator.credentials.get()` – IAmKale Jul 22 '22 at 16:09
  • @IAmKale I got past that - will post answer - but now having problems in Duo webauthn golang server code ;-) – Brad Jul 25 '22 at 13:04

1 Answers1

1

The answer appears to be (from the best I could resolve):

Yubikey does not store credentials, so the ID (passed back from the server during login) must encode the (encrypted private key) credentials - to be handed back to they authenticator (Yubikey) itself. If this isn't done (correctly) you will get an error saying the key is not recognized. Since the spec allows for you to pass no allowCredentials back in the get (login) phase - I would assume this means there may be a facility for an authenticator to store a key on it - though this is not commonly done, (or by Yubikey)?

Either way - in my case, the ID must be passed back, and correctly. My particular issue was that the ID returned during create is expressed as string - which is kind of base64 encoded, but has some oddities in the encoding - and when I was converting it back to an ArrayBuffer for the get - I didn't get it exactly right.

The nonstandard base64 format needs some characters to be replaced before the base64 conversion:

thing = thing.replace(/-/g, "+").replace(/_/g, "/");

Brad
  • 11,262
  • 8
  • 55
  • 74
  • 1
    The "nonstandard base64" that WebAuthn uses is called Base64URL - see the first item on https://www.w3.org/TR/webauthn-2/#sctn-dependencies – IAmKale Jul 25 '22 at 14:31
  • 1
    Here's more info on it if you're interested https://datatracker.ietf.org/doc/html/rfc4648#section-5 – IAmKale Jul 25 '22 at 14:36