コード例 #1
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
コード例 #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
コード例 #3
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)
コード例 #4
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,
        )
コード例 #5
0
    def test_hmac_secret_different_with_uv(self, device, MCHmacSecret, cipher,
                                           sharedSecret):
        salts = [salt1]
        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_no_uv = device.sendGA(*req.toGA())
        assert (auth_no_uv.auth_data.flags & (1 << 2)) == 0

        ext_no_uv = auth_no_uv.auth_data.extensions
        assert ext_no_uv
        assert "hmac-secret" in ext_no_uv
        assert isinstance(ext_no_uv["hmac-secret"], bytes)
        assert len(ext_no_uv["hmac-secret"]) == len(salts) * 32

        verify(MCHmacSecret, auth_no_uv, req.cdh)

        # Now get same auth with UV
        pin = '1234'
        device.client.pin_protocol.set_pin(pin)
        pin_token = device.client.pin_protocol.get_pin_token(pin)
        pin_auth = hmac_sha256(pin_token, req.cdh)[:16]

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

        auth_uv = device.sendGA(*req.toGA())
        assert auth_uv.auth_data.flags & (1 << 2)
        ext_uv = auth_uv.auth_data.extensions
        assert ext_uv
        assert "hmac-secret" in ext_uv
        assert isinstance(ext_uv["hmac-secret"], bytes)
        assert len(ext_uv["hmac-secret"]) == len(salts) * 32

        verify(MCHmacSecret, auth_uv, req.cdh)

        # Now see if the hmac-secrets are different
        assert ext_no_uv['hmac-secret'] != ext_uv['hmac-secret']
コード例 #6
0
    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)
コード例 #7
0
    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)
コード例 #8
0
    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)