@@ -4,7 +4,7 @@ from fido2.client import Fido2Client, WindowsClient, UserInteraction, ClientErro
|
||||
from fido2.ctap2.pin import ClientPin
|
||||
from fido2.server import Fido2Server
|
||||
from fido2.ctap import CtapError
|
||||
from fido2.webauthn import CollectedClientData
|
||||
from fido2.webauthn import CollectedClientData, AttestedCredentialData
|
||||
from getpass import getpass
|
||||
import sys
|
||||
import pytest
|
||||
@@ -106,11 +106,15 @@ class Device():
|
||||
self.__set_server(rp=self.__rp, attestation=self.__attestation)
|
||||
|
||||
def MC(self, client_data_hash=Ellipsis, rp=Ellipsis, user=Ellipsis, key_params=Ellipsis, exclude_list=None, extensions=None, options=None, pin_uv_param=None, pin_uv_protocol=None, enterprise_attestation=None):
|
||||
client_data_hash = client_data_hash if client_data_hash is not Ellipsis else os.urandom(32)
|
||||
rp = rp if rp is not Ellipsis else self.__rp
|
||||
user = user if user is not Ellipsis else self.user()
|
||||
key_params = key_params if key_params is not Ellipsis else self.__server.allowed_algorithms
|
||||
att_obj = self.__client._backend.ctap2.make_credential(
|
||||
client_data_hash=client_data_hash if client_data_hash is not Ellipsis else os.urandom(32),
|
||||
rp=rp if rp is not Ellipsis else self.__rp,
|
||||
user=user if user is not Ellipsis else self.user(),
|
||||
key_params=key_params if key_params is not Ellipsis else self.__server.allowed_algorithms,
|
||||
client_data_hash=client_data_hash,
|
||||
rp=rp,
|
||||
user=user,
|
||||
key_params=key_params,
|
||||
exclude_list=exclude_list,
|
||||
extensions=extensions,
|
||||
options=options,
|
||||
@@ -118,17 +122,23 @@ class Device():
|
||||
pin_uv_protocol=pin_uv_protocol,
|
||||
enterprise_attestation=enterprise_attestation
|
||||
)
|
||||
return att_obj
|
||||
return {'res':att_obj,'req':{'client_data_hash':client_data_hash,
|
||||
'rp':rp,
|
||||
'user':user,
|
||||
'key_params':key_params}}
|
||||
|
||||
def doMC(self, client_data=Ellipsis, rp=Ellipsis, user=Ellipsis, key_params=Ellipsis, exclude_list=None, extensions=None, rk=None, user_verification=None, enterprise_attestation=None, event=None):
|
||||
|
||||
result = self.__client._backend.do_make_credential(
|
||||
client_data=client_data if client_data is not Ellipsis else CollectedClientData.create(
|
||||
client_data = client_data if client_data is not Ellipsis else CollectedClientData.create(
|
||||
type=CollectedClientData.TYPE.CREATE, origin=self.__origin, challenge=os.urandom(32)
|
||||
),
|
||||
rp=rp if rp is not Ellipsis else self.__rp,
|
||||
user=user if user is not Ellipsis else self.user(),
|
||||
key_params=key_params if key_params is not Ellipsis else self.__server.allowed_algorithms,
|
||||
)
|
||||
rp = rp if rp is not Ellipsis else self.__rp
|
||||
user = user if user is not Ellipsis else self.user()
|
||||
key_params = key_params if key_params is not Ellipsis else self.__server.allowed_algorithms
|
||||
result = self.__client._backend.do_make_credential(
|
||||
client_data=client_data,
|
||||
rp=rp,
|
||||
user=user,
|
||||
key_params=key_params,
|
||||
exclude_list=exclude_list,
|
||||
extensions=extensions,
|
||||
rk=rk,
|
||||
@@ -136,7 +146,10 @@ class Device():
|
||||
enterprise_attestation=enterprise_attestation,
|
||||
event=event
|
||||
)
|
||||
return result
|
||||
return {'res':result,'req':{'client_data':client_data,
|
||||
'rp':rp,
|
||||
'user':user,
|
||||
'key_params':key_params}}
|
||||
|
||||
def try_make_credential(self, options=None):
|
||||
if (options is None):
|
||||
@@ -202,32 +215,38 @@ class Device():
|
||||
print("AUTH DATA:", result.authenticator_data)
|
||||
|
||||
def GA(self, rp_id=Ellipsis, client_data_hash=Ellipsis, allow_list=None, extensions=None, options=None, pin_uv_param=None, pin_uv_protocol=None):
|
||||
rp_id = rp_id if rp_id is not Ellipsis else self.__rp['id']
|
||||
client_data_hash = client_data_hash if client_data_hash is not Ellipsis else os.urandom(32)
|
||||
att_obj = self.__client._backend.ctap2.get_assertion(
|
||||
rp_id=rp_id if rp_id is not Ellipsis else self.__rp['id'],
|
||||
client_data_hash=client_data_hash if client_data_hash is not Ellipsis else os.urandom(32),
|
||||
rp_id=rp_id,
|
||||
client_data_hash=client_data_hash,
|
||||
allow_list=allow_list,
|
||||
extensions=extensions,
|
||||
options=options,
|
||||
pin_uv_param=pin_uv_param,
|
||||
pin_uv_protocol=pin_uv_protocol
|
||||
)
|
||||
return att_obj
|
||||
return {'res':att_obj,'req':{'rp_id':rp_id,
|
||||
'client_data_hash':client_data_hash}}
|
||||
|
||||
def GNA(self):
|
||||
return self.__client._backend.ctap2.get_next_assertion()
|
||||
|
||||
def doGA(self, client_data=Ellipsis, rp_id=Ellipsis, allow_list=None, extensions=None, user_verification=None, event=None):
|
||||
result = self.__client._backend.do_get_assertion(
|
||||
client_data=client_data if client_data is not Ellipsis else CollectedClientData.create(
|
||||
client_data = client_data if client_data is not Ellipsis else CollectedClientData.create(
|
||||
type=CollectedClientData.TYPE.CREATE, origin=self.__origin, challenge=os.urandom(32)
|
||||
),
|
||||
rp_id=rp_id if rp_id is not Ellipsis else self.__rp['id'],
|
||||
)
|
||||
rp_id = rp_id if rp_id is not Ellipsis else self.__rp['id']
|
||||
result = self.__client._backend.do_get_assertion(
|
||||
client_data=client_data,
|
||||
rp_id=rp_id,
|
||||
allow_list=allow_list,
|
||||
extensions=extensions,
|
||||
user_verification=user_verification,
|
||||
event=event
|
||||
)
|
||||
return result
|
||||
return {'res':result,'req':{'client_data':client_data,
|
||||
'rp_id':rp_id}}
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
@@ -241,7 +260,7 @@ def info(device):
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def MCRes(device, *args):
|
||||
return device.doMC(*args).attestation_object
|
||||
return device.doMC(*args)
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def resetdevice(device):
|
||||
@@ -250,18 +269,24 @@ def resetdevice(device):
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def GARes(device, MCRes, *args):
|
||||
r = device.doGA(allow_list=[
|
||||
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
res = device.doGA(allow_list=[
|
||||
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
], *args)
|
||||
return r
|
||||
credential_data = AttestedCredentialData(MCRes['res'].attestation_object.auth_data.credential_data)
|
||||
assertions = res['res'].get_assertions()
|
||||
for a in assertions:
|
||||
a.verify(res['req']['client_data'].hash, credential_data.public_key)
|
||||
return res
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def MCRes_DC(device, *args):
|
||||
return device.doMC(rk=True, *args).attestation_object
|
||||
return device.doMC(rk=True, *args)
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def GARes_DC(device, MCRes_DC, *args):
|
||||
r = device.GA(allow_list=[
|
||||
{"id": MCRes_DC.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
res = device.GA(allow_list=[
|
||||
{"id": MCRes_DC['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
], *args)
|
||||
return r
|
||||
credential_data = AttestedCredentialData(MCRes_DC['res'].attestation_object.auth_data.credential_data)
|
||||
res['res'].verify(res['req']['client_data_hash'], credential_data.public_key)
|
||||
return res
|
||||
|
||||
@@ -10,17 +10,17 @@ def test_authenticate(device):
|
||||
AUTRes = device.authenticate(credentials)
|
||||
|
||||
def test_assertion_auth_data(GARes):
|
||||
assert len(GARes.get_response(0).authenticator_data) == 37
|
||||
assert len(GARes['res'].get_response(0).authenticator_data) == 37
|
||||
|
||||
def test_Check_that_AT_flag_is_not_set(GARes):
|
||||
assert (GARes.get_response(0).authenticator_data.flags & 0xF8) == 0
|
||||
assert (GARes['res'].get_response(0).authenticator_data.flags & 0xF8) == 0
|
||||
|
||||
def test_that_user_credential_and_numberOfCredentials_are_not_present(device, MCRes):
|
||||
res = device.GA(allow_list=[
|
||||
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
])
|
||||
assert res.user == None
|
||||
assert res.number_of_credentials == None
|
||||
assert res['res'].user == None
|
||||
assert res['res'].number_of_credentials == None
|
||||
|
||||
def test_empty_allowList(device):
|
||||
with pytest.raises(CtapError) as e:
|
||||
@@ -41,7 +41,7 @@ def test_get_assertion_allow_list_filtering_and_buffering(device):
|
||||
|
||||
l1 = 4
|
||||
for i in range(0, l1):
|
||||
res = device.doMC(rp=rp1).attestation_object
|
||||
res = device.doMC(rp=rp1)['res'].attestation_object
|
||||
rp1_registrations.append(res)
|
||||
allow_list.append({
|
||||
"id": res.auth_data.credential_data.credential_id[:],
|
||||
@@ -50,7 +50,7 @@ def test_get_assertion_allow_list_filtering_and_buffering(device):
|
||||
|
||||
l2 = 6
|
||||
for i in range(0, l2):
|
||||
res = device.doMC(rp=rp2).attestation_object
|
||||
res = device.doMC(rp=rp2)['res'].attestation_object
|
||||
rp2_registrations.append(res)
|
||||
allow_list.append({
|
||||
"id": res.auth_data.credential_data.credential_id[:],
|
||||
@@ -66,10 +66,10 @@ def test_get_assertion_allow_list_filtering_and_buffering(device):
|
||||
# cached.
|
||||
|
||||
# Should authenticate to all credentials matching rp1
|
||||
rp1_assertions = device.doGA(rp_id=rp1['id'], allow_list=allow_list).get_assertions()
|
||||
rp1_assertions = device.doGA(rp_id=rp1['id'], allow_list=allow_list)['res'].get_assertions()
|
||||
|
||||
# Should authenticate to all credentials matching rp2
|
||||
rp2_assertions = device.doGA(rp_id=rp2['id'], allow_list=allow_list).get_assertions()
|
||||
rp2_assertions = device.doGA(rp_id=rp2['id'], allow_list=allow_list)['res'].get_assertions()
|
||||
|
||||
counts = (
|
||||
len(rp1_assertions),
|
||||
@@ -80,14 +80,14 @@ def test_get_assertion_allow_list_filtering_and_buffering(device):
|
||||
|
||||
def test_corrupt_credId(device, MCRes):
|
||||
# apply bit flip
|
||||
badid = list(MCRes.auth_data.credential_data.credential_id[:])
|
||||
badid = list(MCRes['res'].attestation_object.auth_data.credential_data.credential_id[:])
|
||||
badid[len(badid) // 2] = badid[len(badid) // 2] ^ 1
|
||||
badid = bytes(badid)
|
||||
|
||||
allow_list = [{"id": badid, "type": "public-key"}]
|
||||
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.doGA(allow_list=allow_list)
|
||||
device.doGA(allow_list=allow_list)['res']
|
||||
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
|
||||
|
||||
def test_mismatched_rp(device, GARes):
|
||||
@@ -124,38 +124,38 @@ def test_bad_allow_list(device):
|
||||
def test_bad_allow_list_item(device, MCRes):
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.doGA(allow_list=["wrong"] + [
|
||||
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
]
|
||||
)
|
||||
|
||||
def test_unknown_option(device, MCRes):
|
||||
device.GA(options={"unknown": True}, allow_list=[
|
||||
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
])
|
||||
|
||||
def test_option_uv(device, info, GARes):
|
||||
if "uv" in info.options:
|
||||
if info.options["uv"]:
|
||||
res = device.doGA(options={"uv": True})
|
||||
res = device.doGA(options={"uv": True})['res']
|
||||
assert res.auth_data.flags & (1 << 2)
|
||||
|
||||
def test_option_up(device, info, GARes):
|
||||
if "up" in info.options:
|
||||
if info.options["up"]:
|
||||
res = device.doGA(options={"up": True})
|
||||
res = device.doGA(options={"up": True})['res']
|
||||
assert res.auth_data.flags & (1 << 0)
|
||||
|
||||
def test_allow_list_fake_item(device, MCRes):
|
||||
device.doGA(allow_list=[{"type": "rot13", "id": b"1234"}]
|
||||
+ [
|
||||
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
],
|
||||
)
|
||||
|
||||
def test_allow_list_missing_field(device, MCRes):
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.doGA(allow_list=[{"id": b"1234"}] + [
|
||||
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
]
|
||||
)
|
||||
|
||||
@@ -163,7 +163,7 @@ def test_allow_list_field_wrong_type(device, MCRes):
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.doGA(allow_list=[{"type": b"public-key", "id": b"1234"}]
|
||||
+ [
|
||||
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
]
|
||||
)
|
||||
|
||||
@@ -171,20 +171,20 @@ def test_allow_list_id_wrong_type(device, MCRes):
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.doGA(allow_list=[{"type": "public-key", "id": 42}]
|
||||
+ [
|
||||
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
]
|
||||
)
|
||||
|
||||
def test_allow_list_missing_id(device, MCRes):
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.doGA(allow_list=[{"type": "public-key"}] + [
|
||||
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
]
|
||||
)
|
||||
|
||||
def test_user_presence_option_false(device, MCRes):
|
||||
res = device.GA(options={"up": False}, allow_list=[
|
||||
{"id": MCRes.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
])
|
||||
|
||||
def test_credential_resets(device, MCRes, GARes):
|
||||
|
||||
@@ -46,11 +46,11 @@ def generate_user_maximum():
|
||||
|
||||
@pytest.mark.parametrize("do_reboot", [False, True])
|
||||
def test_user_info_returned_when_using_allowlist(device, MCRes_DC, GARes_DC, do_reboot):
|
||||
assert "id" in GARes_DC.user.keys()
|
||||
assert "id" in GARes_DC['res'].user.keys()
|
||||
|
||||
allow_list = [
|
||||
{
|
||||
"id": MCRes_DC.auth_data.credential_data.credential_id[:],
|
||||
"id": MCRes_DC['res'].attestation_object.auth_data.credential_data.credential_id[:],
|
||||
"type": "public-key",
|
||||
}
|
||||
]
|
||||
@@ -58,23 +58,23 @@ def test_user_info_returned_when_using_allowlist(device, MCRes_DC, GARes_DC, do_
|
||||
if do_reboot:
|
||||
device.reboot()
|
||||
|
||||
ga_res = device.GA(allow_list=allow_list)
|
||||
ga_res = device.GA(allow_list=allow_list)['res']
|
||||
|
||||
assert device.user()["id"] == ga_res.user["id"]
|
||||
assert MCRes_DC["req"]["user"]["id"] == ga_res.user["id"]
|
||||
|
||||
def test_with_allow_list_after_reset(device, MCRes_DC, GARes_DC):
|
||||
assert "id" in GARes_DC.user.keys()
|
||||
assert "id" in GARes_DC['res'].user.keys()
|
||||
|
||||
allow_list = [
|
||||
{
|
||||
"id": MCRes_DC.auth_data.credential_data.credential_id[:],
|
||||
"id": MCRes_DC['res'].attestation_object.auth_data.credential_data.credential_id[:],
|
||||
"type": "public-key",
|
||||
}
|
||||
]
|
||||
|
||||
ga_res = device.GA(allow_list=allow_list)
|
||||
ga_res = device.GA(allow_list=allow_list)['res']
|
||||
|
||||
assert device.user()["id"] == ga_res.user["id"]
|
||||
assert MCRes_DC["req"]["user"]["id"] == ga_res.user["id"]
|
||||
|
||||
device.reset()
|
||||
|
||||
@@ -91,16 +91,16 @@ def test_resident_key_auth(MCRes_DC, GARes_DC):
|
||||
pass
|
||||
|
||||
def test_user_info_returned(device, MCRes_DC, GARes_DC):
|
||||
assert "id" in GARes_DC.user.keys()
|
||||
assert "id" in GARes_DC['res'].user.keys()
|
||||
assert (
|
||||
MCRes_DC.auth_data.credential_data.credential_id
|
||||
== GARes_DC.credential["id"]
|
||||
MCRes_DC['res'].attestation_object.auth_data.credential_data.credential_id
|
||||
== GARes_DC['res'].credential["id"]
|
||||
)
|
||||
assert device.user()["id"] == GARes_DC.user["id"]
|
||||
if not GARes_DC.number_of_credentials:
|
||||
assert "id" in GARes_DC.user.keys() and len(GARes_DC.user.keys()) == 1
|
||||
assert MCRes_DC["req"]["user"]["id"] == GARes_DC['res'].user["id"]
|
||||
if not GARes_DC['res'].number_of_credentials:
|
||||
assert "id" in GARes_DC['res'].user.keys() and len(GARes_DC['res'].user.keys()) == 1
|
||||
else:
|
||||
assert device.user() == GARes_DC.user
|
||||
assert MCRes_DC["req"]["user"] == GARes_DC['res'].user
|
||||
|
||||
|
||||
def test_multiple_rk_nodisplay(device, MCRes_DC):
|
||||
@@ -113,7 +113,7 @@ def test_multiple_rk_nodisplay(device, MCRes_DC):
|
||||
regs.append(res)
|
||||
# time.sleep(2)
|
||||
|
||||
res = device.doGA(rp_id=rp['id'])
|
||||
res = device.doGA(rp_id=rp['id'])['res']
|
||||
auths = res.get_assertions()
|
||||
|
||||
assert len(regs) == 3
|
||||
@@ -125,21 +125,20 @@ def test_multiple_rk_nodisplay(device, MCRes_DC):
|
||||
print("FAIL: %s was not in user: " % y, x.user)
|
||||
|
||||
|
||||
def test_rk_maximum_size_nodisplay(device, MCRes_DC):
|
||||
def test_rk_maximum_size_nodisplay(device):
|
||||
"""
|
||||
Check the lengths of the fields according to the FIDO2 spec
|
||||
https://github.com/solokeys/solo/issues/158#issue-426613303
|
||||
https://www.w3.org/TR/webauthn/#dom-publickeycredentialuserentity-displayname
|
||||
"""
|
||||
auths = []
|
||||
device.reset()
|
||||
user_max = generate_user_maximum()
|
||||
print(user_max)
|
||||
resMC = device.doMC(user=user_max)
|
||||
resGA = device.doGA()
|
||||
resMC = device.doMC(user=user_max, rk=True)
|
||||
resGA = device.doGA()['res']
|
||||
auths = resGA.get_assertions()
|
||||
|
||||
user_max_GA = auths[0]
|
||||
|
||||
print(auths)
|
||||
for y in ("name", "displayName", "id"):
|
||||
assert user_max_GA.user[y] == user_max[y]
|
||||
|
||||
@@ -172,20 +171,18 @@ def test_rk_maximum_list_capacity_per_rp_nodisplay(info, device, MCRes_DC):
|
||||
regs = [MCRes_DC]
|
||||
RK_to_generate = RK_CAPACITY_PER_RP - current_credentials_count
|
||||
for i in range(RK_to_generate):
|
||||
req = FidoRequest(MCRes_DC, user=get_user(), rp = rp)
|
||||
res = device.sendMC(*req.toMC())
|
||||
res = device.doMC(user=get_user(), rp=rp, rk=True)['res'].attestation_object
|
||||
regs.append(res)
|
||||
|
||||
req = FidoRequest(MCRes_DC, options=None, user=generate_user_maximum(), rp = rp)
|
||||
res = device.sendGA(*req.toGA())
|
||||
res = device.GA(rp_id = rp['id'])['res']
|
||||
assert res.number_of_credentials == RK_CAPACITY_PER_RP
|
||||
|
||||
auths.append(res)
|
||||
for i in range(RK_CAPACITY_PER_RP - 1):
|
||||
auths.append(device.ctap2.get_next_assertion())
|
||||
auths.append(device.GNA())
|
||||
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.ctap2.get_next_assertion()
|
||||
device.GNA()
|
||||
|
||||
auths = auths[::-1][-RK_to_generate:]
|
||||
regs = regs[-RK_to_generate:]
|
||||
@@ -193,29 +190,24 @@ def test_rk_maximum_list_capacity_per_rp_nodisplay(info, device, MCRes_DC):
|
||||
|
||||
assert len(auths) == len(users)
|
||||
|
||||
if MCRes_DC.request.pin_protocol:
|
||||
for x, u in zip(auths, users):
|
||||
for y in ("name", "icon", "displayName", "id"):
|
||||
assert y in x.user.keys()
|
||||
assert x.user[y] == u[y]
|
||||
for x, u in zip(auths, users):
|
||||
for y in ("name", "displayName", "id"):
|
||||
assert y in x.user.keys()
|
||||
assert x.user[y] == u[y]
|
||||
|
||||
assert len(auths) == len(regs)
|
||||
for x, y in zip(regs, auths):
|
||||
verify(x, y, req.cdh)
|
||||
|
||||
|
||||
def test_rk_with_allowlist_of_different_rp(resetDevice):
|
||||
def test_rk_with_allowlist_of_different_rp(resetdevice):
|
||||
"""
|
||||
Test that a rk credential is not found when using an allowList item for a different RP
|
||||
"""
|
||||
|
||||
rk_rp = {"id": "rk-cred.org", "name": "Example"}
|
||||
rk_req = FidoRequest(rp = rk_rp, options={"rk": True})
|
||||
rk_res = resetDevice.sendMC(*rk_req.toMC())
|
||||
rk_res = resetdevice.doMC(rp = rk_rp, rk=True)['res'].attestation_object
|
||||
|
||||
server_rp = {"id": "server-cred.com", "name": "Example"}
|
||||
server_req = FidoRequest(rp = server_rp)
|
||||
server_res = resetDevice.sendMC(*server_req.toMC())
|
||||
server_res = resetdevice.doMC(rp = server_rp, rk=True)['res'].attestation_object
|
||||
|
||||
allow_list_with_different_rp_cred = [
|
||||
{
|
||||
@@ -224,43 +216,39 @@ def test_rk_with_allowlist_of_different_rp(resetDevice):
|
||||
}
|
||||
]
|
||||
|
||||
test_req = FidoRequest(rp = rk_rp, allow_list = allow_list_with_different_rp_cred)
|
||||
|
||||
with pytest.raises(CtapError) as e:
|
||||
res = resetDevice.sendGA(*test_req.toGA())
|
||||
res = resetdevice.doGA(rp_id = rk_rp['id'], allow_list = allow_list_with_different_rp_cred)
|
||||
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
|
||||
|
||||
|
||||
def test_same_userId_overwrites_rk(resetDevice):
|
||||
def test_same_userId_overwrites_rk(resetdevice):
|
||||
"""
|
||||
A make credential request with a UserId & Rp that is the same as an existing one should overwrite.
|
||||
"""
|
||||
rp = {"id": "overwrite.org", "name": "Example"}
|
||||
user = generate_user()
|
||||
user = generate_random_user()
|
||||
|
||||
req = FidoRequest(rp = rp, options={"rk": True}, user = user)
|
||||
mc_res1 = resetDevice.sendMC(*req.toMC())
|
||||
mc_res1 = resetdevice.doMC(rp = rp, rk=True, user = user)
|
||||
|
||||
# Should overwrite the first credential.
|
||||
mc_res2 = resetDevice.sendMC(*req.toMC())
|
||||
mc_res2 = resetdevice.doMC(rp = rp, rk=True, user = user)
|
||||
|
||||
ga_res = resetDevice.sendGA(*req.toGA())
|
||||
ga_res = resetdevice.GA(rp_id=rp['id'])['res']
|
||||
|
||||
# If there's only one credential, this is None
|
||||
assert ga_res.number_of_credentials == None
|
||||
|
||||
verify(mc_res2, ga_res, req.cdh)
|
||||
|
||||
def test_larger_icon_than_128(device):
|
||||
"""
|
||||
Test it works if we give an icon value larger than 128 bytes
|
||||
"""
|
||||
rp = {"id": "overwrite.org", "name": "Example"}
|
||||
user = generate_user()
|
||||
user = generate_random_user()
|
||||
user['icon'] = 'https://www.w3.org/TR/webauthn/?icon=' + ("A" * 128)
|
||||
|
||||
req = FidoRequest(rp = rp, options={"rk": True}, user = user)
|
||||
device.sendMC(*req.toMC())
|
||||
device.doMC(rp = rp, rk=True, user = user)
|
||||
|
||||
|
||||
def test_returned_credential(device):
|
||||
@@ -269,29 +257,24 @@ def test_returned_credential(device):
|
||||
only 1 will get returned.
|
||||
"""
|
||||
device.reset()
|
||||
pin = '12345'
|
||||
device.client.pin_protocol.set_pin(pin)
|
||||
req = FidoRequest(pin = pin, options={"rk": True})
|
||||
|
||||
regs = []
|
||||
allow_list = []
|
||||
for i in range(0, 2):
|
||||
req = FidoRequest(req, user = {
|
||||
res = device.doMC(rk=True, user = {
|
||||
"id": b'123456' + bytes([i]), "name": f'Test User {i}', "displayName": f'Test User display {i}'
|
||||
})
|
||||
res = device.sendMC(*req.toMC())
|
||||
setattr(res, "request", req)
|
||||
})['res'].attestation_object
|
||||
regs.append(res)
|
||||
allow_list.append({"id": res.auth_data.credential_data.credential_id[:], "type": "public-key"})
|
||||
|
||||
|
||||
print('allow_list: ' , allow_list)
|
||||
ga_req = FidoRequest(pin = pin, allow_list=allow_list)
|
||||
ga_res = device.sendGA(*ga_req.toGA())
|
||||
ga_res = device.GA(allow_list=allow_list)['res']
|
||||
print(ga_res)
|
||||
|
||||
# No other credentials should be returned
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.ctap2.get_next_assertion()
|
||||
device.GNA()
|
||||
|
||||
# the returned credential should have user id in it
|
||||
print(ga_res)
|
||||
|
||||
@@ -11,10 +11,10 @@ def test_make_credential():
|
||||
pass
|
||||
|
||||
def test_attestation_format(MCRes):
|
||||
assert MCRes.fmt in ["packed", "tpm", "android-key", "adroid-safetynet"]
|
||||
assert MCRes['res'].attestation_object.fmt in ["packed", "tpm", "android-key", "adroid-safetynet"]
|
||||
|
||||
def test_authdata_length(MCRes):
|
||||
assert len(MCRes.auth_data) >= 77
|
||||
assert len(MCRes['res'].attestation_object.auth_data) >= 77
|
||||
|
||||
def test_missing_cdh(device):
|
||||
with pytest.raises(CtapError) as e:
|
||||
@@ -152,7 +152,7 @@ def test_bad_type_exclude_list_type(device):
|
||||
device.doMC(exclude_list=[{"type": b"public-key", "id": b"1234"}])
|
||||
|
||||
def test_exclude_list_excluded(device):
|
||||
res = device.doMC().attestation_object
|
||||
res = device.doMC()['res'].attestation_object
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.doMC(exclude_list=[
|
||||
{"id": res.auth_data.credential_data.credential_id, "type": "public-key"}
|
||||
|
||||
Reference in New Issue
Block a user