Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need help at the verify_authentication_response() function #208

Open
Satistile opened this issue Mar 16, 2024 · 9 comments
Open

Need help at the verify_authentication_response() function #208

Satistile opened this issue Mar 16, 2024 · 9 comments

Comments

@Satistile
Copy link

Satistile commented Mar 16, 2024

I currently try to implement the py_webauthn library in a little test project, but currently the verify_authentication_response() function seems to not work correctly.

Here's my code (I currently work with flask):

def verify_authentication_response_func(request):
    content_type = request.headers.get('Content-Type')
    if content_type == 'application/json':
        request_json = request.json

        # get user id from client json and prepare payload for processing
        logged_in_user_id = request_json['id']
        request_payload_object = json.loads(base64url_to_string(request_json['payload']))

        # get current challenge and public key from user
        current_challenge = base64url_to_bytes(db_calls.get_challenge(logged_in_user_id))
        pub_key = base64url_to_bytes(db_calls.get_key(logged_in_user_id))

        print(pub_key)

        try:
            credential = request_payload_object
            verification = verify_authentication_response(
                credential=credential,
                expected_challenge=current_challenge,
                expected_rp_id="localhost",
                expected_origin="http://localhost:63343",
                credential_public_key=pub_key,
                credential_current_sign_count=0,
                require_user_verification=True,
            )
        except Exception as err:
            db_calls.delete_challenge(logged_in_user_id)
            return {"verified": False, "msg": str(err), "status": 400}

        db_calls.delete_challenge(logged_in_user_id)

        return {"verified": True}
    else:
        return 'Content-Type not supported!'

And here's the replied JSON from it: {"msg":"'int' object is not subscriptable","status":400,"verified":false}

The error seems to occour while the processing of the public key. And this is the point, where I don't get what's wrong. After the registration process is completed, I save the public key directly in my database. The public key is send directly from the client, where the @simplewebauthn/browser framework had processed the options and replied the public key as a base64url string.

I currently still don't know if this is my error or an error in the library. Thanks in advance for helping!

Edit:
Here's the complete traceback:

[2024-03-20 21:47:24,264] ERROR in app: Exception on /verify-authentication-response [POST]                                                  
Traceback (most recent call last):                                                                                                           
  File "E:\jetbrains-projekte\passkey test py\passkey test py\.venv\Lib\site-packages\flask\app.py", line 1463, in wsgi_app                  
    response = self.full_dispatch_request()                                                                                                  
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                  
  File "E:\jetbrains-projekte\passkey test py\passkey test py\.venv\Lib\site-packages\flask\app.py", line 872, in full_dispatch_request      
    rv = self.handle_user_exception(e)                                                                                                       
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                       
  File "E:\jetbrains-projekte\passkey test py\passkey test py\.venv\Lib\site-packages\flask_cors\extension.py", line 176, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
                                                ^^^^^^^^^^^^^^^^^^
  File "E:\jetbrains-projekte\passkey test py\passkey test py\.venv\Lib\site-packages\flask\app.py", line 870, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "E:\jetbrains-projekte\passkey test py\passkey test py\.venv\Lib\site-packages\flask\app.py", line 855, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "E:\jetbrains-projekte\passkey test py\passkey test py\.venv\Lib\site-packages\flask_cors\decorator.py", line 130, in wrapped_function
    resp = make_response(f(*args, **kwargs))
                         ^^^^^^^^^^^^^^^^^^
  File "E:\jetbrains-projekte\passkey test py\passkey test py\app.py", line 45, in verify_authentication_response_route
    return verify_authentication_response_func(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "E:\jetbrains-projekte\passkey test py\passkey test py\processes\authentication_functions.py", line 65, in verify_authentication_response_func
    verification = verify_authentication_response(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "E:\jetbrains-projekte\passkey test py\passkey test py\.venv\Lib\site-packages\webauthn\authentication\verify_authentication_response.py", line 164, in verify_authentication_response
    decoded_public_key = decode_credential_public_key(credential_public_key)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "E:\jetbrains-projekte\passkey test py\passkey test py\.venv\Lib\site-packages\webauthn\helpers\decode_credential_public_key.py", line 62, in decode_credential_public_key
    kty = decoded_key[COSEKey.KTY]
          ~~~~~~~~~~~^^^^^^^^^^^^^
TypeError: 'int' object is not subscriptable
127.0.0.1 - - [20/Mar/2024 21:47:24] "POST /verify-authentication-response HTTP/1.1" 500 -

@Satistile Satistile changed the title Needed help at the verify_authentication_response() function Need help at the verify_authentication_response() function Mar 16, 2024
@MasterKale
Copy link
Collaborator

Hello @Satistile, what's the base64url value of pub_key coming out of db_calls.get_key(logged_in_user_id)? Sharing that might help troubleshoot what's going on here.

@Satistile
Copy link
Author

The pub_key variable corresponds to the response.publicKey variable in the JSON object returned by the @simplewebauthn/browser library when calling the startRegistration() function. This value is already encoded in base64url by the library and theoraticly I just have to decode this in my python backend. As far as I got with debugging, I can say for sure that my encoding and decoding functions for base64url are working as intended.

@MasterKale
Copy link
Collaborator

Without a sample value for pub_key I can't assist in troubleshooting any further. Please feel free to reopen this issue if you are able to provide such a value.

@MasterKale MasterKale closed this as not planned Won't fix, can't repro, duplicate, stale Mar 27, 2024
@Satistile
Copy link
Author

A sample value for the pub_key would be MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8APYzNW_OkIzf8cizuNiwqMJhk8IqIxCiVdjlxUulYH0fpTdr0W46fI89XooslN8r1V4Vu1DrUcdc1vHGnHB0g

@MasterKale MasterKale reopened this Mar 27, 2024
@MasterKale
Copy link
Collaborator

MasterKale commented Mar 28, 2024

This is bizarre, that pub_key is the following hex:

3059301306072a8648ce3d020106082a8648ce3d03010703420004f003d8ccd5bf3a42337fc722cee362c2a309864f08a88c4289576397152e9581f47e94ddaf45b8e9f23cf57a28b2537caf557856ed43ad471d735bc71a71c1d2

When I drop that hex into https://cbor.me the site says the bytes are "the value -17", with "90 unused bytes after the end of the data item":

Screenshot 2024-03-28 at 12 34 42 PM

So this is telling me that there's something potentially misbehaving with the browser and/or authenticator, before @simplewebauthn/browser base64url-encodes the output from WebAuthn's response.getPublicKey()...

@Satistile What OS, browser, their versions, and authenticator are you attempting to support here? Might as well let me know what version of @simplewebauthn/browser you're using too (I doubt it's the culprit but just to be safe.)

@Satistile
Copy link
Author

I don't actually know the version of my @simplewebauthn/browser, but I use it in my website with the recommended way without typescript (<script src="https://unpkg.com/@simplewebauthn/browser/dist/bundle/index.umd.min.js"></script>). The site currently runs on Windows 10 pro 22h2 and I use it with Microsoft Edge V. 123.0.2420.65. I've used the Windows Hello authenticator and the authenticator build in into IOS 17.4.1. The error occured while using both authenticators. But on other websites like google.com and icloud.com aren't any problems.

I hope these informations are helpful.

@Satistile
Copy link
Author

Maybe it's also helpful to know, that the registration process don't throws any errors and runs without any problems.

@Satistile
Copy link
Author

I've thought a bit about the issue, and came to the conclusion that the error might have happened while the storing process of the public key.

Corresponding code:

def verify_registration_response_func(request):
    content_type = request.headers.get('Content-Type')
    if content_type == 'application/json':
        request_json = request.json

        # get user id from client json and prepare payload for processing
        logged_in_user_id = request_json['id']
        request_payload_object = json.loads(base64url_to_string(request_json['payload']))

        # get current challenge from user
        current_challenge = base64url_to_bytes(db_calls.get_challenge(logged_in_user_id))

        # verify challenge
        try:
            credential = request_payload_object
            verification = verify_registration_response(
                credential=credential,
                expected_challenge=current_challenge,
                expected_rp_id="localhost",
                expected_origin="http://localhost:63342",
                require_user_verification=True,
            )
        except Exception as err:
            db_calls.delete_challenge(logged_in_user_id)
            return {"verified": False, "msg": str(err), "status": 400}

        # remove challenge from database and add public key to db
        db_calls.delete_challenge(logged_in_user_id)
        db_calls.add_key(logged_in_user_id, credential["response"]["publicKey"])

        return {"verified": True}
    else:
        return 'Content-Type not supported!'

I hope that this might help a bit

@Satistile
Copy link
Author

Oh this was a mistake, sorry

@Satistile Satistile reopened this May 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants