qubes-issues
qubes-issues copied to clipboard
CTAP Proxy: cannot add multiple security keys to website
Qubes OS release
R4.2
Brief summary
When I try to add another security key to website, website and Firefox returns "This device is already registered" error.
My env is Qubes R4.2 + Fedora 39 + Firefox 122 + Google Titan Security Key Both GitHub and Cloudflare are affected, so I think this isn't server side bug.
Steps to reproduce
- Add first security key to website.
- Remove first security key from USB port.
- Insert second security key to USB port.
- Try to add second security key to website.
Expected behavior
Key added successfully.
Actual behavior
"This device is already registered" error.
https://github.com/QubesOS/qubes-issues/issues/8847#issuecomment-1883536438 @ben-grande try enabling debug log, maybe it will explain things
Follow the debug instructions, needs to be applied in sys-usb
.
Hmm, If I use Yubico Security Key instead of Google Titan, the issue is gone...
some logs:
- Add first key to github (google titan) -> success
qctap-get-info: asyncio Using selector: EpollSelector
qctap-get-info: fido2.hid SEND: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-get-info: ctap.request Use CTAP 2 protocol.
qctap-get-info: ctap.request return CborRequestWrapper
qctap-get-info: mux.device request: b'\x04'
qctap-get-info: fido2.hid SEND: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: ctap Execute CTAP2 request
qctap-get-info: fido2.hid SEND: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: mux.device response b'[REDACTED]'
qctap-get-info: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-client-pi: asyncio Using selector: EpollSelector
qctap-client-pi: fido2.hid SEND: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: ctap.request Use CTAP 2 protocol.
qctap-client-pi: ctap.request return CborRequestWrapper
qctap-client-pi: mux.device request: b'\x04'
qctap-client-pi: fido2.hid SEND: [REDACTED]
qctap-client-pi: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: ctap Execute CTAP2 request
qctap-client-pi: fido2.hid SEND: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: mux.device response b'[REDACTED]'
qctap-client-pi: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-make-cred: asyncio Using selector: EpollSelector
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: ctap.request APDU request: use CTAP 1 protocol.
qctap-make-cred: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-make-cred: CommandAPDU from_buffer(untrusted_data=[REDACTED])
qctap-make-cred: CommandAPDU from_buffer lc=64 untrusted_request_data=[REDACTED]
qctap-make-cred: Register __init__(untrusted_cla=0, untrusted_ins=1, untrusted_p1=3, untrusted_p2=0, untrusted_request_data=[REDACTED], untrusted_le=65536)
qctap-make-cred: ctap.request return ApduRequestWrapper
qctap-make-cred: mux.device request: b'[REDACTED]'
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: mux.device response b'i\x85'
qctap-make-cred: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-make-cred: asyncio Using selector: EpollSelector
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: ctap.request APDU request: use CTAP 1 protocol.
qctap-make-cred: CommandAPDU from_buffer(untrusted_data=[REDACTED])
qctap-make-cred: CommandAPDU from_buffer lc=64 untrusted_request_data=[REDACTED]
qctap-make-cred: Register __init__(untrusted_cla=0, untrusted_ins=1, untrusted_p1=3, untrusted_p2=0, untrusted_request_data=[REDACTED], untrusted_le=65536)
qctap-make-cred: ctap.request return ApduRequestWrapper
qctap-make-cred: mux.device request: b'[REDACTED]'
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: mux.device response b'[REDACTED]'
qctap-make-cred: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-make-cred: root attempting to register qrexec rpcname u2f.Authenticate argument [REDACTED] frontend develop-web
- Add second key to github (Google Titan) -> Fail
qctap-get-info: asyncio Using selector: EpollSelector
qctap-get-info: fido2.hid SEND: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-get-info: ctap.request Use CTAP 2 protocol.
qctap-get-info: ctap.request return CborRequestWrapper
qctap-get-info: mux.device request: b'\x04'
qctap-get-info: fido2.hid SEND: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: ctap Execute CTAP2 request
qctap-get-info: fido2.hid SEND: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: mux.device response b'[REDACTED]'
qctap-get-info: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-client-pi: asyncio Using selector: EpollSelector
qctap-client-pi: fido2.hid SEND: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: ctap.request Use CTAP 2 protocol.
qctap-client-pi: ctap.request return CborRequestWrapper
qctap-client-pi: mux.device request: b'\x04'
qctap-client-pi: fido2.hid SEND: [REDACTED]
qctap-client-pi: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: ctap Execute CTAP2 request
qctap-client-pi: fido2.hid SEND: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: mux.device response b'[REDACTED]'
qctap-client-pi: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-get-asser: asyncio Using selector: EpollSelector
qctap-get-asser: ctap.request APDU request: use CTAP 1 protocol.
qctap-get-asser: CommandAPDU from_buffer(untrusted_data=[REDACTED])
qctap-get-asser: CommandAPDU from_buffer lc=225 untrusted_request_data=[REDACTED]
qctap-get-asser: Authenticate __init__(untrusted_cla=0, untrusted_ins=2, untrusted_p1=7, untrusted_p2=0, untrusted_request_data=[REDACTED], untrusted_le=65536)
qctap-get-asser: ctap.request return ApduRequestWrapper
qctap-get-asser: fido2.hid SEND: [REDACTED]
qctap-get-asser: fido2.hid RECV: [REDACTED]
qctap-get-asser: ctap.request APDU request: use CTAP 1 protocol.
qctap-get-asser: CommandAPDU from_buffer(untrusted_data=[REDACTED])
qctap-get-asser: CommandAPDU from_buffer lc=225 untrusted_request_data=[REDACTED]
qctap-get-asser: Authenticate __init__(untrusted_cla=0, untrusted_ins=2, untrusted_p1=7, untrusted_p2=0, untrusted_request_data=[REDACTED], untrusted_le=65536)
qctap-get-asser: ctap.request return ApduRequestWrapper
qctap-get-asser: mux.device request: b'[REDACTED]'
qctap-get-asser: fido2.hid SEND: [REDACTED]
qctap-get-asser: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-get-asser: fido2.hid SEND: [REDACTED]
qctap-get-asser: fido2.hid SEND: [REDACTED]
qctap-get-asser: fido2.hid SEND: [REDACTED]
qctap-get-asser: fido2.hid RECV: [REDACTED]
qctap-get-asser: mux.device response b'i\x85'
qctap-get-asser: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-make-cred: asyncio Using selector: EpollSelector
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-make-cred: ctap.request APDU request: use CTAP 1 protocol.
qctap-make-cred: CommandAPDU from_buffer(untrusted_data=[REDACTED])
qctap-make-cred: CommandAPDU from_buffer lc=64 untrusted_request_data=[REDACTED]
qctap-make-cred: Register __init__(untrusted_cla=0, untrusted_ins=1, untrusted_p1=3, untrusted_p2=0, untrusted_request_data=[REDACTED], untrusted_le=65536)
qctap-make-cred: ctap.request return ApduRequestWrapper
qctap-make-cred: mux.device request: b"[REDACTED]"
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: mux.device response b'[REDACTED]'
qctap-make-cred: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-make-cred: root attempting to register qrexec rpcname u2f.Authenticate argument [REDACTED] frontend develop-web
- Add second key to github (Yubico Security Key) -> success
qctap-get-info: asyncio Using selector: EpollSelector
qctap-get-info: fido2.hid SEND: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: ctap.request Use CTAP 2 protocol.
qctap-get-info: ctap.request return CborRequestWrapper
qctap-get-info: mux.device request: b'\x04'
qctap-get-info: fido2.hid SEND: [REDACTED]
qctap-get-info: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: ctap Execute CTAP2 request
qctap-get-info: fido2.hid SEND: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: fido2.hid RECV: [REDACTED]
qctap-get-info: mux.device response b"[REDACTED]"
qctap-get-info: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-client-pi: asyncio Using selector: EpollSelector
qctap-client-pi: fido2.hid SEND: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: ctap.request Use CTAP 2 protocol.
qctap-client-pi: ctap.request return CborRequestWrapper
qctap-client-pi: mux.device request: b'\x04'
qctap-client-pi: fido2.hid SEND: [REDACTED]
qctap-client-pi: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: ctap Execute CTAP2 request
qctap-client-pi: fido2.hid SEND: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: fido2.hid RECV: [REDACTED]
qctap-client-pi: mux.device response b"[REDACTED]"
qctap-client-pi: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-get-asser: asyncio Using selector: EpollSelector
qctap-get-asser: ctap.request APDU request: use CTAP 1 protocol.
qctap-get-asser: CommandAPDU from_buffer(untrusted_data=[REDACTED])
qctap-get-asser: CommandAPDU from_buffer lc=225 untrusted_request_data=[REDACTED]
qctap-get-asser: Authenticate __init__(untrusted_cla=0, untrusted_ins=2, untrusted_p1=7, untrusted_p2=0, untrusted_request_data=[REDACTED], untrusted_le=65536)
qctap-get-asser: ctap.request return ApduRequestWrapper
qctap-get-asser: fido2.hid SEND: [REDACTED]
qctap-get-asser: fido2.hid RECV: [REDACTED]
qctap-get-asser: ctap.request APDU request: use CTAP 1 protocol.
qctap-get-asser: CommandAPDU from_buffer(untrusted_data=[REDACTED])
qctap-get-asser: CommandAPDU from_buffer lc=225 untrusted_request_data=[REDACTED]
qctap-get-asser: Authenticate __init__(untrusted_cla=0, untrusted_ins=2, untrusted_p1=7, untrusted_p2=0, untrusted_request_data=[REDACTED], untrusted_le=65536)
qctap-get-asser: ctap.request return ApduRequestWrapper
qctap-get-asser: mux.device request: b'[REDACTED]'
qctap-get-asser: fido2.hid SEND: [REDACTED]
qctap-get-asser: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-get-asser: fido2.hid SEND: [REDACTED]
qctap-get-asser: fido2.hid SEND: [REDACTED]
qctap-get-asser: fido2.hid SEND: [REDACTED]
qctap-get-asser: fido2.hid RECV: [REDACTED]
qctap-get-asser: mux.device response b'j\x80'
qctap-get-asser: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-make-cred: asyncio Using selector: EpollSelector
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: ctap.request APDU request: use CTAP 1 protocol.
qctap-make-cred: CommandAPDU from_buffer(untrusted_data=[REDACTED])
qctap-make-cred: CommandAPDU from_buffer lc=64 untrusted_request_data=[REDACTED]
qctap-make-cred: Register __init__(untrusted_cla=0, untrusted_ins=1, untrusted_p1=3, untrusted_p2=0, untrusted_request_data=[REDACTED], untrusted_le=65536)
qctap-make-cred: ctap.request return ApduRequestWrapper
qctap-make-cred: mux.device request: b'[REDACTED]'
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: mux.device response b'i\x85'
qctap-make-cred: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-make-cred: asyncio Using selector: EpollSelector
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: ctap.request APDU request: use CTAP 1 protocol.
qctap-make-cred: mux pending={<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib/python3.11/asyncio/futures.py:387]>}
qctap-make-cred: CommandAPDU from_buffer(untrusted_data=[REDACTED])
qctap-make-cred: CommandAPDU from_buffer lc=64 untrusted_request_data=[REDACTED]
qctap-make-cred: Register __init__(untrusted_cla=0, untrusted_ins=1, untrusted_p1=3, untrusted_p2=0, untrusted_request_data=[REDACTED], untrusted_le=65536)
qctap-make-cred: ctap.request return ApduRequestWrapper
qctap-make-cred: mux.device request: b'[REDACTED]'
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid SEND: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: fido2.hid RECV: [REDACTED]
qctap-make-cred: mux.device response b'[REDACTED]'
qctap-make-cred: root pending=set() done={<Future finished result=<qubesctap.pr...[REDACTED]>>}
qctap-make-cred: root attempting to register qrexec rpcname u2f.Authenticate argument [REDACTED] frontend develop-web
Hmm, editing some code seems fixes (or workaround?) this problem, but I don't understand what I'm doing. :rofl:
for mux.py L111
if result is None \
or isinstance(result.data, ApduError) \
and result.data.code == APDU.WRONG_DATA