def test_exclude_list2(self, device, MCRes): req = FidoRequest( MCRes, exclude_list=[{"id": b"1234", "type": "mangoPapayaCoconutNotAPublicKey"}], ) device.sendMC(*req.toMC())
def test_missing_pubKeyCredParams(self, device, MCRes): req = FidoRequest(MCRes, key_params=None) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC()) assert e.value.code == CtapError.ERR.MISSING_PARAMETER
def test_missing_pubKeyCredParams_type(self, device, MCRes): req = FidoRequest(MCRes, key_params=[{"alg": ES256.ALGORITHM}]) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC()) assert e.value.code == CtapError.ERR.MISSING_PARAMETER
def test_unsupported_algorithm(self, device, MCRes): req = FidoRequest(MCRes, key_params=[{"alg": 1337, "type": "public-key"}]) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC()) assert e.value.code == CtapError.ERR.UNSUPPORTED_ALGORITHM
def MCHmacSecret( resetDevice, ): req = FidoRequest(extensions={"hmac-secret": True}, options={"rk": True}) res = resetDevice.sendMC(*req.toMC()) setattr(res, "request", req) return res
def test_bad_type_user_displayName(self, device, MCRes): req = FidoRequest( MCRes, user={"id": "user_id", "name": "name", "displayName": 8} ) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC())
def test_bad_type_exclude_list_type(self, device, MCRes, GARes): req = FidoRequest(MCRes, exclude_list=GARes.request.allow_list) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC()) assert e.value.code == CtapError.ERR.CREDENTIAL_EXCLUDED
def test_exclude_list(self, device, MCRes): req = FidoRequest(MCRes, exclude_list=[{ "id": b"1234", "type": "rot13" }]) device.sendMC(*req.toMC())
def test_bad_type_pubKeyCredParams_alg(self, device, MCRes): req = FidoRequest(MCRes, key_params=[{ "alg": "7", "type": "public-key" }]) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC())
def test_bad_type_exclude_list_type(self, device, MCRes): req = FidoRequest(MCRes, exclude_list=[{ "type": b"public-key", "id": b"1234" }]) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC())
def test_multiple_key_params_eddsa(self, device, MCRes): key_params = [ {"type": "public-key", "alg": EdDSA.ALGORITHM}, {"type": "public-key", "alg": ES256.ALGORITHM}, ] req = FidoRequest(MCRes, key_params=key_params) resp = device.sendMC(*req.toMC()) assert resp.auth_data.credential_data.public_key[3] == EdDSA.ALGORITHM
def test_bad_type_rp_name(self, device, MCRes): req = FidoRequest(MCRes, rp={ "id": "test.org", "name": 8, "icon": "icon" }) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC())
def test_missing_pubKeyCredParams_alg(self, device, MCRes): req = FidoRequest(MCRes, key_params=[{"type": "public-key"}]) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC()) assert e.value.code in [ CtapError.ERR.MISSING_PARAMETER, CtapError.ERR.UNSUPPORTED_ALGORITHM, ]
def test_hmac_secret_and_credProtect_make_credential( self, resetDevice, MCCredProtect): req = FidoRequest(extensions={"credProtect": 1, "hmac-secret": True}) res = resetDevice.sendMC(*req.toMC()) setattr(res, "request", req) for ext in ["credProtect", "hmac-secret"]: assert res.auth_data.extensions assert ext in res.auth_data.extensions assert res.auth_data.extensions[ext] == True
def test_backup_credential_is_generated_correctly( self, solo, device, ): import seedweed from binascii import hexlify key_A = b"A" * 32 ext_state = b"I'm a dicekey key!" version = b"\x01" ext_key_cmd = 0x62 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()) rpIdHash = sha256(mc_A_req.rp["id"].encode("utf8")) credId = mc_A_res.auth_data.credential_data.credential_id ( uniqueId, extStateInCredId, credMacInCredId, ) = seedweed.nonce_extstate_mac_from_credential_id(credId) 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) 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) 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, )
def test_get_next_assertion_has_extension(self, device, MCHmacSecret, cipher, sharedSecret, salts, fixed_users): """ Check that get_next_assertion properly returns extension information for multiple accounts. """ accounts = 3 regs = [] auths = [] rp = {"id": "example_2.org", "name": "ExampleRP_2"} for i in range(0, accounts): req = FidoRequest(extensions={"hmac-secret": True}, options={"rk": True}, rp=rp, user=fixed_users[i]) res = device.sendMC(*req.toMC()) regs.append(res) key_agreement, shared_secret = sharedSecret salt_enc, salt_auth = get_salt_params(cipher, shared_secret, salts) req = FidoRequest( extensions={ "hmac-secret": { 1: key_agreement, 2: salt_enc, 3: salt_auth } }, rp=rp, ) auth = device.sendGA(*req.toGA()) assert auth.number_of_credentials == accounts auths.append(auth) for i in range(0, accounts - 1): auths.append(device.ctap2.get_next_assertion()) for x in auths: assert x.auth_data.flags & (1 << 7) # has extension ext = auth.auth_data.extensions assert ext assert "hmac-secret" in ext assert isinstance(ext["hmac-secret"], bytes) assert len(ext["hmac-secret"]) == len(salts) * 32 dec = cipher.decryptor() key = dec.update(ext["hmac-secret"]) + dec.finalize() auths.reverse() for x, y in zip(regs, auths): verify(x, y, req.cdh)
def test_big_request_response(self, device, MCRes): req = FidoRequest( MCRes, exclude_list=[ { "id": b"0123456789012345678901234567890123456789012345678901234567890123456789", "type": "public-key"}, { "id": b"1123456789012345678901234567890123456789012345678901234567890123456789", "type": "public-key"}, { "id": b"2123456789012345678901234567890123456789012345678901234567890123456789", "type": "public-key"}], ) device.sendMC(*req.toMC())
def test_ext_state_in_credential_id( self, solo, device, ): key_A = b'A' * 32 ext_state = b"I'm a dicekey key abc1234!!@@##" version = b'\x01' ext_key_cmd = 0x62 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()) assert ext_state in mc_A_res.auth_data.credential_data.credential_id
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.') ext_key_cmd = 0x62 solo.send_data_hid(ext_key_cmd, version + v['seed'] + b'') 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])
def test_load_external_key( self, solo, device, ): key_A = b'A' * 32 key_B = b'B' * 32 ext_state = b"I'm a dicekey key" version = b'\x01' ext_key_cmd = 0x62 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" }] 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.') 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) # Load up Key A and verify cred A is back. 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)
def test_eddsa(self, device): mc_req = FidoRequest(key_params=[{ "type": "public-key", "alg": EdDSA.ALGORITHM }]) try: mc_res = device.sendMC(*mc_req.toMC()) except CtapError as e: if e.code == CtapError.ERR.UNSUPPORTED_ALGORITHM: print("ed25519 is not supported. Skip this test.") return setattr(mc_res, "request", mc_req) 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()) setattr(ga_res, "request", ga_req) try: verify(mc_res, ga_res) 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 credential_data = AttestedCredentialData( mc_res.auth_data.credential_data) print("public key:", hexlify(credential_data.public_key[-2])) verify(mc_res, ga_res)
def test_fake_extension(self, device): req = FidoRequest(extensions={"tetris": True}) res = device.sendMC(*req.toMC())
def test_bad_type_pubKeyCredParams(self, device, MCRes): req = FidoRequest(MCRes, key_params=b"1234a") with pytest.raises(CtapError) as e: device.sendMC(*req.toMC())
def test_missing_exclude_list_type(self, device, MCRes): req = FidoRequest(MCRes, exclude_list=[{"id": b"1234"}]) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC())
def test_bad_type_rp(self, device, MCRes): req = FidoRequest(MCRes, rp=b"1234abcdef") with pytest.raises(CtapError) as e: device.sendMC(*req.toMC())
def test_bad_type_cdh(self, device, MCRes): req = FidoRequest(MCRes, cdh=5) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC())
def test_missing_exclude_list_id(self, device, MCRes): req = FidoRequest(MCRes, exclude_list=[{"type": "public-key"}]) with pytest.raises(CtapError) as e: device.sendMC(*req.toMC())
def test_unknown_option(self, device, MCRes): req = FidoRequest(MCRes, options={"unknown": False}) print("MC", req.toMC()) device.sendMC(*req.toMC())
def MCCredProtect(resetDevice, ): req = FidoRequest(extensions={"credProtect": 1}) res = resetDevice.sendMC(*req.toMC()) setattr(res, "request", req) return res
def test_basic_attestation_rp(self, device, MCRes): # Make credential for an RP that requires basic attestation. req = FidoRequest(MCRes, rp={"id": "login.microsoft.com"}) resp = device.sendMC(*req.toMC()) assert "x5c" in resp.att_statement