We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
2FA: Enrolling a TouchID sensor as a webauthn security key fails (Chrome, Mac)
<!--
    NOTE: This issue should be for problems with PyPI itself, including:
    * pypi.org
    * test.pypi.org
    * files.pythonhosted.org

    This issue should NOT be for a project installed from PyPI. If you are
    having an issue with a specific package, you should reach out to the
    maintainers of that project directly instead.

    Furthermore, this issue should NOT be for any non-PyPI properties (like
    python.org, docs.python.org, etc.)
-->

**Describe the bug**
I'm trying to enroll a TouchID sensor as a webauthn device. PyPI and Chrome do let me select the sensor, and I do get prompted for a touch, but then PyPI throws an error: "Registration rejected. Error: Self attestation is not permitted.."

**Expected behavior**
I expect to be able to enroll a TouchID sensor. 

**To Reproduce**
- PyPI --> Account Settings
- Click "Add 2FA With Security Key"
- Type a key name, click "Provision Key"
- Chrome prompts to choose between a USB security key and a built-in sensor. Choose "Built-in sensor"
- MacOS prompts to hit the TouchID sensor. Do so.
- Chrome prompts, "Allow this site to see your security key?" Click "Allow"
- PyPI displays an error: "Registration rejected. Error: Self attestation is not permitted.."

**My Platform**
- MacOS 10.14.5
- MacBook Air (2018 edition, with TouchID)
- Chrome "75.0.3770.100 (Official Build) (64-bit)"


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `warehouse/utils/webauthn.py`
Content:
```
1 # Licensed under the Apache License, Version 2.0 (the "License");
2 # you may not use this file except in compliance with the License.
3 # You may obtain a copy of the License at
4 #
5 # http://www.apache.org/licenses/LICENSE-2.0
6 #
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS,
9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 # See the License for the specific language governing permissions and
11 # limitations under the License.
12 
13 import base64
14 import os
15 
16 import webauthn as pywebauthn
17 
18 from webauthn.webauthn import (
19     AuthenticationRejectedException as _AuthenticationRejectedException,
20     RegistrationRejectedException as _RegistrationRejectedException,
21 )
22 
23 
24 class AuthenticationRejectedException(Exception):
25     pass
26 
27 
28 class RegistrationRejectedException(Exception):
29     pass
30 
31 
32 WebAuthnCredential = pywebauthn.WebAuthnCredential
33 
34 
35 def _get_webauthn_users(user, *, icon_url, rp_id):
36     """
37     Returns a webauthn.WebAuthnUser instance corresponding
38     to the given user model, with properties suitable for
39     usage within the webauthn API.
40     """
41     return [
42         pywebauthn.WebAuthnUser(
43             str(user.id),
44             user.username,
45             user.name,
46             icon_url,
47             credential.credential_id,
48             credential.public_key,
49             credential.sign_count,
50             rp_id,
51         )
52         for credential in user.webauthn
53     ]
54 
55 
56 def _webauthn_b64decode(encoded):
57     padding = "=" * (len(encoded) % 4)
58     return base64.urlsafe_b64decode(encoded + padding)
59 
60 
61 def _webauthn_b64encode(source):
62     return base64.urlsafe_b64encode(source).rstrip(b"=")
63 
64 
65 def generate_webauthn_challenge():
66     """
67     Returns a random challenge suitable for use within
68     Webauthn's credential and configuration option objects.
69 
70     See: https://w3c.github.io/webauthn/#cryptographic-challenges
71     """
72     # NOTE: Webauthn recommends at least 16 bytes of entropy,
73     # we go with 32 because it doesn't cost us anything.
74     return _webauthn_b64encode(os.urandom(32)).decode()
75 
76 
77 def get_credential_options(user, *, challenge, rp_name, rp_id, icon_url):
78     """
79     Returns a dictionary of options for credential creation
80     on the client side.
81     """
82     options = pywebauthn.WebAuthnMakeCredentialOptions(
83         challenge, rp_name, rp_id, str(user.id), user.username, user.name, icon_url
84     )
85 
86     return options.registration_dict
87 
88 
89 def get_assertion_options(user, *, challenge, icon_url, rp_id):
90     """
91     Returns a dictionary of options for assertion retrieval
92     on the client side.
93     """
94     options = pywebauthn.WebAuthnAssertionOptions(
95         _get_webauthn_users(user, icon_url=icon_url, rp_id=rp_id), challenge
96     )
97 
98     return options.assertion_dict
99 
100 
101 def verify_registration_response(response, challenge, *, rp_id, origin):
102     """
103     Validates the challenge and attestation information
104     sent from the client during device registration.
105 
106     Returns a WebAuthnCredential on success.
107     Raises RegistrationRejectedException on failire.
108     """
109     # NOTE: We re-encode the challenge below, because our
110     # response's clientData.challenge is encoded twice:
111     # first for the entire clientData payload, and then again
112     # for the individual challenge.
113     response = pywebauthn.WebAuthnRegistrationResponse(
114         rp_id, origin, response, _webauthn_b64encode(challenge.encode()).decode()
115     )
116     try:
117         return response.verify()
118     except _RegistrationRejectedException as e:
119         raise RegistrationRejectedException(str(e))
120 
121 
122 def verify_assertion_response(assertion, *, challenge, user, origin, icon_url, rp_id):
123     """
124     Validates the challenge and assertion information
125     sent from the client during authentication.
126 
127     Returns an updated signage count on success.
128     Raises AuthenticationRejectedException on failure.
129     """
130     webauthn_users = _get_webauthn_users(user, icon_url=icon_url, rp_id=rp_id)
131     cred_ids = [cred.credential_id for cred in webauthn_users]
132 
133     for webauthn_user in webauthn_users:
134         response = pywebauthn.WebAuthnAssertionResponse(
135             webauthn_user,
136             assertion,
137             _webauthn_b64encode(challenge.encode()).decode(),
138             origin,
139             allow_credentials=cred_ids,
140         )
141         try:
142             return (webauthn_user.credential_id, response.verify())
143         except _AuthenticationRejectedException:
144             pass
145 
146     # If we exit the loop, then we've failed to verify the assertion against
147     # any of the user's WebAuthn credentials. Fail.
148     raise AuthenticationRejectedException("Invalid WebAuthn credential")
149
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/warehouse/utils/webauthn.py b/warehouse/utils/webauthn.py
--- a/warehouse/utils/webauthn.py
+++ b/warehouse/utils/webauthn.py
@@ -110,8 +110,9 @@
     # response's clientData.challenge is encoded twice:
     # first for the entire clientData payload, and then again
     # for the individual challenge.
+    encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()
     response = pywebauthn.WebAuthnRegistrationResponse(
-        rp_id, origin, response, _webauthn_b64encode(challenge.encode()).decode()
+        rp_id, origin, response, encoded_challenge, self_attestation_permitted=True
     )
     try:
         return response.verify()
@@ -129,12 +130,13 @@
     """
     webauthn_users = _get_webauthn_users(user, icon_url=icon_url, rp_id=rp_id)
     cred_ids = [cred.credential_id for cred in webauthn_users]
+    encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()
 
     for webauthn_user in webauthn_users:
         response = pywebauthn.WebAuthnAssertionResponse(
             webauthn_user,
             assertion,
-            _webauthn_b64encode(challenge.encode()).decode(),
+            encoded_challenge,
             origin,
             allow_credentials=cred_ids,
         )

{"golden_diff": "diff --git a/warehouse/utils/webauthn.py b/warehouse/utils/webauthn.py\n--- a/warehouse/utils/webauthn.py\n+++ b/warehouse/utils/webauthn.py\n@@ -110,8 +110,9 @@\n     # response's clientData.challenge is encoded twice:\n     # first for the entire clientData payload, and then again\n     # for the individual challenge.\n+    encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()\n     response = pywebauthn.WebAuthnRegistrationResponse(\n-        rp_id, origin, response, _webauthn_b64encode(challenge.encode()).decode()\n+        rp_id, origin, response, encoded_challenge, self_attestation_permitted=True\n     )\n     try:\n         return response.verify()\n@@ -129,12 +130,13 @@\n     \"\"\"\n     webauthn_users = _get_webauthn_users(user, icon_url=icon_url, rp_id=rp_id)\n     cred_ids = [cred.credential_id for cred in webauthn_users]\n+    encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()\n \n     for webauthn_user in webauthn_users:\n         response = pywebauthn.WebAuthnAssertionResponse(\n             webauthn_user,\n             assertion,\n-            _webauthn_b64encode(challenge.encode()).decode(),\n+            encoded_challenge,\n             origin,\n             allow_credentials=cred_ids,\n         )\n", "issue": "2FA: Enrolling a TouchID sensor as a webauthn security key fails (Chrome, Mac)\n<!--\r\n    NOTE: This issue should be for problems with PyPI itself, including:\r\n    * pypi.org\r\n    * test.pypi.org\r\n    * files.pythonhosted.org\r\n\r\n    This issue should NOT be for a project installed from PyPI. If you are\r\n    having an issue with a specific package, you should reach out to the\r\n    maintainers of that project directly instead.\r\n\r\n    Furthermore, this issue should NOT be for any non-PyPI properties (like\r\n    python.org, docs.python.org, etc.)\r\n-->\r\n\r\n**Describe the bug**\r\nI'm trying to enroll a TouchID sensor as a webauthn device. PyPI and Chrome do let me select the sensor, and I do get prompted for a touch, but then PyPI throws an error: \"Registration rejected. Error: Self attestation is not permitted..\"\r\n\r\n**Expected behavior**\r\nI expect to be able to enroll a TouchID sensor. \r\n\r\n**To Reproduce**\r\n- PyPI --> Account Settings\r\n- Click \"Add 2FA With Security Key\"\r\n- Type a key name, click \"Provision Key\"\r\n- Chrome prompts to choose between a USB security key and a built-in sensor. Choose \"Built-in sensor\"\r\n- MacOS prompts to hit the TouchID sensor. Do so.\r\n- Chrome prompts, \"Allow this site to see your security key?\" Click \"Allow\"\r\n- PyPI displays an error: \"Registration rejected. Error: Self attestation is not permitted..\"\r\n\r\n**My Platform**\r\n- MacOS 10.14.5\r\n- MacBook Air (2018 edition, with TouchID)\r\n- Chrome \"75.0.3770.100 (Official Build) (64-bit)\"\r\n\n", "before_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport base64\nimport os\n\nimport webauthn as pywebauthn\n\nfrom webauthn.webauthn import (\n    AuthenticationRejectedException as _AuthenticationRejectedException,\n    RegistrationRejectedException as _RegistrationRejectedException,\n)\n\n\nclass AuthenticationRejectedException(Exception):\n    pass\n\n\nclass RegistrationRejectedException(Exception):\n    pass\n\n\nWebAuthnCredential = pywebauthn.WebAuthnCredential\n\n\ndef _get_webauthn_users(user, *, icon_url, rp_id):\n    \"\"\"\n    Returns a webauthn.WebAuthnUser instance corresponding\n    to the given user model, with properties suitable for\n    usage within the webauthn API.\n    \"\"\"\n    return [\n        pywebauthn.WebAuthnUser(\n            str(user.id),\n            user.username,\n            user.name,\n            icon_url,\n            credential.credential_id,\n            credential.public_key,\n            credential.sign_count,\n            rp_id,\n        )\n        for credential in user.webauthn\n    ]\n\n\ndef _webauthn_b64decode(encoded):\n    padding = \"=\" * (len(encoded) % 4)\n    return base64.urlsafe_b64decode(encoded + padding)\n\n\ndef _webauthn_b64encode(source):\n    return base64.urlsafe_b64encode(source).rstrip(b\"=\")\n\n\ndef generate_webauthn_challenge():\n    \"\"\"\n    Returns a random challenge suitable for use within\n    Webauthn's credential and configuration option objects.\n\n    See: https://w3c.github.io/webauthn/#cryptographic-challenges\n    \"\"\"\n    # NOTE: Webauthn recommends at least 16 bytes of entropy,\n    # we go with 32 because it doesn't cost us anything.\n    return _webauthn_b64encode(os.urandom(32)).decode()\n\n\ndef get_credential_options(user, *, challenge, rp_name, rp_id, icon_url):\n    \"\"\"\n    Returns a dictionary of options for credential creation\n    on the client side.\n    \"\"\"\n    options = pywebauthn.WebAuthnMakeCredentialOptions(\n        challenge, rp_name, rp_id, str(user.id), user.username, user.name, icon_url\n    )\n\n    return options.registration_dict\n\n\ndef get_assertion_options(user, *, challenge, icon_url, rp_id):\n    \"\"\"\n    Returns a dictionary of options for assertion retrieval\n    on the client side.\n    \"\"\"\n    options = pywebauthn.WebAuthnAssertionOptions(\n        _get_webauthn_users(user, icon_url=icon_url, rp_id=rp_id), challenge\n    )\n\n    return options.assertion_dict\n\n\ndef verify_registration_response(response, challenge, *, rp_id, origin):\n    \"\"\"\n    Validates the challenge and attestation information\n    sent from the client during device registration.\n\n    Returns a WebAuthnCredential on success.\n    Raises RegistrationRejectedException on failire.\n    \"\"\"\n    # NOTE: We re-encode the challenge below, because our\n    # response's clientData.challenge is encoded twice:\n    # first for the entire clientData payload, and then again\n    # for the individual challenge.\n    response = pywebauthn.WebAuthnRegistrationResponse(\n        rp_id, origin, response, _webauthn_b64encode(challenge.encode()).decode()\n    )\n    try:\n        return response.verify()\n    except _RegistrationRejectedException as e:\n        raise RegistrationRejectedException(str(e))\n\n\ndef verify_assertion_response(assertion, *, challenge, user, origin, icon_url, rp_id):\n    \"\"\"\n    Validates the challenge and assertion information\n    sent from the client during authentication.\n\n    Returns an updated signage count on success.\n    Raises AuthenticationRejectedException on failure.\n    \"\"\"\n    webauthn_users = _get_webauthn_users(user, icon_url=icon_url, rp_id=rp_id)\n    cred_ids = [cred.credential_id for cred in webauthn_users]\n\n    for webauthn_user in webauthn_users:\n        response = pywebauthn.WebAuthnAssertionResponse(\n            webauthn_user,\n            assertion,\n            _webauthn_b64encode(challenge.encode()).decode(),\n            origin,\n            allow_credentials=cred_ids,\n        )\n        try:\n            return (webauthn_user.credential_id, response.verify())\n        except _AuthenticationRejectedException:\n            pass\n\n    # If we exit the loop, then we've failed to verify the assertion against\n    # any of the user's WebAuthn credentials. Fail.\n    raise AuthenticationRejectedException(\"Invalid WebAuthn credential\")\n", "path": "warehouse/utils/webauthn.py"}], "after_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport base64\nimport os\n\nimport webauthn as pywebauthn\n\nfrom webauthn.webauthn import (\n    AuthenticationRejectedException as _AuthenticationRejectedException,\n    RegistrationRejectedException as _RegistrationRejectedException,\n)\n\n\nclass AuthenticationRejectedException(Exception):\n    pass\n\n\nclass RegistrationRejectedException(Exception):\n    pass\n\n\nWebAuthnCredential = pywebauthn.WebAuthnCredential\n\n\ndef _get_webauthn_users(user, *, icon_url, rp_id):\n    \"\"\"\n    Returns a webauthn.WebAuthnUser instance corresponding\n    to the given user model, with properties suitable for\n    usage within the webauthn API.\n    \"\"\"\n    return [\n        pywebauthn.WebAuthnUser(\n            str(user.id),\n            user.username,\n            user.name,\n            icon_url,\n            credential.credential_id,\n            credential.public_key,\n            credential.sign_count,\n            rp_id,\n        )\n        for credential in user.webauthn\n    ]\n\n\ndef _webauthn_b64decode(encoded):\n    padding = \"=\" * (len(encoded) % 4)\n    return base64.urlsafe_b64decode(encoded + padding)\n\n\ndef _webauthn_b64encode(source):\n    return base64.urlsafe_b64encode(source).rstrip(b\"=\")\n\n\ndef generate_webauthn_challenge():\n    \"\"\"\n    Returns a random challenge suitable for use within\n    Webauthn's credential and configuration option objects.\n\n    See: https://w3c.github.io/webauthn/#cryptographic-challenges\n    \"\"\"\n    # NOTE: Webauthn recommends at least 16 bytes of entropy,\n    # we go with 32 because it doesn't cost us anything.\n    return _webauthn_b64encode(os.urandom(32)).decode()\n\n\ndef get_credential_options(user, *, challenge, rp_name, rp_id, icon_url):\n    \"\"\"\n    Returns a dictionary of options for credential creation\n    on the client side.\n    \"\"\"\n    options = pywebauthn.WebAuthnMakeCredentialOptions(\n        challenge, rp_name, rp_id, str(user.id), user.username, user.name, icon_url\n    )\n\n    return options.registration_dict\n\n\ndef get_assertion_options(user, *, challenge, icon_url, rp_id):\n    \"\"\"\n    Returns a dictionary of options for assertion retrieval\n    on the client side.\n    \"\"\"\n    options = pywebauthn.WebAuthnAssertionOptions(\n        _get_webauthn_users(user, icon_url=icon_url, rp_id=rp_id), challenge\n    )\n\n    return options.assertion_dict\n\n\ndef verify_registration_response(response, challenge, *, rp_id, origin):\n    \"\"\"\n    Validates the challenge and attestation information\n    sent from the client during device registration.\n\n    Returns a WebAuthnCredential on success.\n    Raises RegistrationRejectedException on failire.\n    \"\"\"\n    # NOTE: We re-encode the challenge below, because our\n    # response's clientData.challenge is encoded twice:\n    # first for the entire clientData payload, and then again\n    # for the individual challenge.\n    encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()\n    response = pywebauthn.WebAuthnRegistrationResponse(\n        rp_id, origin, response, encoded_challenge, self_attestation_permitted=True\n    )\n    try:\n        return response.verify()\n    except _RegistrationRejectedException as e:\n        raise RegistrationRejectedException(str(e))\n\n\ndef verify_assertion_response(assertion, *, challenge, user, origin, icon_url, rp_id):\n    \"\"\"\n    Validates the challenge and assertion information\n    sent from the client during authentication.\n\n    Returns an updated signage count on success.\n    Raises AuthenticationRejectedException on failure.\n    \"\"\"\n    webauthn_users = _get_webauthn_users(user, icon_url=icon_url, rp_id=rp_id)\n    cred_ids = [cred.credential_id for cred in webauthn_users]\n    encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()\n\n    for webauthn_user in webauthn_users:\n        response = pywebauthn.WebAuthnAssertionResponse(\n            webauthn_user,\n            assertion,\n            encoded_challenge,\n            origin,\n            allow_credentials=cred_ids,\n        )\n        try:\n            return (webauthn_user.credential_id, response.verify())\n        except _AuthenticationRejectedException:\n            pass\n\n    # If we exit the loop, then we've failed to verify the assertion against\n    # any of the user's WebAuthn credentials. Fail.\n    raise AuthenticationRejectedException(\"Invalid WebAuthn credential\")\n", "path": "warehouse/utils/webauthn.py"}]}