Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def test_nfc_call_u2f(self):
dev = mock.Mock()
dev.select_applet.return_value = (b'U2F', 0x90, 0x00)
dev.apdu_exchange.return_value = (b'version', 0x90, 0x00)
nfc_dev = CtapNfcDevice(dev)
res = nfc_dev.call(CTAPHID.MSG,
b'\x00\x01\x00\x00\x05' +
b'\x01' * 5 +
b'\x00')
dev.apdu_exchange.assert_called_with(
b'\x00\x01\x00\x00\x05\x01\x01\x01\x01\x01\x00')
self.assertEqual(res, b'version\x90\x00')
def test_echo_command(self):
with open_device(transports=TRANSPORT.FIDO) as dev:
res = dev.driver._dev.call(
CTAPHID.MSG,
struct.pack(
'>HBBBH6s',
FIPS_U2F_CMD.ECHO, P1, P2, 0, 6, b'012345'
))
self.assertEqual(res, b'012345\x90\x00')
def lock(self, lock_time=10):
"""Locks the channel."""
self.call(CTAPHID.LOCK, struct.pack(">B", lock_time))
def ping(self, msg=b"Hello FIDO"):
"""Sends data to the authenticator, which echoes it back.
:param msg: The data to send.
:return: The response from the authenticator.
"""
return self.call(CTAPHID.PING, msg)
from __future__ import absolute_import
from .driver import AbstractDriver, NotSupportedError
from .util import TRANSPORT, PID, YUBIKEY, Mode
from fido2.hid import CtapHidDevice, CTAPHID
from enum import IntEnum, unique
import logging
import struct
logger = logging.getLogger(__name__)
@unique
class CMD(IntEnum):
YUBIKEY_DEVICE_CONFIG = CTAPHID.VENDOR_FIRST
READ_CONFIG = CTAPHID.VENDOR_FIRST + 2
WRITE_CONFIG = CTAPHID.VENDOR_FIRST + 3
class FidoDriver(AbstractDriver):
transport = TRANSPORT.FIDO
def __init__(self, dev):
pid = PID(dev.descriptor['product_id'])
super(FidoDriver, self).__init__(pid.get_type(), Mode.from_pid(pid))
self._dev = dev
def read_config(self):
if self.key_type == YUBIKEY.NEO:
raise NotSupportedError()
def __init__(self, dev):
self._dev = dev
self._dev.connect()
self._capabilities = 0
result, sw1, sw2 = self._dev.select_applet(AID_FIDO)
if (sw1, sw2) != SW_SUCCESS:
raise CardSelectException("Select error")
if result == b"U2F_V2":
self._capabilities |= CAPABILITY.NMSG
try: # Probe for CTAP2 by calling GET_INFO
self.call(CTAPHID.CBOR, b"\x04")
self._capabilities |= CAPABILITY.CBOR
except CtapError:
pass
def call(self, cmd, data=b"", event=None, on_keepalive=None):
event = event or Event()
self._dev.InternalSend(TYPE_INIT | cmd, bytearray(data))
last_ka = None
while not event.is_set():
status, resp = self._dev.InternalRecv()
status ^= TYPE_INIT
if status == cmd:
return bytes(resp)
elif status == CTAPHID.ERROR:
raise CtapError(resp[0])
elif status == CTAPHID.KEEPALIVE:
ka_status = resp[0]
if on_keepalive and last_ka != ka_status:
try:
ka_status = STATUS(ka_status)
except ValueError:
pass # Unknown status value
last_ka = ka_status
on_keepalive(ka_status)
continue
else:
raise CtapError(CtapError.ERR.INVALID_COMMAND)
# Cancel the request.
self._dev.InternalSend(TYPE_INIT | CTAPHID.CANCEL, bytearray())
authenticate methods if possible instead.
:param cla: The CLA parameter of the request.
:param ins: The INS parameter of the request.
:param p1: The P1 parameter of the request.
:param p2: The P2 parameter of the request.
:param data: The body of the request.
:return: The response APDU data of a successful request.
:raise: ApduError
"""
size = len(data)
size_h = size >> 16 & 0xFF
size_l = size & 0xFFFF
apdu = struct.pack(">BBBBBH", cla, ins, p1, p2, size_h, size_l) + data + b"\0\0"
response = self.device.call(CTAPHID.MSG, apdu)
status = struct.unpack(">H", response[-2:])[0]
data = response[:-2]
if status != APDU.OK:
raise ApduError(status, data)
return data
def call(self, cmd, data=b"", event=None, on_keepalive=None):
event = event or Event()
self._dev.InternalSend(TYPE_INIT | cmd, bytearray(data))
last_ka = None
while not event.is_set():
status, resp = self._dev.InternalRecv()
status ^= TYPE_INIT
if status == cmd:
return bytes(resp)
elif status == CTAPHID.ERROR:
raise CtapError(resp[0])
elif status == CTAPHID.KEEPALIVE:
ka_status = resp[0]
if on_keepalive and last_ka != ka_status:
try:
ka_status = STATUS(ka_status)
except ValueError:
pass # Unknown status value
last_ka = ka_status
on_keepalive(ka_status)
continue
else:
raise CtapError(CtapError.ERR.INVALID_COMMAND)
# Cancel the request.
self._dev.InternalSend(TYPE_INIT | CTAPHID.CANCEL, bytearray())
self._dev.InternalRecv()
raise CtapError(CtapError.ERR.KEEPALIVE_CANCEL)
def fips_reset(self):
res = self._dev.call(CTAPHID.MSG, [*[0, FIPS_U2F_CMD.RESET], 0, 0])
(sw, ) = struct.unpack('>H', res)
if sw == SW_OK:
return sw
else:
raise APDUError(b'', sw)