CredMgmt must be redeclared everytime, since PinToken might be changed due to underlaying doMC.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2022-12-09 18:42:59 +01:00
parent 00ba0db87a
commit 866d69a82d

View File

@@ -17,14 +17,6 @@ def client_pin_set(request, device, client_pin):
pin = request.param pin = request.param
client_pin.set_pin(pin) client_pin.set_pin(pin)
@pytest.fixture(params=[PIN], scope = 'function')
def PinToken(request, device, client_pin):
pin = request.param
token = client_pin.get_pin_token(pin, permissions=ClientPin.PERMISSION.MAKE_CREDENTIAL | ClientPin.PERMISSION.CREDENTIAL_MGMT)
print(f"GET TOKEN {hexlify(token)}")
return token
@pytest.fixture(scope = 'function') @pytest.fixture(scope = 'function')
def MC_RK_Res(device, client_pin_set): def MC_RK_Res(device, client_pin_set):
rp = {"id": "ssh:", "name": "Bate Goiko"} rp = {"id": "ssh:", "name": "Bate Goiko"}
@@ -33,51 +25,54 @@ def MC_RK_Res(device, client_pin_set):
rp = {"id": "xakcop.com", "name": "John Doe"} rp = {"id": "xakcop.com", "name": "John Doe"}
device.doMC(rp=rp, rk=True) device.doMC(rp=rp, rk=True)
def PinToken(device):
return ClientPin(device.client()._backend.ctap2).get_pin_token(PIN, permissions=ClientPin.PERMISSION.MAKE_CREDENTIAL | ClientPin.PERMISSION.CREDENTIAL_MGMT)
@pytest.fixture(scope = 'function') def CredMgmt(device):
def CredMgmt(device, PinToken): pt = PinToken(device)
pin_protocol = PinProtocolV2() pin_protocol = PinProtocolV2()
return CredentialManagement(device.client()._backend.ctap2, pin_protocol, PinToken) return CredentialManagement(device.client()._backend.ctap2, pin_protocol, pt)
def _test_enumeration(CredMgmt, rp_map): def _test_enumeration(device, rp_map):
"Enumerate credentials using BFS" "Enumerate credentials using BFS"
res = CredMgmt.enumerate_rps() res = CredMgmt(device).enumerate_rps()
assert len(rp_map.keys()) == len(res) assert len(rp_map.keys()) == len(res)
for rp in res: for rp in res:
creds = CredMgmt.enumerate_creds(sha256(rp[3]["id"])) creds = CredMgmt(device).enumerate_creds(sha256(rp[3]["id"].encode()))
assert len(creds) == rp_map[rp[3]["id"].decode()] assert len(creds) == rp_map[rp[3]["id"]]
def _test_enumeration_interleaved(CredMgmt, rp_map): def _test_enumeration_interleaved(device, rp_map):
"Enumerate credentials using DFS" "Enumerate credentials using DFS"
first_rp = CredMgmt.enumerate_rps_begin() first_rp = CredMgmt(device).enumerate_rps_begin()
assert len(rp_map.keys()) == first_rp[CredentialManagement.RESULT.TOTAL_RPS] assert len(rp_map.keys()) == first_rp[CredentialManagement.RESULT.TOTAL_RPS]
rk_count = 1 rk_count = 1
first_rk = CredMgmt.enumerate_creds_begin(sha256(first_rp[3]["id"])) first_rk = CredMgmt(device).enumerate_creds_begin(sha256(first_rp[3]["id"].encode()))
for i in range(1, first_rk[CredentialManagement.RESULT.TOTAL_CREDENTIALS]): for i in range(1, first_rk[CredentialManagement.RESULT.TOTAL_CREDENTIALS]):
c = CredMgmt.enumerate_creds_next() c = CredMgmt(device).enumerate_creds_next()
rk_count += 1 rk_count += 1
assert rk_count == rp_map[first_rp[3]["id"].decode()] assert rk_count == rp_map[first_rp[3]["id"]]
for i in range(1, first_rp[CredentialManagement.RESULT.TOTAL_RPS]): for i in range(1, first_rp[CredentialManagement.RESULT.TOTAL_RPS]):
next_rp = CredMgmt.enumerate_rps_next() next_rp = CredMgmt(device).enumerate_rps_next()
rk_count = 1 rk_count = 1
first_rk = CredMgmt.enumerate_creds_begin( first_rk = CredMgmt(device).enumerate_creds_begin(
sha256(next_rp[3]["id"]) sha256(next_rp[3]["id"].encode())
) )
for i in range(1, first_rk[CredentialManagement.RESULT.TOTAL_CREDENTIALS]): for i in range(1, first_rk[CredentialManagement.RESULT.TOTAL_CREDENTIALS]):
c = CredMgmt.enumerate_creds_next() c = CredMgmt(device).enumerate_creds_next()
rk_count += 1 rk_count += 1
assert rk_count == rp_map[next_rp[3]["id"].decode()] assert rk_count == rp_map[next_rp[3]["id"]]
def CredMgmtWrongPinAuth(device, pin_token): def CredMgmtWrongPinAuth(device):
pin_token = PinToken(device)
pin_protocol = PinProtocolV2() pin_protocol = PinProtocolV2()
wrong_pt = bytearray(pin_token) wrong_pt = bytearray(pin_token)
wrong_pt[0] = (wrong_pt[0] + 1) % 256 wrong_pt[0] = (wrong_pt[0] + 1) % 256
@@ -103,13 +98,13 @@ def test_get_info(info):
assert 0x8 in info assert 0x8 in info
assert info[0x8] > 1 assert info[0x8] > 1
def test_get_metadata_ok(MC_RK_Res, CredMgmt): def test_get_metadata_ok(MC_RK_Res, device):
metadata = CredMgmt.get_metadata() metadata = CredMgmt(device).get_metadata()
assert metadata[CredentialManagement.RESULT.EXISTING_CRED_COUNT] == 2 assert metadata[CredentialManagement.RESULT.EXISTING_CRED_COUNT] == 2
assert metadata[CredentialManagement.RESULT.MAX_REMAINING_COUNT] >= 48 assert metadata[CredentialManagement.RESULT.MAX_REMAINING_COUNT] >= 48
def test_enumerate_rps(MC_RK_Res, CredMgmt): def test_enumerate_rps(MC_RK_Res, device):
res = CredMgmt.enumerate_rps() res = CredMgmt(device).enumerate_rps()
assert len(res) == 2 assert len(res) == 2
assert res[0][CredentialManagement.RESULT.RP]["id"] == "ssh:" assert res[0][CredentialManagement.RESULT.RP]["id"] == "ssh:"
assert res[0][CredentialManagement.RESULT.RP_ID_HASH] == sha256(b"ssh:") assert res[0][CredentialManagement.RESULT.RP_ID_HASH] == sha256(b"ssh:")
@@ -117,41 +112,41 @@ def test_enumerate_rps(MC_RK_Res, CredMgmt):
assert res[1][CredentialManagement.RESULT.RP]["id"] == "xakcop.com" assert res[1][CredentialManagement.RESULT.RP]["id"] == "xakcop.com"
assert res[1][CredentialManagement.RESULT.RP_ID_HASH] == sha256(b"xakcop.com") assert res[1][CredentialManagement.RESULT.RP_ID_HASH] == sha256(b"xakcop.com")
def test_enumarate_creds(MC_RK_Res, CredMgmt): def test_enumarate_creds(MC_RK_Res, device):
res = CredMgmt.enumerate_creds(sha256(b"ssh:")) res = CredMgmt(device).enumerate_creds(sha256(b"ssh:"))
assert len(res) == 1 assert len(res) == 1
assert_cred_response_has_all_fields(res[0]) assert_cred_response_has_all_fields(res[0])
res = CredMgmt.enumerate_creds(sha256(b"xakcop.com")) res = CredMgmt(device).enumerate_creds(sha256(b"xakcop.com"))
assert len(res) == 1 assert len(res) == 1
assert_cred_response_has_all_fields(res[0]) assert_cred_response_has_all_fields(res[0])
res = CredMgmt.enumerate_creds(sha256(b"missing.com")) res = CredMgmt(device).enumerate_creds(sha256(b"missing.com"))
assert not res assert not res
def test_get_metadata_wrong_pinauth(device, MC_RK_Res, PinToken): def test_get_metadata_wrong_pinauth(device, MC_RK_Res):
cmd = lambda credMgmt: credMgmt.get_metadata() cmd = lambda credMgmt: credMgmt.get_metadata()
_test_wrong_pinauth(device, cmd, PinToken) _test_wrong_pinauth(device, cmd)
def test_rpbegin_wrong_pinauth(device, MC_RK_Res, PinToken): def test_rpbegin_wrong_pinauth(device, MC_RK_Res):
cmd = lambda credMgmt: credMgmt.enumerate_rps_begin() cmd = lambda credMgmt: credMgmt.enumerate_rps_begin()
_test_wrong_pinauth(device, cmd, PinToken) _test_wrong_pinauth(device, cmd)
def test_rkbegin_wrong_pinauth(device, MC_RK_Res, PinToken): def test_rkbegin_wrong_pinauth(device, MC_RK_Res):
cmd = lambda credMgmt: credMgmt.enumerate_creds_begin(sha256(b"ssh:")) cmd = lambda credMgmt: credMgmt.enumerate_creds_begin(sha256(b"ssh:"))
_test_wrong_pinauth(device, cmd, PinToken) _test_wrong_pinauth(device, cmd)
def test_rpnext_without_rpbegin(device, MC_RK_Res, CredMgmt): def test_rpnext_without_rpbegin(device, MC_RK_Res):
CredMgmt.enumerate_creds_begin(sha256(b"ssh:")) CredMgmt(device).enumerate_creds_begin(sha256(b"ssh:"))
with pytest.raises(CtapError) as e: with pytest.raises(CtapError) as e:
CredMgmt.enumerate_rps_next() CredMgmt(device).enumerate_rps_next()
assert e.value.code == CtapError.ERR.NOT_ALLOWED assert e.value.code == CtapError.ERR.NOT_ALLOWED
def test_rknext_without_rkbegin(device, MC_RK_Res, CredMgmt): def test_rknext_without_rkbegin(device, MC_RK_Res):
CredMgmt.enumerate_rps_begin() CredMgmt(device).enumerate_rps_begin()
with pytest.raises(CtapError) as e: with pytest.raises(CtapError) as e:
CredMgmt.enumerate_creds_next() CredMgmt(device).enumerate_creds_next()
assert e.value.code == CtapError.ERR.NOT_ALLOWED assert e.value.code == CtapError.ERR.NOT_ALLOWED
def test_delete(device, PinToken, CredMgmt): def test_delete(device):
# create a new RK # create a new RK
rp = {"id": "example_3.com", "name": "John Doe 2"} rp = {"id": "example_3.com", "name": "John Doe 2"}
@@ -161,21 +156,21 @@ def test_delete(device, PinToken, CredMgmt):
auth = device.doGA(rp_id=rp['id']) auth = device.doGA(rp_id=rp['id'])
# get the ID from enumeration # get the ID from enumeration
creds = CredMgmt.enumerate_creds(reg.auth_data.rp_id_hash) creds = CredMgmt(device).enumerate_creds(reg.auth_data.rp_id_hash)
for cred in creds: 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 break
# delete it # delete it
cred = {"id": cred[7]["id"], "type": "public-key"} cred = {"id": cred[7]["id"], "type": "public-key"}
CredMgmt.delete_cred(cred) CredMgmt(device).delete_cred(cred)
# make sure it doesn't work # make sure it doesn't work
with pytest.raises(CtapError) as e: with pytest.raises(CtapError) as e:
auth = device.doGA(rp_id=rp['id']) auth = device.doGA(rp_id=rp['id'])
assert e.value.code == CtapError.ERR.NO_CREDENTIALS assert e.value.code == CtapError.ERR.NO_CREDENTIALS
def test_add_delete(device, PinToken, CredMgmt): def test_add_delete(device):
""" Delete a credential in the 'middle' and ensure other credentials are not affected. """ """ Delete a credential in the 'middle' and ensure other credentials are not affected. """
rp = {"id": "example_4.com", "name": "John Doe 3"} rp = {"id": "example_4.com", "name": "John Doe 3"}
@@ -187,11 +182,11 @@ def test_add_delete(device, PinToken, CredMgmt):
regs.append(reg) regs.append(reg)
# Check they all enumerate # Check they all enumerate
res = CredMgmt.enumerate_creds(regs[1].auth_data.rp_id_hash) res = CredMgmt(device).enumerate_creds(regs[1].auth_data.rp_id_hash)
assert len(res) == 3 assert len(res) == 3
# delete the middle one # delete the middle one
creds = CredMgmt.enumerate_creds(reg.auth_data.rp_id_hash) creds = CredMgmt(device).enumerate_creds(reg.auth_data.rp_id_hash)
for cred in creds: 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 break
@@ -199,16 +194,16 @@ def test_add_delete(device, PinToken, CredMgmt):
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"} cred = {"id": cred[7]["id"], "type": "public-key"}
CredMgmt.delete_cred(cred) CredMgmt(device).delete_cred(cred)
# Check one less enumerates # Check one less enumerates
res = CredMgmt.enumerate_creds(regs[0].auth_data.rp_id_hash) res = CredMgmt(device).enumerate_creds(regs[0].auth_data.rp_id_hash)
assert len(res) == 2 assert len(res) == 2
def test_multiple_creds_per_multiple_rps( def test_multiple_creds_per_multiple_rps(
device, MC_RK_Res, CredMgmt device, MC_RK_Res
): ):
res = CredMgmt.enumerate_rps() res = CredMgmt(device).enumerate_rps()
assert len(res) == 2 assert len(res) == 2
new_rps = [ new_rps = [
@@ -222,27 +217,27 @@ def test_multiple_creds_per_multiple_rps(
for i in range(0, 3): for i in range(0, 3):
reg = device.doMC(rp=rp, rk=True, user=generate_random_user()) reg = device.doMC(rp=rp, rk=True, user=generate_random_user())
res = CredMgmt.enumerate_rps() res = CredMgmt(device).enumerate_rps()
assert len(res) == 5 assert len(res) == 5
for rp in res: for rp in res:
if rp[3]["id"][:12] == "new_example_": if rp[3]["id"][:12] == "new_example_":
creds = CredMgmt.enumerate_creds(sha256(rp[3]["id"].encode("utf8"))) creds = CredMgmt(device).enumerate_creds(sha256(rp[3]["id"].encode("utf8")))
assert len(creds) == 3 assert len(creds) == 3
@pytest.mark.parametrize( @pytest.mark.parametrize(
"enumeration_test", [_test_enumeration, _test_enumeration_interleaved] "enumeration_test", [_test_enumeration, _test_enumeration_interleaved]
) )
def test_multiple_enumeration( def test_multiple_enumeration(
device, MC_RK_Res, CredMgmt, enumeration_test device, MC_RK_Res, enumeration_test
): ):
""" Test enumerate still works after different commands """ """ Test enumerate still works after different commands """
res = CredMgmt.enumerate_rps() res = CredMgmt(device).enumerate_rps()
expected_enumeration = {"xakcop.com": 1, "ssh:": 1} expected_enumeration = {"xakcop.com": 1, "ssh:": 1}
enumeration_test(CredMgmt, expected_enumeration) enumeration_test(device, expected_enumeration)
new_rps = [ new_rps = [
{"id": "example-2.com", "name": "Example-2-creds", "count": 2}, {"id": "example-2.com", "name": "Example-2-creds", "count": 2},
@@ -258,27 +253,27 @@ def test_multiple_enumeration(
# Now expect creds from this RP # 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(device, expected_enumeration)
enumeration_test(CredMgmt, expected_enumeration) enumeration_test(device, expected_enumeration)
metadata = CredMgmt.get_metadata() metadata = CredMgmt(device).get_metadata()
enumeration_test(CredMgmt, expected_enumeration) enumeration_test(device, expected_enumeration)
enumeration_test(CredMgmt, expected_enumeration) enumeration_test(device, expected_enumeration)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"enumeration_test", [_test_enumeration, _test_enumeration_interleaved] "enumeration_test", [_test_enumeration, _test_enumeration_interleaved]
) )
def test_multiple_enumeration_with_deletions( def test_multiple_enumeration_with_deletions(
device, MC_RK_Res, CredMgmt, enumeration_test device, MC_RK_Res, enumeration_test
): ):
""" Create each credential in random order. Test enumerate still works after randomly deleting each credential""" """ Create each credential in random order. Test enumerate still works after randomly deleting each credential"""
res = CredMgmt.enumerate_rps() res = CredMgmt(device).enumerate_rps()
expected_enumeration = {"xakcop.com": 1, "ssh:": 1} expected_enumeration = {"xakcop.com": 1, "ssh:": 1}
enumeration_test(CredMgmt, expected_enumeration) enumeration_test(device, expected_enumeration)
new_rps = [ new_rps = [
{"id": "example-1.com", "name": "Example-1-creds"}, {"id": "example-1.com", "name": "Example-1-creds"},
@@ -299,7 +294,7 @@ def test_multiple_enumeration_with_deletions(
else: else:
expected_enumeration[rp["id"]] += 1 expected_enumeration[rp["id"]] += 1
enumeration_test(CredMgmt, expected_enumeration) enumeration_test(device, expected_enumeration)
total_creds = len(new_rps) total_creds = len(new_rps)
@@ -309,10 +304,10 @@ def test_multiple_enumeration_with_deletions(
num = expected_enumeration[rp] num = expected_enumeration[rp]
index = 0 if num == 1 else random.randint(0, num - 1) index = 0 if num == 1 else random.randint(0, num - 1)
cred = CredMgmt.enumerate_creds(sha256(rp.encode("utf8")))[index] cred = CredMgmt(device).enumerate_creds(sha256(rp.encode("utf8")))[index]
# print('Delete %d index (%d total) cred of %s' % (index, expected_enumeration[rp], rp)) # 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(device).delete_cred({"id": cred[7]["id"], "type": "public-key"})
expected_enumeration[rp] -= 1 expected_enumeration[rp] -= 1
if expected_enumeration[rp] == 0: if expected_enumeration[rp] == 0:
@@ -321,11 +316,11 @@ def test_multiple_enumeration_with_deletions(
if len(list(expected_enumeration.keys())) == 0: if len(list(expected_enumeration.keys())) == 0:
break break
enumeration_test(CredMgmt, expected_enumeration) enumeration_test(device, expected_enumeration)
def _test_wrong_pinauth(device, cmd, PinToken): def _test_wrong_pinauth(device, cmd):
credMgmt = CredMgmtWrongPinAuth(device, PinToken) credMgmt = CredMgmtWrongPinAuth(device)
for i in range(2): for i in range(2):
with pytest.raises(CtapError) as e: with pytest.raises(CtapError) as e:
@@ -336,8 +331,8 @@ def _test_wrong_pinauth(device, cmd, PinToken):
cmd(credMgmt) cmd(credMgmt)
assert e.value.code == CtapError.ERR.PIN_AUTH_BLOCKED assert e.value.code == CtapError.ERR.PIN_AUTH_BLOCKED
#device.reboot() device.reboot()
credMgmt = CredMgmtWrongPinAuth(device, PinToken) credMgmt = CredMgmtWrongPinAuth(device)
for i in range(2): for i in range(2):
time.sleep(0.2) time.sleep(0.2)
@@ -349,8 +344,8 @@ def _test_wrong_pinauth(device, cmd, PinToken):
cmd(credMgmt) cmd(credMgmt)
assert e.value.code == CtapError.ERR.PIN_AUTH_BLOCKED assert e.value.code == CtapError.ERR.PIN_AUTH_BLOCKED
#device.reboot() device.reboot()
credMgmt = CredMgmtWrongPinAuth(device, PinToken) credMgmt = CredMgmtWrongPinAuth(device)
for i in range(1): for i in range(1):
time.sleep(0.2) time.sleep(0.2)