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
Example #2
0
    def get_output(self, device, MCHmacSecret, cipher, sharedSecret, salts):
        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
            }
        })
        auth = device.sendGA(*req.toGA())

        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

        verify(MCHmacSecret, auth, req.cdh)

        dec = cipher.decryptor()
        output = dec.update(ext["hmac-secret"]) + dec.finalize()

        if len(salts) == 2:
            return (output[0:32], output[32:64])
        else:
            return output
    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
Example #4
0
    def test_hmac_secret_entropy(self, device, MCHmacSecret, cipher,
                                 sharedSecret, salts):
        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
            }
        })
        auth = device.sendGA(*req.toGA())

        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

        verify(MCHmacSecret, auth, req.cdh)

        dec = cipher.decryptor()
        key = dec.update(ext["hmac-secret"]) + dec.finalize()

        print(shannon_entropy(ext["hmac-secret"]))
        if len(salts) == 1:
            assert shannon_entropy(ext["hmac-secret"]) > 4.6
            assert shannon_entropy(key) > 4.6
        if len(salts) == 2:
            assert shannon_entropy(ext["hmac-secret"]) > 5.4
            assert shannon_entropy(key) > 5.4
Example #5
0
    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.')
            ext_key_cmd = 0x62
            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)
            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']
            # reg.auth_data.credential_data.credential_id

            seedweed.conformance.verify_get_assertion(
                v,
                convert_der_sig_to_padded_binary(ga_res.signature),
                # ga_res.signature,
                ga_res.auth_data + ga_req.cdh,
            )
    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 test_exclude_list2(self, device, MCRes):
        req = FidoRequest(
            MCRes,
            exclude_list=[{"id": b"1234", "type": "mangoPapayaCoconutNotAPublicKey"}],
        )

        device.sendMC(*req.toMC())
    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_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())
Example #10
0
def MCHmacSecret(
    resetDevice,
):
    req = FidoRequest(extensions={"hmac-secret": True}, options={"rk": True})
    res = resetDevice.sendMC(*req.toMC())
    setattr(res, "request", req)
    return res
Example #11
0
    def test_exclude_list(self, device, MCRes):
        req = FidoRequest(MCRes,
                          exclude_list=[{
                              "id": b"1234",
                              "type": "rot13"
                          }])

        device.sendMC(*req.toMC())
Example #12
0
    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())
Example #13
0
    def test_missing_keyAgreement(self, device, cipher, sharedSecret):
        key_agreement, shared_secret = sharedSecret

        salt_enc, salt_auth = get_salt_params(cipher, shared_secret, (salt3,))

        req = FidoRequest(extensions={"hmac-secret": {2: salt_enc, 3: salt_auth}})

        with pytest.raises(CtapError):
            device.sendGA(*req.toGA())
    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
Example #15
0
    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())
Example #16
0
    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,
        ]
Example #17
0
    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())
Example #18
0
    def test_missing_saltEnc(self, device, cipher, sharedSecret):
        key_agreement, shared_secret = sharedSecret

        salt_enc, salt_auth = get_salt_params(cipher, shared_secret, (salt3,))

        req = FidoRequest(extensions={"hmac-secret": {1: key_agreement, 3: salt_auth}})

        with pytest.raises(CtapError) as e:
            device.sendGA(*req.toGA())
        assert e.value.code == CtapError.ERR.MISSING_PARAMETER
Example #19
0
    def test_invalid_salt_length(self, device, cipher, sharedSecret, salts):
        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}}
        )

        with pytest.raises(CtapError) as e:
            device.sendGA(*req.toGA())
        assert e.value.code == CtapError.ERR.INVALID_LENGTH
Example #20
0
    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_authenticate_ctap1_through_ctap2(self, device, RegRes):
        req = FidoRequest(allow_list=[{
            "id": RegRes.key_handle,
            "type": "public-key"
        }])

        auth = device.sendGA(*req.toGA())

        credential_data = AttestedCredentialData.from_ctap1(
            RegRes.key_handle, RegRes.public_key)
        auth.verify(req.cdh, credential_data.public_key)
        assert auth.credential["id"] == RegRes.key_handle
Example #22
0
    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')

        # 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)
Example #23
0
 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())
Example #24
0
    def test_bad_auth(self, device, cipher, sharedSecret):

        key_agreement, shared_secret = sharedSecret

        salt_enc, salt_auth = get_salt_params(cipher, shared_secret, (salt3,))

        bad_auth = list(salt_auth[:])
        bad_auth[len(bad_auth) // 2] = bad_auth[len(bad_auth) // 2] ^ 1
        bad_auth = bytes(bad_auth)

        req = FidoRequest(
            extensions={"hmac-secret": {1: key_agreement, 2: salt_enc, 3: bad_auth}}
        )

        with pytest.raises(CtapError) as e:
            device.sendGA(*req.toGA())
        assert e.value.code == CtapError.ERR.EXTENSION_FIRST
Example #25
0
    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
Example #26
0
    def test_u2f(self, device, iterations):
        lastc = 0
        chal = FidoRequest().challenge
        appid = FidoRequest().appid

        regs = []

        for i in range(0, iterations):
            print("U2F reg + auth %d/%d (count: %02x)" %
                  (i + 1, iterations, lastc))
            reg = device.register(chal, appid)
            reg.verify(appid, chal)
            auth = device.authenticate(chal, appid, reg.key_handle)
            auth.verify(appid, chal, reg.public_key)

            regs.append(reg)
            # check endianness
            if lastc:
                assert (auth.counter - lastc) < 10
            lastc = auth.counter
            if lastc > 0x80000000:
                print("WARNING: counter is unusually high: %04x" % lastc)
                assert 0

        for i in range(0, iterations):
            auth = device.authenticate(chal, appid, regs[i].key_handle)
            auth.verify(appid, chal, regs[i].public_key)

        device.reboot()

        for i in range(0, iterations):
            auth = device.authenticate(chal, appid, regs[i].key_handle)
            auth.verify(appid, chal, regs[i].public_key)

        print("Check that all previous credentials are registered...")
        for i in range(0, iterations):
            with pytest.raises(ApduError) as e:
                auth = device.ctap1.authenticate(chal,
                                                 appid,
                                                 regs[i].key_handle,
                                                 check_only=True)
            assert e.value.code == APDU.USE_NOT_SATISFIED
    def test_ctap1_authenticate(self, MCRes, device):
        req = FidoRequest()
        key_handle = MCRes.auth_data.credential_data.credential_id
        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)
Example #28
0
    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_ctap1_authenticate(self, MCRes, device):
        req = FidoRequest()
        key_handle = MCRes.auth_data.credential_data.credential_id
        if len(key_handle) <= 255:
            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)
        else:
            print(
                "ctap2 credId is longer than 255 bytes, cannot use with U2F.")
Example #30
0
    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,
        )