Yubico / python-fido2

Provides library functionality for FIDO 2.0, including communication with a device over USB.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

crossOrigin vs cross_origin in authenticatorData serialization

prateeknischal opened this issue · comments

It seems that the JSON serialized version of the authenticatorData field in the repsonse of a get_assertion call uses cross_origin instead of crossOrigin which seems to be the case for every other client. The spec has the key named as crossOrigin. Could this be a potential issue.

I am trying to generate the assertions using the Fido2Client and for some unknown reason, the assertions aren't accepted by a FIDO2 server which works just fine with the browser implementation of the operations. I tried changing the key just in the webauthn.py#L374 but it did not help so I am not sure what the issue could be.

This does indeed look like a bug in the library that we need to fix. However, it's difficult to say if that is what is causing the problem you're seeing or not. Since you already tried changing the string in webauthn.py I would say that points to the problem being something else. Does the server provide any indicator to why it isn't accepting the assertion?

The same, I am not able to verify if the serialization is the problem. However, that was the only place I changed the key. I saw some handlers which were taking care of converting the snake case into camel case, so I am not sure that cosmetic fix would have solved the problem.

The server does not indicate any problem apart from throwing a opaque ChallengeVerificationError. The server is a hosted private server and I can't debug it. I know for sure though it's using the webauthn-ruby library for processing the webauthn request.

I am yet to swap out the server to make sure it isn't something on the server side. The next step would be to use libfido2 to generate the assertion.

I've addressed the cross_origin case issue in b674c2b at least, even if we don't know what is causing the issue here.

I tried using this commit, no luck..! :(
Mystery deepens. For some reason, it works just fine with the libfido2 implementation. Thank you for taking a look into this! I will spend some more time on this and try and figure out what's the delta.

So, We finally ported the implementation to libfido2 and it works with the webauthn server which is strange. To be honest I haven't been able to figure out the difference. Semantically the payload looks the same, I haven't had enough time to go deeper but I will still give it a go as soon as I find enough concentration.

Very strange indeed. If you'd be willing to post the two payloads here I could take a look as well, see if I see anything.

The payload generated from python-fido2 (doesn't work)

{
  "id": "pRzZEQAirW_1xuhzt6RBun_EG5288P8le9VznqinqG0o2ZGogqjTAREP-C4itXR9",
  "type": "public-key",
  "response": {
    "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiVmhzSGxHNlpleHJNa3QtOTlmamx3bUl2ZGFsdnU5amtXbHhybjJmZUNlQSIsIm9yaWdpbiI6Imh0dHBzOi8vbWlkd2F5LWF1dGguYW1hem9uLmNvbSIsImNyb3NzT3JpZ2luIjpmYWxzZX0",
    "authenticatorData": "rM9dRu45NrZlVVA9BUip_LY5AfXutTVHx9xZzyoxyqwBAAABLQ",
    "signature": "MEUCIQCvLeReAYgtOudr8tXtS3ulOO2EYzQcc-Lq-qU7IlSssAIgKIJfLxi306jZ8exZ4iv1RbpaBedSjK9WTI326okTUZY",
    "userHandle": ""
  }
}

The source that generates the above assertion assert.py

The payload generated from libfido2 (works)

{
  "id": "pRzZEQAirW_1xuhzt6RBun_EG5288P8le9VznqinqG0o2ZGogqjTAREP-C4itXR9",
  "response": {
    "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoicS1iSWJDRm5qMVMyaUlCOU1WUUd0dDVvVnB6S2tkXzg0eThvSnloYThDNCIsIm9yaWdpbiI6Imh0dHBzOi8vbWlkd2F5LWF1dGguYW1hem9uLmNvbSIsImNyb3NzT3JpZ2luIjpmYWxzZX0",
    "signature": "MEUCIQCkeKvOncGh3ftmtCiA18PTBimLQmJA8ELd787clSlijQIgJP6N9pqz0fY3JV2E1pRir4y3k8-29mmi9J5hJoU_bHs",
    "authenticatorData": "rM9dRu45NrZlVVA9BUip_LY5AfXutTVHx9xZzyoxyqwFAAABMA",
    "userHandle": "",
    "clientExtensionResults": {
      "appid": false
    }
  }
}

Note: Please ignore the appid extension. That's to identify u2f vs fido2
authenticators and I have inspected the code, it's not relevant for a fido2
challenge verification.

Side Note: I just noticed that we are not adding type as public-key in the libfido2 payload which is the only supported type right now, but the server is not complaining, so I guess that's not the reason.

I don't see anything that looks out of the ordinary in either response either. Very weird. Since the error is a ChallengeVerificationError, is there any chance the challenge gets somehow modified in the construction of the ClientDataJSON?

These payload dumps are right before the client (curl vs libcurl) encodes them to application/x-www-form-urlencoded and sends it to the server, so I doubt there would be any modifications to how clientDataJSON.

curl --cookie /tmp/session https://rpId-response-endpoint \
    --data-urlencode "type=webauthn" \
    --data-urlencode "response=$ASSERTION" \
    -s -H "Content-type: application/x-www-form-urlencoded"

Where ASSERTION is the compacted JSON dump of the assertion. I have tried looking in case bash was doing something funky, but It did not.. I tried intercepting the payload using a netcat server locally and the form encoded payload looked correct to me. I was able to decode it using urllib.parse.unquote, websafe_decode and then json.loads

This is the raw http dump from the above curl.

POST / HTTP/1.1
Host: localhost:9000
User-Agent: curl/7.79.1
Accept: */*
Content-type: application/x-www-form-urlencoded
Content-Length: 636

type=webauthn&response=%7B%22id%22%3A+%22pRzZEQAirW_1xuhzt6RBun_EG5288P8le9VznqinqG0o2ZGogqjTAREP-C4itXR9%22%2C+%22type%22%3A+%22public-key%22%2C+%22response%22%3A+%7B%22authenticatorData%22%3A+%22rM9dRu45NrZlVVA9BUip_LY5AfXutTVHx9xZzyoxyqwBAAABNA%22%2C+%22clientDataJSON%22%3A+%22eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiZWtvOVFLcUQtVFBmckRVWmdnNGxoRnZLOUo4aW4yeWVwQ1l5d2tBVzEtOCIsIm9yaWdpbiI6Imh0dHBzOi8vbWlkd2F5LWF1dGguYW1hem9uLmNvbSIsImNyb3NzT3JpZ2luIjpmYWxzZX0%22%2C+%22signature%22%3A+%22MEYCIQDXtQcbaIRYsA8kv-IADq57yKjbk206BHjn2RUWkvfuDAIhANd4Yf-q9z2scbaAJMekuImkx5a_5eeKxAo3WQznzDJd%22%2C+%22userHandle%22%3A+%22%22%7D%7D

Finally found the issue, it's not related to the python-fido2 library. The server was selecting the incorrect challenge to verify. The old client has the same incorrect challenge selection, so it never broke and we never found the issue. I have verified that using the same old faulty challenge selection, the python-fido2 library works as expected!

Finally answer to this question.

Ah, thanks for reporting back with the cause!