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!