run black format on everything

This commit is contained in:
Conor Patrick
2021-02-14 20:26:03 -08:00
parent cbc31b3f59
commit b7fc538af8
16 changed files with 428 additions and 235 deletions
+44 -17
View File
@@ -13,7 +13,7 @@ from fido2.utils import hmac_sha256, sha256
from tests.utils import *
if 'trezor' in sys.argv:
if "trezor" in sys.argv:
from .vendor.trezor.udp_backend import force_udp_backend
else:
from solo.fido2 import force_udp_backend
@@ -45,7 +45,9 @@ def info(device):
@pytest.fixture(scope="module")
def MCRes(resetDevice,):
def MCRes(
resetDevice,
):
req = FidoRequest()
res = resetDevice.sendMC(*req.toMC())
setattr(res, "request", req)
@@ -65,7 +67,9 @@ def GARes(device, MCRes):
@pytest.fixture(scope="module")
def RegRes(resetDevice,):
def RegRes(
resetDevice,
):
req = FidoRequest()
res = resetDevice.register(req.challenge, req.appid)
setattr(res, "request", req)
@@ -115,7 +119,9 @@ class Packet(object):
def __init__(self, data):
self.data = data
def ToWireFormat(self,):
def ToWireFormat(
self,
):
return self.data
@staticmethod
@@ -177,7 +183,9 @@ class TestDevice:
def set_sim(self, b):
self.is_sim = b
def reboot(self,):
def reboot(
self,
):
if self.is_sim:
print("Sending restart command...")
self.send_magic_reboot()
@@ -190,14 +198,14 @@ class TestDevice:
self.find_device(self.nfc_interface_only)
return
if 'solokeys' in sys.argv or 'solobee' in sys.argv:
if "solokeys" in sys.argv or "solobee" in sys.argv:
try:
self.dev.call(0x53 ^ 0x80,b'')
self.dev.call(0x53 ^ 0x80, b"")
except OSError:
pass
print('Rebooting..')
for _ in range(0,8):
print("Rebooting..")
for _ in range(0, 8):
time.sleep(0.1)
try:
self.find_device(self.nfc_interface_only)
@@ -233,7 +241,9 @@ class TestDevice:
assert len(data) == 64
self.dev._dev.InternalSendPacket(Packet(data))
def send_magic_reboot(self,):
def send_magic_reboot(
self,
):
"""
For use in simulation and testing. Random bytes that authenticator should detect
and then restart itself.
@@ -248,16 +258,20 @@ class TestDevice:
)
self.dev._dev.InternalSendPacket(Packet(magic_cmd))
def send_nfc_reboot(self,):
def send_nfc_reboot(
self,
):
"""
Send magic nfc reboot sequence for solokey
"""
data = b"\x12\x56\xab\xf0"
header = struct.pack('!BBBBB', 0x00, 0xee, 0x00, 0x00, len(data))
header = struct.pack("!BBBBB", 0x00, 0xEE, 0x00, 0x00, len(data))
resp, sw1, sw2 = self.dev.apdu_exchange(header + data)
return sw1 == 0x90 and sw2 == 0x00
def cid(self,):
def cid(
self,
):
return self.dev._dev.cid
def set_cid(self, cid):
@@ -265,7 +279,9 @@ class TestDevice:
cid = struct.pack("%dB" % len(cid), *[ord(x) for x in cid])
self.dev._dev.cid = cid
def recv_raw(self,):
def recv_raw(
self,
):
with Timeout(1.0):
cmd, payload = self.dev._dev.InternalRecv()
return cmd, payload
@@ -279,10 +295,19 @@ class TestDevice:
raise ValueError("Unexpected error: %02x" % data[0])
def register(self, chal, appid, on_keepalive=DeviceSelectCredential(1)):
reg_data = _call_polling(0.25, None, on_keepalive, self.ctap1.register, chal, appid)
reg_data = _call_polling(
0.25, None, on_keepalive, self.ctap1.register, chal, appid
)
return reg_data
def authenticate(self, chal, appid, key_handle, check_only=False, on_keepalive=DeviceSelectCredential(1)):
def authenticate(
self,
chal,
appid,
key_handle,
check_only=False,
on_keepalive=DeviceSelectCredential(1),
):
auth_data = _call_polling(
0.25,
None,
@@ -295,7 +320,9 @@ class TestDevice:
)
return auth_data
def reset(self,):
def reset(
self,
):
print("Resetting Authenticator...")
try:
self.ctap2.reset(on_keepalive=DeviceSelectCredential(1))
+3 -1
View File
@@ -6,7 +6,9 @@ from fido2.ctap2 import ES256, AttestedCredentialData, PinProtocolV1
from tests.utils import *
@pytest.mark.skipif('trezor' in sys.argv, reason="ClientPin is not supported on Trezor.")
@pytest.mark.skipif(
"trezor" in sys.argv, reason="ClientPin is not supported on Trezor."
)
def test_lockout(device, resetDevice):
pin = "TestPin"
device.client.pin_protocol.set_pin(pin)
+6 -2
View File
@@ -50,7 +50,9 @@ def GAPinRes(device, MCPinRes):
return res
@pytest.mark.skipif('trezor' in sys.argv, reason="ClientPin is not supported on Trezor.")
@pytest.mark.skipif(
"trezor" in sys.argv, reason="ClientPin is not supported on Trezor."
)
class TestPin(object):
def test_pin(self, CPRes):
pass
@@ -136,7 +138,9 @@ class TestPin(object):
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
@pytest.mark.skipif('trezor' in sys.argv, reason="ClientPin is not supported on Trezor.")
@pytest.mark.skipif(
"trezor" in sys.argv, reason="ClientPin is not supported on Trezor."
)
def test_pin_attempts(device, SetPinRes):
# Flip 1 bit
pin = SetPinRes.PIN
+3 -1
View File
@@ -6,7 +6,9 @@ from fido2.ctap2 import ES256, AttestedCredentialData, PinProtocolV1
from tests.utils import *
@pytest.mark.skipif('trezor' in sys.argv, reason="ClientPin is not supported on Trezor.")
@pytest.mark.skipif(
"trezor" in sys.argv, reason="ClientPin is not supported on Trezor."
)
class TestSetPin(object):
def test_send_zero_length_pin_auth(self, resetDevice):
with pytest.raises(CtapError) as e:
+8 -5
View File
@@ -27,6 +27,7 @@ class TestCtap1WithCtap2(object):
auth.verify(req.cdh, credential_data.public_key)
assert auth.credential["id"] == RegRes.key_handle
# Test FIDO2 register works with U2F auth
class TestCtap2WithCtap1(object):
def test_ctap1_authenticate(self, MCRes, device):
@@ -36,10 +37,12 @@ class TestCtap2WithCtap1(object):
res = device.authenticate(req.challenge, req.appid, key_handle)
credential_data = AttestedCredentialData(MCRes.auth_data.credential_data)
pubkey_string = b'\x04' + credential_data.public_key[-2] + credential_data.public_key[-3]
res.verify(
req.appid, req.challenge, pubkey_string
pubkey_string = (
b"\x04"
+ credential_data.public_key[-2]
+ credential_data.public_key[-3]
)
res.verify(req.appid, req.challenge, pubkey_string)
else:
print("ctap2 credId is longer than 255 bytes, cannot use with U2F.")
print("ctap2 credId is longer than 255 bytes, cannot use with U2F.")
+14 -11
View File
@@ -39,17 +39,16 @@ class TestGetAssertion(object):
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
def test_mismatched_rp(self, device, GARes):
rp_id = GARes.request.rp['id'][:]
rp_name = GARes.request.rp['name'][:]
rp_id += '.com'
rp_id = GARes.request.rp["id"][:]
rp_name = GARes.request.rp["name"][:]
rp_id += ".com"
mismatch_rp = {'id': rp_id, 'name': rp_name}
mismatch_rp = {"id": rp_id, "name": rp_name}
with pytest.raises(CtapError) as e:
device.sendGA(*FidoRequest(GARes, rp=mismatch_rp).toGA())
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
def test_missing_rp(self, device, GARes):
with pytest.raises(CtapError) as e:
device.sendGA(*FidoRequest(GARes, rp=None).toGA())
@@ -84,7 +83,10 @@ class TestGetAssertion(object):
def test_unknown_option(self, device, GARes):
device.sendGA(*FidoRequest(GARes, options={"unknown": True}).toGA())
@pytest.mark.skipif('trezor' in sys.argv, reason="User verification flag is intentionally set to true on Trezor even when user verification is not configured. (Otherwise some services refuse registration without giving a reason.)")
@pytest.mark.skipif(
"trezor" in sys.argv,
reason="User verification flag is intentionally set to true on Trezor even when user verification is not configured. (Otherwise some services refuse registration without giving a reason.)",
)
def test_option_uv(self, device, info, GARes):
if "uv" in info.options:
if info.options["uv"]:
@@ -145,19 +147,20 @@ class TestGetAssertion(object):
def test_user_presence_option_false(self, device, MCRes, GARes):
from cryptography.exceptions import InvalidSignature
res = device.sendGA(*FidoRequest(GARes, options = {'up': False}).toGA())
res = device.sendGA(*FidoRequest(GARes, options={"up": False}).toGA())
try:
verify(MCRes, res, GARes.request.cdh)
except InvalidSignature:
if 'trezor' not in sys.argv:
if "trezor" not in sys.argv:
raise
if '--nfc' not in sys.argv:
assert((res.auth_data.flags & 1) == 0)
if "--nfc" not in sys.argv:
assert (res.auth_data.flags & 1) == 0
@pytest.mark.skipif('trezor' in sys.argv, reason="Reboot is not supported on Trezor.")
@pytest.mark.skipif("trezor" in sys.argv, reason="Reboot is not supported on Trezor.")
class TestGetAssertionAfterBoot(object):
def test_assertion_after_reboot(self, rebootedDevice, MCRes, GARes):
credential_data = AttestedCredentialData(MCRes.auth_data.credential_data)
+10 -2
View File
@@ -25,7 +25,10 @@ def test_Check_options_field(info):
assert info.options[x] in [True, False]
@pytest.mark.skipif('trezor' in sys.argv, reason="User verification flag is intentionally set to true on Trezor even when user verification is not configured. (Otherwise some services refuse registration without giving a reason.)")
@pytest.mark.skipif(
"trezor" in sys.argv,
reason="User verification flag is intentionally set to true on Trezor even when user verification is not configured. (Otherwise some services refuse registration without giving a reason.)",
)
def test_Check_uv_option(device, info):
if "uv" in info.options:
if info.options["uv"]:
@@ -39,6 +42,7 @@ def test_Check_up_option(device, info):
device.sendMC(*FidoRequest(options={"up": True}).toMC())
assert e.value.code == CtapError.ERR.INVALID_OPTION
def test_self_cbor_sorting():
cbor_key_list_sorted = [
0,
@@ -58,18 +62,22 @@ def test_self_cbor_sorting():
]
TestCborKeysSorted(cbor_key_list_sorted)
def test_self_cbor_integers():
with pytest.raises(ValueError) as e:
TestCborKeysSorted([1, 0])
def test_self_cbor_major_type():
with pytest.raises(ValueError) as e:
TestCborKeysSorted([-1, 0])
def test_self_cbor_strings():
with pytest.raises(ValueError) as e:
TestCborKeysSorted(["bb", "a"])
def test_self_cbor_same_length_strings():
with pytest.raises(ValueError) as e:
TestCborKeysSorted(["ab", "aa"])
TestCborKeysSorted(["ab", "aa"])
+20 -8
View File
@@ -155,7 +155,10 @@ class TestMakeCredential(object):
with pytest.raises(CtapError) as e:
device.sendMC(*req.toMC())
assert e.value.code in [CtapError.ERR.MISSING_PARAMETER, CtapError.ERR.UNSUPPORTED_ALGORITHM]
assert e.value.code in [
CtapError.ERR.MISSING_PARAMETER,
CtapError.ERR.UNSUPPORTED_ALGORITHM,
]
def test_bad_type_pubKeyCredParams_alg(self, device, MCRes):
req = FidoRequest(MCRes, key_params=[{"alg": "7", "type": "public-key"}])
@@ -228,7 +231,9 @@ class TestMakeCredential(object):
device.sendMC(*req.toMC())
def test_eddsa(self, device):
mc_req = FidoRequest(key_params=[{"type": "public-key", "alg": EdDSA.ALGORITHM}])
mc_req = FidoRequest(
key_params=[{"type": "public-key", "alg": EdDSA.ALGORITHM}]
)
try:
mc_res = device.sendMC(*mc_req.toMC())
except CtapError as e:
@@ -238,7 +243,12 @@ class TestMakeCredential(object):
setattr(mc_res, "request", mc_req)
allow_list = [{"id": mc_res.auth_data.credential_data.credential_id[:], "type": "public-key"}]
allow_list = [
{
"id": mc_res.auth_data.credential_data.credential_id[:],
"type": "public-key",
}
]
ga_req = FidoRequest(allow_list=allow_list)
ga_res = device.sendGA(*ga_req.toGA())
@@ -249,10 +259,12 @@ class TestMakeCredential(object):
except:
# Print out extra details on failure
from binascii import hexlify
print('authdata', hexlify(ga_res.auth_data))
print('cdh', hexlify(ga_res.request.cdh))
print('sig', hexlify(ga_res.signature))
from fido2.ctap2 import AttestedCredentialData
print("authdata", hexlify(ga_res.auth_data))
print("cdh", hexlify(ga_res.request.cdh))
print("sig", hexlify(ga_res.signature))
from fido2.ctap2 import AttestedCredentialData
credential_data = AttestedCredentialData(mc_res.auth_data.credential_data)
print('public key:', hexlify(credential_data.public_key[-2]))
print("public key:", hexlify(credential_data.public_key[-2]))
verify(mc_res, ga_res)
@@ -5,7 +5,10 @@ from fido2.ctap import CtapError
from tests.utils import *
@pytest.mark.skipif('trezor' in sys.argv, reason="Trezor does not invalidate server-resident credentials.")
@pytest.mark.skipif(
"trezor" in sys.argv,
reason="Trezor does not invalidate server-resident credentials.",
)
def test_credential_resets(device, MCRes, GARes):
verify(MCRes, GARes)
device.reset()
+48 -18
View File
@@ -51,14 +51,20 @@ class TestResidentKey(object):
def test_user_info_returned(self, MC_RK_Res, GA_RK_Res):
assert "id" in GA_RK_Res.user.keys()
assert MC_RK_Res.auth_data.credential_data.credential_id == GA_RK_Res.credential['id']
assert MC_RK_Res.request.user['id'] == GA_RK_Res.user['id']
assert (
MC_RK_Res.auth_data.credential_data.credential_id
== GA_RK_Res.credential["id"]
)
assert MC_RK_Res.request.user["id"] == GA_RK_Res.user["id"]
if not MC_RK_Res.request.pin_protocol or not GA_RK_Res.number_of_credentials:
assert "id" in GA_RK_Res.user.keys() and len(GA_RK_Res.user.keys()) == 1
else:
assert MC_RK_Res.request.user == GA_RK_Res.user
@pytest.mark.skipif('trezor' in sys.argv, reason="Trezor does not support get_next_assertion() because it has a display.")
@pytest.mark.skipif(
"trezor" in sys.argv,
reason="Trezor does not support get_next_assertion() because it has a display.",
)
def test_multiple_rk_nodisplay(self, device, MC_RK_Res):
auths = []
regs = [MC_RK_Res]
@@ -92,7 +98,7 @@ class TestResidentKey(object):
for x, y in zip(regs, auths[::-1]):
verify(x, y, req.cdh)
@pytest.mark.skipif('trezor' not in sys.argv, reason="Only Trezor has a display.")
@pytest.mark.skipif("trezor" not in sys.argv, reason="Only Trezor has a display.")
def test_multiple_rk_display(self, device, MC_RK_Res):
regs = [MC_RK_Res]
for i in range(0, 3):
@@ -102,7 +108,9 @@ class TestResidentKey(object):
regs.append(res)
for i, reg in enumerate(reversed(regs)):
req = FidoRequest(MC_RK_Res, options=None, on_keepalive=DeviceSelectCredential(i + 1))
req = FidoRequest(
MC_RK_Res, options=None, on_keepalive=DeviceSelectCredential(i + 1)
)
res = device.sendGA(*req.toGA())
assert res.number_of_credentials is None
@@ -113,7 +121,7 @@ class TestResidentKey(object):
assert res.user["id"] == reg.request.user["id"]
verify(reg, res, req.cdh)
@pytest.mark.skipif('trezor' not in sys.argv, reason="Only Trezor has a display.")
@pytest.mark.skipif("trezor" not in sys.argv, reason="Only Trezor has a display.")
def test_replace_rk_display(self, device):
"""
Test replacing resident keys.
@@ -126,7 +134,12 @@ class TestResidentKey(object):
# Registration data is a list of (rp, user, number), where number is
# the expected position of the credential after all registrations are
# complete.
reg_data = [(rp1, user1, 2), (rp1, user2, None), (rp1, user2, 1), (rp2, user2, 1)]
reg_data = [
(rp1, user1, 2),
(rp1, user2, None),
(rp1, user2, 1),
(rp2, user2, 1),
]
regs = []
for rp, user, number in reg_data:
req = FidoRequest(options={"rk": True}, rp=rp, user=user)
@@ -138,13 +151,22 @@ class TestResidentKey(object):
# Check.
for reg in regs:
if reg.number is not None:
req = FidoRequest(rp=reg.request.rp, options=None, on_keepalive=DeviceSelectCredential(reg.number))
req = FidoRequest(
rp=reg.request.rp,
options=None,
on_keepalive=DeviceSelectCredential(reg.number),
)
res = device.sendGA(*req.toGA())
assert res.user["id"] == reg.request.user["id"]
verify(reg, res, req.cdh)
@pytest.mark.skipif('trezor' in sys.argv, reason="Trezor does not support get_next_assertion() because it has a display.")
@pytest.mark.skipif('solokeys' in sys.argv, reason="Initial SoloKeys model truncates displayName")
@pytest.mark.skipif(
"trezor" in sys.argv,
reason="Trezor does not support get_next_assertion() because it has a display.",
)
@pytest.mark.skipif(
"solokeys" in sys.argv, reason="Initial SoloKeys model truncates displayName"
)
def test_rk_maximum_size_nodisplay(self, device, MC_RK_Res):
"""
Check the lengths of the fields according to the FIDO2 spec
@@ -155,7 +177,7 @@ class TestResidentKey(object):
user_max = generate_user_maximum()
req = FidoRequest(MC_RK_Res, user=user_max)
resMC = device.sendMC(*req.toMC())
req.options={}
req.options = {}
resGA = device.sendGA(*req.toGA())
credentials = resGA.number_of_credentials
assert credentials == 5
@@ -171,7 +193,7 @@ class TestResidentKey(object):
for y in ("name", "icon", "displayName", "id"):
assert user_max_GA.user[y] == user_max[y]
@pytest.mark.skipif('trezor' not in sys.argv, reason="Only Trezor has a display.")
@pytest.mark.skipif("trezor" not in sys.argv, reason="Only Trezor has a display.")
def test_rk_maximum_size_display(self, device, MC_RK_Res):
"""
Check the lengths of the fields according to the FIDO2 spec
@@ -186,16 +208,22 @@ class TestResidentKey(object):
assert resGA.number_of_credentials is None
verify(resMC, resGA, req.cdh)
@pytest.mark.skipif('trezor' in sys.argv, reason="Trezor does not support get_next_assertion() because it has a display.")
@pytest.mark.skipif('solokeys' in sys.argv, reason="Initial SoloKeys model truncates displayName")
@pytest.mark.skipif(
"trezor" in sys.argv,
reason="Trezor does not support get_next_assertion() because it has a display.",
)
@pytest.mark.skipif(
"solokeys" in sys.argv, reason="Initial SoloKeys model truncates displayName"
)
def test_rk_maximum_list_capacity_per_rp_nodisplay(self, info, device, MC_RK_Res):
"""
Test maximum returned capacity of the RK for the given RP
"""
# Try to determine from get_info, or default to 19.
RK_CAPACITY_PER_RP = info.max_creds_in_list
if not RK_CAPACITY_PER_RP: RK_CAPACITY_PER_RP = 19
RK_CAPACITY_PER_RP = info.max_creds_in_list
if not RK_CAPACITY_PER_RP:
RK_CAPACITY_PER_RP = 19
users = []
@@ -243,7 +271,7 @@ class TestResidentKey(object):
for x, y in zip(regs, auths):
verify(x, y, req.cdh)
@pytest.mark.skipif('trezor' not in sys.argv, reason="Only Trezor has a display.")
@pytest.mark.skipif("trezor" not in sys.argv, reason="Only Trezor has a display.")
def test_rk_maximum_list_capacity_per_rp_display(self, device):
"""
Test maximum capacity of resident keys.
@@ -267,7 +295,9 @@ class TestResidentKey(object):
for i, reg in enumerate(reversed(regs)):
if i not in (0, 1, 7, 14, 15):
continue
req = FidoRequest(req, options=None, on_keepalive=DeviceSelectCredential(i + 1))
req = FidoRequest(
req, options=None, on_keepalive=DeviceSelectCredential(i + 1)
)
res = device.sendGA(*req.toGA())
assert res.user["id"] == reg.request.user["id"]
verify(reg, res, req.cdh)
@@ -8,8 +8,8 @@ from tests.utils import *
@pytest.mark.skipif(
("--sim" in sys.argv or '--nfc' in sys.argv) and not 'trezor' in sys.argv,
reason="Simulation doesn't care about user presence"
("--sim" in sys.argv or "--nfc" in sys.argv) and not "trezor" in sys.argv,
reason="Simulation doesn't care about user presence",
)
class TestUserPresence(object):
def test_user_presence_instructions(self, MCRes, GARes):
@@ -31,40 +31,53 @@ class TestUserPresence(object):
print("DO NOT ACTIVATE UP")
with pytest.raises(CtapError) as e:
with Timeout(2.0) as event:
device.sendGA(*FidoRequest(GARes, timeout=event, on_keepalive=None).toGA())
device.sendGA(
*FidoRequest(GARes, timeout=event, on_keepalive=None).toGA()
)
assert e.value.code == CtapError.ERR.KEEPALIVE_CANCEL
@pytest.mark.skipif(not 'trezor' in sys.argv, reason="Only Trezor supports decline.")
@pytest.mark.skipif(
not "trezor" in sys.argv, reason="Only Trezor supports decline."
)
def test_user_decline(self, device, MCRes, GARes):
print("PRESS DECLINE")
with pytest.raises(CtapError) as e:
device.sendGA(*FidoRequest(GARes, on_keepalive=DeviceSelectCredential(0)).toGA())
device.sendGA(
*FidoRequest(GARes, on_keepalive=DeviceSelectCredential(0)).toGA()
)
assert e.value.code == CtapError.ERR.OPERATION_DENIED
def test_user_presence_option_false_on_get_assertion(self, device, MCRes, GARes):
print("DO NOT ACTIVATE UP")
time.sleep(1)
with Timeout(2.0) as event:
device.sendGA(*FidoRequest(GARes, options = {'up': False}, timeout=event).toGA())
device.sendGA(
*FidoRequest(GARes, options={"up": False}, timeout=event).toGA()
)
def test_user_presence_option_false_on_make_credential(self, device, MCRes):
print("DO NOT ACTIVATE UP")
time.sleep(1)
with pytest.raises(CtapError) as e:
with Timeout(1.0) as event:
device.sendMC(*FidoRequest(MCRes, options = {'up': False}, timeout=event).toMC())
device.sendMC(
*FidoRequest(MCRes, options={"up": False}, timeout=event).toMC()
)
assert e.value.code == CtapError.ERR.INVALID_OPTION
with pytest.raises(CtapError) as e:
with Timeout(1.0) as event:
device.sendMC(*FidoRequest(MCRes, options = {'up': True}, timeout=event).toMC())
device.sendMC(
*FidoRequest(MCRes, options={"up": True}, timeout=event).toMC()
)
assert e.value.code == CtapError.ERR.INVALID_OPTION
def test_user_presence_permits_only_one_request(self, device, MCRes, GARes):
print("ACTIVATE UP ONCE")
device.sendGA(*FidoRequest(GARes).toGA())
with pytest.raises(CtapError) as e:
with Timeout(1.0) as event:
device.sendGA(*FidoRequest(GARes, timeout=event, on_keepalive=None).toGA())
device.sendGA(
*FidoRequest(GARes, timeout=event, on_keepalive=None).toGA()
)
assert e.value.code == CtapError.ERR.KEEPALIVE_CANCEL
+4 -7
View File
@@ -8,10 +8,8 @@ import pytest
from fido2.ctap import CtapError
from fido2.hid import CTAPHID
@pytest.mark.skipif(
'--nfc' in sys.argv,
reason="Wrong transport"
)
@pytest.mark.skipif("--nfc" in sys.argv, reason="Wrong transport")
class TestHID(object):
def test_long_ping(self, device):
amt = 1000
@@ -50,14 +48,13 @@ class TestHID(object):
r = device.send_data(CTAPHID.INIT, payload)
capabilities = r[16]
if (capabilities ^ 0x04) != 0:
print('Implements CBOR.')
print("Implements CBOR.")
with pytest.raises(CtapError) as e:
r = device.send_data(CTAPHID.CBOR, "")
assert e.value.code == CtapError.ERR.INVALID_LENGTH
else:
print('CBOR is not implemented.')
print("CBOR is not implemented.")
def test_no_data_in_u2f_msg(self, device):
payload = b"\x11\x11\x11\x11\x11\x11\x11\x11"
+8 -7
View File
@@ -4,10 +4,7 @@ import pytest
from tests.utils import FidoRequest
@pytest.mark.skipif(
not ('--nfc' in sys.argv),
reason="NFC transport only"
)
@pytest.mark.skipif(not ("--nfc" in sys.argv), reason="NFC transport only")
class TestMakeCredential(object):
def test_big_request_response(self, device, MCRes):
req = FidoRequest(
@@ -15,12 +12,16 @@ class TestMakeCredential(object):
exclude_list=[
{
"id": b"0123456789012345678901234567890123456789012345678901234567890123456789",
"type": "public-key"},
"type": "public-key",
},
{
"id": b"1123456789012345678901234567890123456789012345678901234567890123456789",
"type": "public-key"},
"type": "public-key",
},
{
"id": b"2123456789012345678901234567890123456789012345678901234567890123456789",
"type": "public-key"}],
"type": "public-key",
},
],
)
device.sendMC(*req.toMC())
+13 -7
View File
@@ -8,7 +8,7 @@ from numbers import Number
from fido2.ctap2 import ES256, AttestedCredentialData, PinProtocolV1
from fido2.utils import hmac_sha256, sha256
if 'trezor' in sys.argv:
if "trezor" in sys.argv:
from .vendor.trezor.utils import DeviceSelectCredential
else:
from .vendor.solo.utils import DeviceSelectCredential
@@ -57,6 +57,7 @@ def generate_user():
counter = 1
def generate_user_maximum():
"""
Generate RK with the maximum lengths of the fields, according to the minimal requirements of the FIDO2 spec
@@ -69,8 +70,8 @@ def generate_user_maximum():
# https://www.w3.org/TR/webauthn/#dictionary-pkcredentialentity
name = " ".join(random.choice(name_list).strip() for i in range(0, 30))
name = f'{counter}: {name}'
icon = "https://www.w3.org/TR/webauthn/" + 'A'*128
name = f"{counter}: {name}"
icon = "https://www.w3.org/TR/webauthn/" + "A" * 128
display_name = "Displayed " + name
name = name[:64]
@@ -150,8 +151,8 @@ class FidoRequest:
def save_attr(self, attr, value, request):
"""
Will assign attribute from source, in following priority:
Argument, request object, generated
Will assign attribute from source, in following priority:
Argument, request object, generated
"""
if value != Empty:
setattr(self, attr, value)
@@ -160,7 +161,9 @@ class FidoRequest:
else:
setattr(self, attr, generate(attr))
def toGA(self,):
def toGA(
self,
):
return [
None if not self.rp else self.rp["id"],
self.cdh,
@@ -173,7 +176,9 @@ class FidoRequest:
self.on_keepalive,
]
def toMC(self,):
def toMC(
self,
):
return [
self.cdh,
self.rp,
@@ -220,6 +225,7 @@ class FidoRequest:
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
class Timeout(object):
"""Utility class for adding a timeout to an event.
:param time_or_event: A number, in seconds, or a threading.Event object.
+126 -78
View File
@@ -8,6 +8,7 @@ from binascii import hexlify
PIN = "123456"
@pytest.fixture(params=[PIN])
def PinToken(request, device):
device.reboot()
@@ -17,15 +18,17 @@ def PinToken(request, device):
return device.client.pin_protocol.get_pin_token(pin)
@pytest.fixture()
def MC_RK_Res(device, PinToken):
req = FidoRequest()
pin_auth = hmac_sha256(PinToken, req.cdh)[:16]
rp = {"id": "ssh:", "name": "Bate Goiko"}
req = FidoRequest(
request=None, pin_protocol=1, pin_auth=pin_auth, rp=rp, options={"rk": True},
request=None,
pin_protocol=1,
pin_auth=pin_auth,
rp=rp,
options={"rk": True},
)
device.sendMC(*req.toMC())
@@ -33,7 +36,11 @@ def MC_RK_Res(device, PinToken):
pin_auth = hmac_sha256(PinToken, req.cdh)[:16]
rp = {"id": "xakcop.com", "name": "John Doe"}
req = FidoRequest(
request=None, pin_protocol=1, pin_auth=pin_auth, rp=rp, options={"rk": True},
request=None,
pin_protocol=1,
pin_auth=pin_auth,
rp=rp,
options={"rk": True},
)
device.sendMC(*req.toMC())
@@ -50,8 +57,9 @@ def _test_enumeration(CredMgmt, rp_map):
assert len(rp_map.keys()) == len(res)
for rp in res:
creds = CredMgmt.enumerate_creds(sha256( rp[3]['id'].encode('utf8') ))
assert len(creds) == rp_map[rp[3]['id']]
creds = CredMgmt.enumerate_creds(sha256(rp[3]["id"].encode("utf8")))
assert len(creds) == rp_map[rp[3]["id"]]
def _test_enumeration_interleaved(CredMgmt, rp_map):
"Enumerate credentials using DFS"
@@ -59,24 +67,25 @@ def _test_enumeration_interleaved(CredMgmt, rp_map):
assert len(rp_map.keys()) == first_rp[CredentialManagement.RESULT.TOTAL_RPS]
rk_count = 1
first_rk = CredMgmt.enumerate_creds_begin( sha256( first_rp[3]['id'].encode('utf8') ) )
first_rk = CredMgmt.enumerate_creds_begin(sha256(first_rp[3]["id"].encode("utf8")))
for i in range(1, first_rk[CredentialManagement.RESULT.TOTAL_CREDENTIALS]):
c = CredMgmt.enumerate_creds_next()
rk_count += 1
assert rk_count == rp_map[first_rp[3]['id']]
assert rk_count == rp_map[first_rp[3]["id"]]
for i in range(1, first_rp[CredentialManagement.RESULT.TOTAL_RPS]):
next_rp = CredMgmt.enumerate_rps_next()
rk_count = 1
first_rk = CredMgmt.enumerate_creds_begin( sha256( next_rp[3]['id'].encode('utf8') ) )
first_rk = CredMgmt.enumerate_creds_begin(
sha256(next_rp[3]["id"].encode("utf8"))
)
for i in range(1, first_rk[CredentialManagement.RESULT.TOTAL_CREDENTIALS]):
c = CredMgmt.enumerate_creds_next()
rk_count += 1
assert rk_count == rp_map[next_rp[3]['id']]
assert rk_count == rp_map[next_rp[3]["id"]]
def CredMgmtWrongPinAuth(device, pin_token):
@@ -85,6 +94,7 @@ def CredMgmtWrongPinAuth(device, pin_token):
wrong_pt[0] = (wrong_pt[0] + 1) % 256
return CredentialManagement(device.ctap2, pin_protocol, bytes(wrong_pt))
def assert_cred_response_has_all_fields(cred_res):
for i in (
CredentialManagement.RESULT.USER,
@@ -92,17 +102,18 @@ def assert_cred_response_has_all_fields(cred_res):
CredentialManagement.RESULT.PUBLIC_KEY,
CredentialManagement.RESULT.TOTAL_CREDENTIALS,
CredentialManagement.RESULT.CRED_PROTECT,
):
assert( i in cred_res )
):
assert i in cred_res
class TestCredentialManagement(object):
def test_get_info(self, info):
assert('credMgmt' in info.options)
assert(info.options['credMgmt'] == True)
assert(0x7 in info)
assert(info[0x7] > 1)
assert(0x8 in info)
assert(info[0x8] > 1)
assert "credMgmt" in info.options
assert info.options["credMgmt"] == True
assert 0x7 in info
assert info[0x7] > 1
assert 0x8 in info
assert info[0x8] > 1
def test_get_metadata(self, CredMgmt, MC_RK_Res):
metadata = CredMgmt.get_metadata()
@@ -159,12 +170,15 @@ class TestCredentialManagement(object):
pin_auth = hmac_sha256(PinToken, req.cdh)[:16]
rp = {"id": "example_3.com", "name": "John Doe 2"}
req = FidoRequest(
pin_protocol=1, pin_auth=pin_auth, options={"rk": True}, rp = rp,
pin_protocol=1,
pin_auth=pin_auth,
options={"rk": True},
rp=rp,
)
reg = device.sendMC(*req.toMC())
# make sure it works
req = FidoRequest(rp = rp)
req = FidoRequest(rp=rp)
auth = device.sendGA(*req.toGA())
verify(reg, auth, req.cdh)
@@ -172,15 +186,15 @@ class TestCredentialManagement(object):
# get the ID from enumeration
creds = CredMgmt.enumerate_creds(reg.auth_data.rp_id_hash)
for cred in creds:
if cred[7]['id'] == reg.auth_data.credential_data.credential_id:
if cred[7]["id"] == reg.auth_data.credential_data.credential_id:
break
# delete it
cred = {"id": cred[7]['id'], "type": "public-key"}
CredMgmt.delete_cred( cred )
cred = {"id": cred[7]["id"], "type": "public-key"}
CredMgmt.delete_cred(cred)
# make sure it doesn't work
req = FidoRequest(rp = rp)
req = FidoRequest(rp=rp)
with pytest.raises(CtapError) as e:
auth = device.sendGA(*req.toGA())
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
@@ -192,11 +206,14 @@ class TestCredentialManagement(object):
regs = []
# create 3 new RK's
for i in range(0,3):
for i in range(0, 3):
req = FidoRequest()
pin_auth = hmac_sha256(PinToken, req.cdh)[:16]
req = FidoRequest(
pin_protocol=1, pin_auth=pin_auth, options={"rk": True}, rp = rp,
pin_protocol=1,
pin_auth=pin_auth,
options={"rk": True},
rp=rp,
)
reg = device.sendMC(*req.toMC())
regs.append(reg)
@@ -208,19 +225,21 @@ class TestCredentialManagement(object):
# delete the middle one
creds = CredMgmt.enumerate_creds(reg.auth_data.rp_id_hash)
for cred in creds:
if cred[7]['id'] == regs[1].auth_data.credential_data.credential_id:
if cred[7]["id"] == regs[1].auth_data.credential_data.credential_id:
break
assert cred[7]['id'] == regs[1].auth_data.credential_data.credential_id
assert cred[7]["id"] == regs[1].auth_data.credential_data.credential_id
cred = {"id": cred[7]['id'], "type": "public-key"}
CredMgmt.delete_cred( cred )
cred = {"id": cred[7]["id"], "type": "public-key"}
CredMgmt.delete_cred(cred)
# Check one less enumerates
res = CredMgmt.enumerate_creds(regs[0].auth_data.rp_id_hash)
assert len(res) == 2
def test_multiple_creds_per_multiple_rps(self, device, PinToken, CredMgmt, MC_RK_Res):
def test_multiple_creds_per_multiple_rps(
self, device, PinToken, CredMgmt, MC_RK_Res
):
res = CredMgmt.enumerate_rps()
assert len(res) == 2
@@ -232,11 +251,14 @@ class TestCredentialManagement(object):
# create 3 new credentials per RP
for rp in new_rps:
for i in range(0,3):
for i in range(0, 3):
req = FidoRequest()
pin_auth = hmac_sha256(PinToken, req.cdh)[:16]
req = FidoRequest(
pin_protocol=1, pin_auth=pin_auth, options={"rk": True}, rp = rp,
pin_protocol=1,
pin_auth=pin_auth,
options={"rk": True},
rp=rp,
)
reg = device.sendMC(*req.toMC())
@@ -244,12 +266,16 @@ class TestCredentialManagement(object):
assert len(res) == 5
for rp in res:
if rp[3]['id'][:12] == 'new_example_':
creds = CredMgmt.enumerate_creds(sha256( rp[3]['id'].encode('utf8') ))
if rp[3]["id"][:12] == "new_example_":
creds = CredMgmt.enumerate_creds(sha256(rp[3]["id"].encode("utf8")))
assert len(creds) == 3
@pytest.mark.parametrize("enumeration_test", [_test_enumeration, _test_enumeration_interleaved])
def test_multiple_enumeration(self, device, PinToken, MC_RK_Res, CredMgmt, enumeration_test):
@pytest.mark.parametrize(
"enumeration_test", [_test_enumeration, _test_enumeration_interleaved]
)
def test_multiple_enumeration(
self, device, PinToken, MC_RK_Res, CredMgmt, enumeration_test
):
""" Test enumerate still works after different commands """
res = CredMgmt.enumerate_rps()
@@ -266,18 +292,19 @@ class TestCredentialManagement(object):
# create 3 new credentials per RP
for rp in new_rps:
for i in range(0,rp['count']):
for i in range(0, rp["count"]):
req = FidoRequest()
pin_auth = hmac_sha256(PinToken, req.cdh)[:16]
req = FidoRequest(
pin_protocol=1, pin_auth=pin_auth, options={"rk": True}, rp = {
"id": rp["id"], "name": rp["name"]
},
pin_protocol=1,
pin_auth=pin_auth,
options={"rk": True},
rp={"id": rp["id"], "name": rp["name"]},
)
reg = device.sendMC(*req.toMC())
# Now expect creds from this RP
expected_enumeration[rp['id']] = rp['count']
expected_enumeration[rp["id"]] = rp["count"]
enumeration_test(CredMgmt, expected_enumeration)
enumeration_test(CredMgmt, expected_enumeration)
@@ -287,9 +314,12 @@ class TestCredentialManagement(object):
enumeration_test(CredMgmt, expected_enumeration)
enumeration_test(CredMgmt, expected_enumeration)
@pytest.mark.parametrize("enumeration_test", [_test_enumeration, _test_enumeration_interleaved])
def test_multiple_enumeration_with_deletions(self, device, PinToken, MC_RK_Res, CredMgmt, enumeration_test):
@pytest.mark.parametrize(
"enumeration_test", [_test_enumeration, _test_enumeration_interleaved]
)
def test_multiple_enumeration_with_deletions(
self, device, PinToken, MC_RK_Res, CredMgmt, enumeration_test
):
""" Create each credential in random order. Test enumerate still works after randomly deleting each credential"""
res = CredMgmt.enumerate_rps()
@@ -308,14 +338,15 @@ class TestCredentialManagement(object):
# create new credentials per RP in random order
for rp in new_rps:
for i in range(0,rp['count']):
for i in range(0, rp["count"]):
req = FidoRequest()
pin_auth = hmac_sha256(PinToken, req.cdh)[:16]
req = FidoRequest(
pin_protocol=1, pin_auth=pin_auth, options={"rk": True}, rp = {
"id": rp["id"], "name": rp["name"]
},
user = generate_user_maximum(),
pin_protocol=1,
pin_auth=pin_auth,
options={"rk": True},
rp={"id": rp["id"], "name": rp["name"]},
user=generate_user_maximum(),
)
reg_requests.append(req)
@@ -324,10 +355,10 @@ class TestCredentialManagement(object):
reg_requests.remove(req)
device.sendMC(*req.toMC())
if req.rp['id'] not in expected_enumeration:
expected_enumeration[req.rp['id']] = 1
if req.rp["id"] not in expected_enumeration:
expected_enumeration[req.rp["id"]] = 1
else:
expected_enumeration[req.rp['id']] += 1
expected_enumeration[req.rp["id"]] += 1
enumeration_test(CredMgmt, expected_enumeration)
@@ -338,13 +369,13 @@ class TestCredentialManagement(object):
num = expected_enumeration[rp]
index = 0 if num == 1 else random.randint(0,num - 1)
cred = CredMgmt.enumerate_creds(sha256( rp.encode('utf8') ))[index]
index = 0 if num == 1 else random.randint(0, num - 1)
cred = CredMgmt.enumerate_creds(sha256(rp.encode("utf8")))[index]
# print('Delete %d index (%d total) cred of %s' % (index, expected_enumeration[rp], rp))
CredMgmt.delete_cred( {"id": cred[7]['id'], "type": "public-key"} )
CredMgmt.delete_cred({"id": cred[7]["id"], "type": "public-key"})
expected_enumeration[rp] -=1
expected_enumeration[rp] -= 1
if expected_enumeration[rp] == 0:
del expected_enumeration[rp]
@@ -353,7 +384,6 @@ class TestCredentialManagement(object):
enumeration_test(CredMgmt, expected_enumeration)
def _test_wrong_pinauth(self, device, cmd, PinToken):
credMgmt = CredMgmtWrongPinAuth(device, PinToken)
@@ -371,7 +401,7 @@ class TestCredentialManagement(object):
credMgmt = CredMgmtWrongPinAuth(device, PinToken)
for i in range(2):
time.sleep(.2)
time.sleep(0.2)
with pytest.raises(CtapError) as e:
cmd(credMgmt)
assert e.value.code == CtapError.ERR.PIN_AUTH_INVALID
@@ -384,7 +414,7 @@ class TestCredentialManagement(object):
credMgmt = CredMgmtWrongPinAuth(device, PinToken)
for i in range(2):
time.sleep(.2)
time.sleep(0.2)
with pytest.raises(CtapError) as e:
cmd(credMgmt)
assert e.value.code == CtapError.ERR.PIN_AUTH_INVALID
@@ -393,15 +423,16 @@ class TestCredentialManagement(object):
cmd(credMgmt)
assert e.value.code == CtapError.ERR.PIN_BLOCKED
class TestCredProtect(object):
def test_credProtect_0(self,resetDevice):
def test_credProtect_0(self, resetDevice):
req = FidoRequest(extensions={"credProtect": 0}, options={"rk": True})
res = resetDevice.sendMC(*req.toMC())
if res.auth_data.extensions:
assert "credProtect" not in res.auth_data.extensions
def test_credProtect_1(self,device):
def test_credProtect_1(self, device):
req = FidoRequest(extensions={"credProtect": 1}, options={"rk": True})
MCRes = device.sendMC(*req.toMC())
@@ -410,7 +441,10 @@ class TestCredProtect(object):
req = FidoRequest(
allow_list=[
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
{
"id": MCRes.auth_data.credential_data.credential_id,
"type": "public-key",
}
]
)
@@ -418,7 +452,7 @@ class TestCredProtect(object):
verify(MCRes, GARes, req.cdh)
assert (GARes.auth_data.flags & (1 << 2)) == 0
def test_credProtect_2_allow_list(self,device):
def test_credProtect_2_allow_list(self, device):
""" credProtect level 2 shouldn't need UV if allow_list is specified """
req = FidoRequest(extensions={"credProtect": 2}, options={"rk": True})
MCRes = device.sendMC(*req.toMC())
@@ -428,7 +462,10 @@ class TestCredProtect(object):
req = FidoRequest(
allow_list=[
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
{
"id": MCRes.auth_data.credential_data.credential_id,
"type": "public-key",
}
]
)
@@ -436,7 +473,7 @@ class TestCredProtect(object):
verify(MCRes, GARes, req.cdh)
assert (GARes.auth_data.flags & (1 << 2)) == 0
def test_credProtect_2_no_allow_list(self,device):
def test_credProtect_2_no_allow_list(self, device):
device.reset()
req = FidoRequest(extensions={"credProtect": 2}, options={"rk": True})
MCRes = device.sendMC(*req.toMC())
@@ -450,7 +487,7 @@ class TestCredProtect(object):
GARes = device.sendGA(*req.toGA())
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
def test_credProtect_3_allow_list_and_no_allow_list(self,device):
def test_credProtect_3_allow_list_and_no_allow_list(self, device):
""" credProtect level 3 requires UV """
device.reset()
req = FidoRequest(extensions={"credProtect": 3}, options={"rk": True})
@@ -461,7 +498,10 @@ class TestCredProtect(object):
req = FidoRequest(
allow_list=[
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
{
"id": MCRes.auth_data.credential_data.credential_id,
"type": "public-key",
}
]
)
@@ -475,16 +515,22 @@ class TestCredProtect(object):
GARes = device.sendGA(*req.toGA())
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
def test_credProtect_3_success(self,device):
def test_credProtect_3_success(self, device):
device.reset()
# Set a PIN
pin = '1234'
pin = "1234"
device.client.pin_protocol.set_pin(pin)
pin_token = device.client.pin_protocol.get_pin_token(pin)
req = FidoRequest()
pin_auth = hmac_sha256(pin_token, req.cdh)[:16]
req = FidoRequest(req, pin_auth = pin_auth, pin_protocol = 1, extensions={"credProtect": 3}, options={"rk": True})
req = FidoRequest(
req,
pin_auth=pin_auth,
pin_protocol=1,
extensions={"credProtect": 3},
options={"rk": True},
)
MCRes = device.sendMC(*req.toMC())
@@ -492,14 +538,16 @@ class TestCredProtect(object):
assert (MCRes.auth_data.flags & (1 << 2)) != 0
req = FidoRequest(
pin = pin,
pin_auth = pin_auth,
pin=pin,
pin_auth=pin_auth,
allow_list=[
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
]
{
"id": MCRes.auth_data.credential_data.credential_id,
"type": "public-key",
}
],
)
GARes = device.sendGA(*req.toGA())
assert (GARes.auth_data.flags & (1 << 2)) != 0
verify(MCRes, GARes, req.cdh)
+94 -60
View File
@@ -6,6 +6,7 @@ import hashlib
from fido2.ctap1 import ApduError
from fido2.ctap2 import CtapError
from fido2.utils import hmac_sha256, sha256, int2bytes
try:
from solo.client import SoloClient
except:
@@ -15,13 +16,14 @@ from solo.commands import SoloExtension
from tests.utils import shannon_entropy, verify, FidoRequest
def convert_der_sig_to_padded_binary(der):
r,s = ecdsa.util.sigdecode_der(der,None)
r, s = ecdsa.util.sigdecode_der(der, None)
r = int2bytes(r)
s = int2bytes(s)
r = (b'\x00' * (32 - len(r))) + r
s = (b'\x00' * (32 - len(s))) + s
r = (b"\x00" * (32 - len(r))) + r
s = (b"\x00" * (32 - len(s))) + s
return r + s
@@ -35,13 +37,12 @@ def solo(request, device):
sc.use_hid()
return sc
IS_EXPERIMENTAL = '--experimental' in sys.argv
IS_NFC = '--nfc' in sys.argv
@pytest.mark.skipif(
IS_NFC,
reason="Wrong transport"
)
IS_EXPERIMENTAL = "--experimental" in sys.argv
IS_NFC = "--nfc" in sys.argv
@pytest.mark.skipif(IS_NFC, reason="Wrong transport")
class TestSolo(object):
def test_solo(self, solo):
pass
@@ -61,10 +62,9 @@ class TestSolo(object):
assert len(solo.solo_version()) == 4
def test_version_hid(self, solo):
data = solo.send_data_hid(0x61, b'')
data = solo.send_data_hid(0x61, b"")
assert len(data) == 4
print(f'Version is {data[0]}.{data[1]}.{data[2]} locked?=={data[3]}')
print(f"Version is {data[0]}.{data[1]}.{data[2]} locked?=={data[3]}")
def test_bootloader_not(self, solo):
with pytest.raises(ApduError) as e:
@@ -88,71 +88,85 @@ class TestSolo(object):
solo.exchange = exchange
@pytest.mark.skipif(not IS_EXPERIMENTAL, reason="Experimental")
def test_load_external_key_wrong_length(self,solo, ):
def test_load_external_key_wrong_length(
self,
solo,
):
ext_key_cmd = 0x62
with pytest.raises(CtapError) as e:
solo.send_data_hid(ext_key_cmd, b'\x01' + b'wrong length'*2)
assert(e.value.code == CtapError.ERR.INVALID_LENGTH)
solo.send_data_hid(ext_key_cmd, b"\x01" + b"wrong length" * 2)
assert e.value.code == CtapError.ERR.INVALID_LENGTH
@pytest.mark.skipif(not IS_EXPERIMENTAL, reason="Experimental")
def test_load_external_key_invalidate_old_cred(self,solo, device, MCRes, GARes):
def test_load_external_key_invalidate_old_cred(self, solo, device, MCRes, GARes):
ext_key_cmd = 0x62
verify(MCRes, GARes)
print ('Enter user presence THREE times.')
solo.send_data_hid(ext_key_cmd, b'\x01' + b'Z' * 32 + b'dicekeys key')
print("Enter user presence THREE times.")
solo.send_data_hid(ext_key_cmd, b"\x01" + b"Z" * 32 + b"dicekeys key")
# Old credential should not exist now.
with pytest.raises(CtapError) as e:
ga_bad_req = FidoRequest(GARes)
device.sendGA(*ga_bad_req.toGA())
assert(e.value.code == CtapError.ERR.NO_CREDENTIALS)
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
@pytest.mark.skipif(not IS_EXPERIMENTAL, reason="Experimental")
def test_load_external_key(self,solo, device,):
def test_load_external_key(
self,
solo,
device,
):
key_A = b'A' * 32
key_B = b'B' * 32
key_A = b"A" * 32
key_B = b"B" * 32
ext_state = b"I'm a dicekey key"
version = b'\x01'
version = b"\x01"
ext_key_cmd = 0x62
print ('Enter user presence THREE times.')
print("Enter user presence THREE times.")
solo.send_data_hid(ext_key_cmd, version + key_A + ext_state)
# New credential works.
mc_A_req = FidoRequest()
mc_A_res = device.sendMC(*mc_A_req.toMC())
allow_list = [{"id":mc_A_res.auth_data.credential_data.credential_id, "type":"public-key"}]
allow_list = [
{
"id": mc_A_res.auth_data.credential_data.credential_id,
"type": "public-key",
}
]
ga_A_req = FidoRequest(mc_A_req, allow_list=allow_list)
ga_A_res = device.sendGA(*FidoRequest(ga_A_req).toGA())
verify(mc_A_res, ga_A_res, ga_A_req.cdh)
# Load up Key B and verify cred A doesn't exist.
print ('Enter user presence THREE times.')
print("Enter user presence THREE times.")
solo.send_data_hid(ext_key_cmd, version + key_B + ext_state)
with pytest.raises(CtapError) as e:
ga_A_res = device.sendGA(*FidoRequest(ga_A_req).toGA())
assert(e.value.code == CtapError.ERR.NO_CREDENTIALS)
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
# Load up Key A and verify cred A is back.
print ('Enter user presence THREE times.')
print("Enter user presence THREE times.")
solo.send_data_hid(ext_key_cmd, version + key_A + ext_state)
ga_A_res = device.sendGA(*FidoRequest(ga_A_req).toGA())
verify(mc_A_res, ga_A_res, ga_A_req.cdh)
@pytest.mark.skipif(not IS_EXPERIMENTAL, reason="Experimental")
def test_ext_state_in_credential_id(self,solo, device,):
def test_ext_state_in_credential_id(
self,
solo,
device,
):
key_A = b'A' * 32
key_A = b"A" * 32
ext_state = b"I'm a dicekey key abc1234!!@@##"
version = b'\x01'
version = b"\x01"
ext_key_cmd = 0x62
print ('Enter user presence THREE times.')
print("Enter user presence THREE times.")
solo.send_data_hid(ext_key_cmd, version + key_A + ext_state)
# New credential works.
@@ -162,15 +176,20 @@ class TestSolo(object):
assert ext_state in mc_A_res.auth_data.credential_data.credential_id
@pytest.mark.skipif(not IS_EXPERIMENTAL, reason="Experimental")
def test_backup_credential_is_generated_correctly(self,solo, device,):
def test_backup_credential_is_generated_correctly(
self,
solo,
device,
):
import seedweed
from binascii import hexlify
key_A = b'A' * 32
key_A = b"A" * 32
ext_state = b"I'm a dicekey key!"
version = b'\x01'
version = b"\x01"
ext_key_cmd = 0x62
print ('Enter user presence THREE times.')
print("Enter user presence THREE times.")
solo.send_data_hid(ext_key_cmd, version + key_A + ext_state)
# New credential works.
@@ -190,65 +209,80 @@ class TestSolo(object):
seedweed.validate_credential_id(key_A, credId, rpIdHash)
credMac = hmac_sha256(key_A, rpIdHash + version + uniqueId + ext_state)
allow_list = [{"id": mc_A_res.auth_data.credential_data.credential_id, "type": "public-key"}]
ga_req = FidoRequest(allow_list = allow_list)
allow_list = [
{
"id": mc_A_res.auth_data.credential_data.credential_id,
"type": "public-key",
}
]
ga_req = FidoRequest(allow_list=allow_list)
ga_res = device.sendGA(*ga_req.toGA())
verify(mc_A_res, ga_res, ga_req.cdh)
# Independently create the key and verify
_, _, keypair, iterations = seedweed.keypair_from_seed_mac(
key_A, credMac
)
_, _, keypair, iterations = seedweed.keypair_from_seed_mac(key_A, credMac)
assert iterations == 1
keypair.verifying_key.verify(
ga_res.signature,
ga_res.auth_data + ga_req.cdh,
sigdecode=ecdsa.util.sigdecode_der,
hashfunc=hashlib.sha256
hashfunc=hashlib.sha256,
)
# @pytest.mark.skipif(False, reason="Experimental")
@pytest.mark.skipif(not IS_EXPERIMENTAL, reason="Experimental")
def test_seedweed_vectors_make_credential(self,solo, device,):
def test_seedweed_vectors_make_credential(
self,
solo,
device,
):
import seedweed
from binascii import hexlify
version = b'\x01'
for i,v in enumerate(seedweed.load_test_vectors(shortlist=True)):
print (f'{i}) Enter user presence THREE times.')
version = b"\x01"
for i, v in enumerate(seedweed.load_test_vectors(shortlist=True)):
print(f"{i}) Enter user presence THREE times.")
ext_key_cmd = 0x62
solo.send_data_hid(ext_key_cmd, version + v['seed'] + b'')
solo.send_data_hid(ext_key_cmd, version + v["seed"] + b"")
mc_req = FidoRequest(rp = {"id": v['rp_id'], "name": "seedweed"})
mc_req = FidoRequest(rp={"id": v["rp_id"], "name": "seedweed"})
mc_res = device.sendMC(*mc_req.toMC())
seedweed.conformance.verify_make_credential(
v,
mc_res.auth_data.credential_data.credential_id,
mc_res.auth_data.credential_data.public_key[-2] +
mc_res.auth_data.credential_data.public_key[-3]
mc_res.auth_data.credential_data.public_key[-2]
+ mc_res.auth_data.credential_data.public_key[-3],
)
@pytest.mark.skipif(not IS_EXPERIMENTAL, reason="Experimental")
def test_seedweed_vectors_get_assertion(self,solo, device,):
def test_seedweed_vectors_get_assertion(
self,
solo,
device,
):
import seedweed
from binascii import hexlify
version = b'\x01'
for i,v in enumerate(seedweed.load_test_vectors(shortlist=True)):
print (f'{i}) Enter user presence THREE times.')
version = b"\x01"
for i, v in enumerate(seedweed.load_test_vectors(shortlist=True)):
print(f"{i}) Enter user presence THREE times.")
ext_key_cmd = 0x62
solo.send_data_hid(ext_key_cmd, version + v['seed'] + b'')
solo.send_data_hid(ext_key_cmd, version + v["seed"] + b"")
allow_list = [{"id": v['credential_id'], "type": "public-key"}]
ga_req = FidoRequest(rp = {"id": v['rp_id'], "name": "seedweed"}, allow_list = allow_list)
allow_list = [{"id": v["credential_id"], "type": "public-key"}]
ga_req = FidoRequest(
rp={"id": v["rp_id"], "name": "seedweed"}, allow_list=allow_list
)
ga_res = device.sendGA(*ga_req.toGA())
# print(v)
# print(ga_res.auth_data + ga_req.cdh)
# assert ga_res.auth_data.rp_id_hash == reg.auth_data.rp_id_hash
assert ga_res.credential["id"] == v['credential_id']
assert ga_res.credential["id"] == v["credential_id"]
# reg.auth_data.credential_data.credential_id
seedweed.conformance.verify_get_assertion(