kanidm / webauthn-rs

An implementation of webauthn components for Rustlang servers
Mozilla Public License 2.0
483 stars 80 forks source link

Question or help request - javascript client fails finishing register #344

Closed flarocca closed 1 year ago

flarocca commented 1 year ago

I am having some issues working with a standard JS implementation using the server provided in the tutorials. Everything works if I use the wasm example, but when I use a plain JS implementation it fails. Seems to be a serialization issue between the server and the client, but I am not being able to understand why, that's the reason I am asking for help.

It is failing at the register_finish with MismatchedChallenge. The thing is that, the challenge that it is being sent from the server is different from what it is being deserialized at the client side. For example, if I do println!("ccr: {:?}", ccr); just right after start_register finishes, this is what I see as challenge:

[137, 199, 17, 95, 74, 155, 2, 72, 40, 20, 32, 217, 48, 209, 182, 17, 69, 44, 11, 156, 43, 242, 55, 180, 133, 176, 91, 101, 172, 139, 248, 13]

However, If I just console.log the exact same response in the client side, this is what I see:

[67, 117, 67, 85, 83, 85, 89, 75, 112, 117, 45, 107, 54, 45, 98, 111, 72, 74, 115, 104, 72, 111, 87, 52, 51, 110, 122, 112, 80, 104, 107, 45, 45, 68, 95, 68, 121, 117, 73, 57, 110, 55, 107]

This is the request I am doing on the client side:

fetch(`http://localhost:8080/register_start/example`, {
        method: "POST",
        credentials: 'include',
        body: null
    })
    .then(response => {
        return response.json();
    })
    .then(json_response => {
        // All Uint8Array items differ from what was sent from the server
        console.log("json_response", json_response);

        return json_response;
    })
   //... snip...

What I am missing? Thanks

Firstyear commented 1 year ago

Are you base64 decoding the challenge / uint8array types? That would be the first thing I can think of. There are a number of values in webauthn that can't be turned into json directly because you can't go from json -> uint8array directly, so you have to fudge with them internally (it's a huge oversight in the actual webauthn spec that you have to always alter/modify the content of the requests in js).

flarocca commented 1 year ago

Hey! Thank you very mich for taking the time to respond. I really appreciate it. As you are saying, that was the case. After a couple of hours of deep debuging I realized that the standard respnse.json() was not correctly handling (If I am not wrong due to the URL_SAFE option from the rust side. I ended up getting the the raw contents and parsing it manually.

Thank you so much.

Firstyear commented 1 year ago

No problem! It's a huge gotcha, and a massive flaw in the webauthn specification but when I raised it early in the spec life it was ignored :(

Anyway, it's a trap I have seen many people fall into. If you have any other issues please let us know, we are always happy to help :)