Esempio n. 1
0
def test_device_certificate():
    from parsec.api.data.certif import (
        _RsDeviceCertificateContent,
        DeviceCertificateContent,
        _PyDeviceCertificateContent,
    )

    assert DeviceCertificateContent is _RsDeviceCertificateContent

    def _assert_device_certificate_eq(py, rs):
        assert py.author == rs.author
        assert py.timestamp == rs.timestamp
        assert py.device_id == rs.device_id
        assert py.device_label == rs.device_label
        assert py.verify_key == rs.verify_key

    kwargs = {
        "author": DeviceID.new(),
        "timestamp": pendulum.now(),
        "device_id": DeviceID("bob@dev1"),
        "device_label": DeviceLabel("dev machine"),
        "verify_key": SigningKey.generate().verify_key,
    }

    py_dc = _PyDeviceCertificateContent(**kwargs)
    rs_dc = DeviceCertificateContent(**kwargs)
    _assert_device_certificate_eq(py_dc, rs_dc)

    kwargs = {
        "author": DeviceID.new(),
        "timestamp": pendulum.now(),
        "device_id": DeviceID("alice@dev1"),
        "device_label": None,
        "verify_key": SigningKey.generate().verify_key,
    }

    py_dc = py_dc.evolve(**kwargs)
    rs_dc = rs_dc.evolve(**kwargs)
    _assert_device_certificate_eq(py_dc, rs_dc)

    sign_key = SigningKey.generate()
    py_data = py_dc.dump_and_sign(sign_key)
    rs_data = rs_dc.dump_and_sign(sign_key)

    py_dc = _PyDeviceCertificateContent.verify_and_load(
        rs_data, sign_key.verify_key, expected_author=py_dc.author, expected_device=py_dc.device_id
    )
    rs_dc = DeviceCertificateContent.verify_and_load(
        py_data, sign_key.verify_key, expected_author=rs_dc.author, expected_device=rs_dc.device_id
    )
    _assert_device_certificate_eq(py_dc, rs_dc)

    py_dc = _PyDeviceCertificateContent.unsecure_load(rs_data)
    rs_dc = DeviceCertificateContent.unsecure_load(py_data)
    _assert_device_certificate_eq(py_dc, rs_dc)
async def _bootstrap_organization(
    debug, device_id, organization_bootstrap_addr, config_dir, force, password
):
    root_signing_key = SigningKey.generate()
    root_verify_key = root_signing_key.verify_key
    organization_addr = organization_bootstrap_addr.generate_organization_addr(root_verify_key)

    device_display = click.style(device_id, fg="yellow")
    device = generate_new_device(device_id, organization_addr)

    with operation(f"Creating locally {device_display}"):
        save_device_with_password(config_dir, device, password, force=force)

    now = pendulum.now()
    certified_user = certify_user(None, root_signing_key, device.user_id, device.public_key, now)
    certified_device = certify_device(None, root_signing_key, device_id, device.verify_key, now)

    async with spinner(f"Sending {device_display} to server"):
        async with backend_anonymous_cmds_factory(organization_bootstrap_addr) as cmds:
            await cmds.organization_bootstrap(
                organization_bootstrap_addr.organization_id,
                organization_bootstrap_addr.bootstrap_token,
                root_verify_key,
                certified_user,
                certified_device,
            )

    organization_addr_display = click.style(organization_addr, fg="yellow")
    click.echo(f"Organization url: {organization_addr_display}")
Esempio n. 3
0
def generate_ALICE_local_device():
    return LocalDevice(
        organization_addr=BackendOrganizationAddr.from_url(
            "parsec://alice_dev1.example.com:9999/CoolOrg?no_ssl=true&rvk=XYUXM4ZM5SGKSTXNZ4FK7VATZUKZGY7A7LOJ42CXFR32DYL5TO6Qssss"
        ),
        device_id=DeviceID("alice@dev1"),
        device_label=DeviceLabel("My dev1 machine"),
        human_handle=HumanHandle("*****@*****.**", "Alicey McAliceFace"),
        signing_key=SigningKey(
            unhexlify(
                "d544f66ece9c85d5b80275db9124b5f04bb038081622bed139c1e789c5217400"
            )),
        private_key=PrivateKey(
            unhexlify(
                "74e860967fd90d063ebd64fb1ba6824c4c010099dd37508b7f2875a5db2ef8c9"
            )),
        profile=UserProfile.ADMIN,
        user_manifest_id=EntryID.from_hex("a4031e8bcdd84df8ae12bd3d05e6e20f"),
        user_manifest_key=SecretKey(
            unhexlify(
                "26bf35a98c1e54e90215e154af92a1af2d1142cdd0dba25b990426b0b30b0f9a"
            )),
        local_symkey=SecretKey(
            unhexlify(
                "125a78618995e2e0f9a19bc8617083c809c03deb5457d5b82df5bcaec9966cd4"
            )),
    )
Esempio n. 4
0
def generate_BOB_local_device():
    return LocalDevice(
        organization_addr=BackendOrganizationAddr.from_url(
            "parsec://bob_dev1.example.com:9999/CoolOrg?no_ssl=true&rvk=XYUXM4ZM5SGKSTXNZ4FK7VATZUKZGY7A7LOJ42CXFR32DYL5TO6Qssss"
        ),
        device_id=DeviceID("bob@dev1"),
        device_label=DeviceLabel("My dev1 machine"),
        human_handle=HumanHandle("*****@*****.**", "Boby McBobFace"),
        signing_key=SigningKey(
            unhexlify(
                "85f47472a2c0f30f01b769617db248f3ec8d96a490602a9262f95e9e43432b30"
            )),
        private_key=PrivateKey(
            unhexlify(
                "16767ec446f2611f971c36f19c2dc11614d853475ac395d6c1d70ba46d07dd49"
            )),
        profile=UserProfile.STANDARD,
        user_manifest_id=EntryID.from_hex("71568d41afcb4e2380b3d164ace4fb85"),
        user_manifest_key=SecretKey(
            unhexlify(
                "65de53d2c6cd965aa53a1ba5cc7e54b331419e6103466121996fa99a97197a48"
            )),
        local_symkey=SecretKey(
            unhexlify(
                "93f25b18491016f20b10dcf4eb7986716d914653d6ab4e778701c13435e6bdf0"
            )),
    )
Esempio n. 5
0
async def claim_device(cmds: BackendCmdsPool, new_device_id: DeviceID,
                       token: str) -> LocalDevice:
    """
    Raises:
        InviteClaimError
        core.backend_connection.BackendConnectionError
        core.trustchain.TrustChainError
    """
    device_signing_key = SigningKey.generate()
    answer_private_key = PrivateKey.generate()

    invitation_creator = await cmds.device_get_invitation_creator(new_device_id
                                                                  )

    encrypted_claim = generate_device_encrypted_claim(
        creator_public_key=invitation_creator.public_key,
        token=token,
        device_id=new_device_id,
        verify_key=device_signing_key.verify_key,
        answer_public_key=answer_private_key.public_key,
    )
    encrypted_answer = await cmds.device_claim(new_device_id, encrypted_claim)

    answer = extract_device_encrypted_answer(answer_private_key,
                                             encrypted_answer)
    return LocalDevice(
        organization_addr=cmds.addr,
        device_id=new_device_id,
        signing_key=device_signing_key,
        private_key=answer["private_key"],
        user_manifest_access=answer["user_manifest_access"],
        local_symkey=generate_secret_key(),
    )
def test_signing_key():
    from parsec.crypto import (
        _PySigningKey,
        _RsSigningKey,
        SigningKey,
        VerifyKey,
        _RsVerifyKey,
        _PyVerifyKey,
    )

    assert SigningKey is _RsSigningKey
    assert VerifyKey is _RsVerifyKey

    KEY = b"a" * 32

    rs_sk = SigningKey(KEY)
    py_sk = _PySigningKey(KEY)

    rs_vk = rs_sk.verify_key
    py_vk = py_sk.verify_key

    assert SigningKey(KEY) == SigningKey(KEY)
    assert SigningKey(KEY) != SigningKey(b"b" * 32)

    assert isinstance(rs_vk, _RsVerifyKey)
    assert isinstance(py_vk, _PyVerifyKey)

    # Sign a message with both, check if the signed message is the same
    MESSAGE = b"My message"

    rs_signed = rs_sk.sign(MESSAGE)
    py_signed = py_sk.sign(MESSAGE)

    assert rs_signed == py_signed

    # Verify with both
    assert rs_vk.verify(rs_signed) == py_vk.verify(py_signed)
    assert rs_vk.verify(py_signed) == py_vk.verify(rs_signed)

    # Check if unsecure_unwrap is the same
    assert VerifyKey.unsecure_unwrap(
        rs_signed) == _PyVerifyKey.unsecure_unwrap(py_signed)
    assert VerifyKey.unsecure_unwrap(
        py_signed) == _PyVerifyKey.unsecure_unwrap(rs_signed)

    # Check if generate returns the right type
    assert isinstance(SigningKey.generate(), SigningKey)
    assert isinstance(_PySigningKey.generate(), _PySigningKey)

    # Check if they both react in a similar manner with incorrect data
    assert rs_vk.unsecure_unwrap(b"random_data") == py_vk.unsecure_unwrap(
        b"random_data")

    with pytest.raises(nacl.exceptions.CryptoError):
        py_vk.verify(b"random_data")
    with pytest.raises(nacl.exceptions.CryptoError):
        rs_vk.verify(b"random data")
Esempio n. 7
0
async def bootstrap_organization(
    cmds: APIV1_BackendAnonymousCmds,
    human_handle: Optional[HumanHandle],
    device_label: Optional[str],
) -> LocalDevice:
    root_signing_key = SigningKey.generate()
    root_verify_key = root_signing_key.verify_key

    organization_addr = BackendOrganizationAddr.build(
        backend_addr=cmds.addr,
        organization_id=cmds.addr.organization_id,
        root_verify_key=root_verify_key,
    )

    device = generate_new_device(
        organization_addr=organization_addr,
        profile=UserProfile.ADMIN,
        human_handle=human_handle,
        device_label=device_label,
    )

    now = pendulum_now()
    user_certificate = UserCertificateContent(
        author=None,
        timestamp=now,
        user_id=device.user_id,
        human_handle=device.human_handle,
        public_key=device.public_key,
        profile=device.profile,
    )
    redacted_user_certificate = user_certificate.evolve(human_handle=None)
    device_certificate = DeviceCertificateContent(
        author=None,
        timestamp=now,
        device_id=device.device_id,
        device_label=device.device_label,
        verify_key=device.verify_key,
    )
    redacted_device_certificate = device_certificate.evolve(device_label=None)

    user_certificate = user_certificate.dump_and_sign(root_signing_key)
    redacted_user_certificate = redacted_user_certificate.dump_and_sign(
        root_signing_key)
    device_certificate = device_certificate.dump_and_sign(root_signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(
        root_signing_key)

    rep = await cmds.organization_bootstrap(
        organization_id=cmds.addr.organization_id,
        bootstrap_token=cmds.addr.token,
        root_verify_key=root_verify_key,
        user_certificate=user_certificate,
        device_certificate=device_certificate,
        redacted_user_certificate=redacted_user_certificate,
        redacted_device_certificate=redacted_device_certificate,
    )
    _check_rep(rep, step_name="organization bootstrap")

    return device
Esempio n. 8
0
    async def do_claim_user(
        self,
        requested_device_label: Optional[DeviceLabel],
        requested_human_handle: Optional[HumanHandle],
    ) -> LocalDevice:
        # User&device keys are generated here and kept in memory until the end of
        # the enrollment process. This mean we can lost it if something goes wrong.
        # This has no impact until step 4 (somewhere between data exchange and
        # confirmation exchange steps) where greeter upload our certificates in
        # the server.
        # This is considered acceptable given 1) the error window is small and
        # 2) if this occurs the inviter can revoke the user and retry the
        # enrollment process to fix this
        private_key = PrivateKey.generate()
        signing_key = SigningKey.generate()

        try:
            payload = InviteUserData(
                requested_device_label=requested_device_label,
                requested_human_handle=requested_human_handle,
                public_key=private_key.public_key,
                verify_key=signing_key.verify_key,
            ).dump_and_encrypt(key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Cannot generate InviteUserData payload") from exc

        rep = await self._cmds.invite_4_claimer_communicate(payload=payload)
        _check_rep(rep, step_name="step 4 (data exchange)")

        rep = await self._cmds.invite_4_claimer_communicate(payload=b"")
        _check_rep(rep, step_name="step 4 (confirmation exchange)")

        try:
            confirmation = InviteUserConfirmation.decrypt_and_load(
                rep["payload"], key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Invalid InviteUserConfirmation payload provided by peer"
            ) from exc

        organization_addr = BackendOrganizationAddr.build(
            backend_addr=self._cmds.addr.get_backend_addr(),
            organization_id=self._cmds.addr.organization_id,
            root_verify_key=confirmation.root_verify_key,
        )

        new_device = generate_new_device(
            organization_addr=organization_addr,
            device_id=confirmation.device_id,
            device_label=confirmation.device_label,
            human_handle=confirmation.human_handle,
            profile=confirmation.profile,
            private_key=private_key,
            signing_key=signing_key,
        )

        return new_device
Esempio n. 9
0
async def bootstrap_organization(
    addr: BackendOrganizationBootstrapAddr,
    human_handle: Optional[HumanHandle],
    device_label: Optional[DeviceLabel],
) -> LocalDevice:
    root_signing_key = SigningKey.generate()
    root_verify_key = root_signing_key.verify_key

    organization_addr = BackendOrganizationAddr.build(
        backend_addr=addr.get_backend_addr(),
        organization_id=addr.organization_id,
        root_verify_key=root_verify_key,
    )

    device = generate_new_device(
        organization_addr=organization_addr,
        profile=UserProfile.ADMIN,
        human_handle=human_handle,
        device_label=device_label,
    )

    timestamp = device.timestamp()
    user_certificate = UserCertificateContent(
        author=None,
        timestamp=timestamp,
        user_id=device.user_id,
        human_handle=device.human_handle,
        public_key=device.public_key,
        profile=device.profile,
    )
    redacted_user_certificate = user_certificate.evolve(human_handle=None)
    device_certificate = DeviceCertificateContent(
        author=None,
        timestamp=timestamp,
        device_id=device.device_id,
        device_label=device.device_label,
        verify_key=device.verify_key,
    )
    redacted_device_certificate = device_certificate.evolve(device_label=None)

    user_certificate = user_certificate.dump_and_sign(root_signing_key)
    redacted_user_certificate = redacted_user_certificate.dump_and_sign(root_signing_key)
    device_certificate = device_certificate.dump_and_sign(root_signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(root_signing_key)

    rep = await failsafe_organization_bootstrap(
        addr=addr,
        root_verify_key=root_verify_key,
        user_certificate=user_certificate,
        device_certificate=device_certificate,
        redacted_user_certificate=redacted_user_certificate,
        redacted_device_certificate=redacted_device_certificate,
    )
    _check_rep(rep, step_name="organization bootstrap")

    return device
Esempio n. 10
0
    async def do_claim_user(
            self, requested_device_label: Optional[str],
            requested_human_handle: Optional[HumanHandle]) -> LocalDevice:
        private_key = PrivateKey.generate()
        signing_key = SigningKey.generate()

        try:
            payload = InviteUserData(
                requested_device_label=requested_device_label,
                requested_human_handle=requested_human_handle,
                public_key=private_key.public_key,
                verify_key=signing_key.verify_key,
            ).dump_and_encrypt(key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Cannot generate InviteUserData payload") from exc

        rep = await self._cmds.invite_4_claimer_communicate(payload=payload)
        if rep["status"] == "invalid_state":
            raise InvitePeerResetError()
        elif rep["status"] != "ok":
            raise InviteError(
                f"Backend error during step 4 (data exchange): {rep}")

        rep = await self._cmds.invite_4_claimer_communicate(payload=b"")
        if rep["status"] == "invalid_state":
            raise InvitePeerResetError()
        elif rep["status"] != "ok":
            raise InviteError(
                f"Backend error during step 4 (confirmation exchange): {rep}")

        try:
            confirmation = InviteUserConfirmation.decrypt_and_load(
                rep["payload"], key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Invalid InviteUserConfirmation payload provided by peer"
            ) from exc

        organization_addr = BackendOrganizationAddr.build(
            backend_addr=self._cmds.addr,
            organization_id=self._cmds.addr.organization_id,
            root_verify_key=confirmation.root_verify_key,
        )

        new_device = generate_new_device(
            organization_addr=organization_addr,
            device_id=confirmation.device_id,
            device_label=confirmation.device_label,
            human_handle=confirmation.human_handle,
            profile=confirmation.profile,
            private_key=private_key,
            signing_key=signing_key,
        )

        return new_device
Esempio n. 11
0
    def dump_and_sign(self, author_signkey: SigningKey) -> bytes:
        """
        Raises:
            DataError
        """
        try:
            return author_signkey.sign(self._serialize())

        except CryptoError as exc:
            raise DataError(str(exc)) from exc
Esempio n. 12
0
def test_local_device():
    from parsec.core.types.local_device import _RsLocalDevice, LocalDevice, _PyLocalDevice

    assert LocalDevice is _RsLocalDevice

    def _assert_local_device_eq(py, rs):
        assert isinstance(py, _PyLocalDevice)
        assert isinstance(rs, _RsLocalDevice)

        assert py.organization_addr == rs.organization_addr
        assert py.device_id == rs.device_id
        assert py.device_label == rs.device_label
        assert py.human_handle == rs.human_handle
        assert py.signing_key == rs.signing_key
        assert py.private_key == rs.private_key
        assert py.profile == rs.profile
        assert py.user_manifest_id == rs.user_manifest_id
        assert py.user_manifest_key == rs.user_manifest_key
        assert py.local_symkey == rs.local_symkey

        assert py.is_admin == rs.is_admin
        assert py.is_outsider == rs.is_outsider
        assert py.slug == rs.slug
        assert py.slughash == rs.slughash
        assert py.root_verify_key == rs.root_verify_key
        assert py.organization_id == rs.organization_id
        assert py.device_name == rs.device_name
        assert py.user_id == rs.user_id
        assert py.verify_key == rs.verify_key
        assert py.public_key == rs.public_key
        assert py.user_display == rs.user_display
        assert py.short_user_display == rs.short_user_display
        assert py.device_display == rs.device_display

    signing_key = SigningKey.generate()
    kwargs = {
        "organization_addr": BackendOrganizationAddr.build(
            BackendAddr.from_url("parsec://foo"),
            organization_id=OrganizationID("org"),
            root_verify_key=signing_key.verify_key,
        ),
        "device_id": DeviceID.new(),
        "device_label": None,
        "human_handle": None,
        "signing_key": signing_key,
        "private_key": PrivateKey.generate(),
        "profile": UserProfile.ADMIN,
        "user_manifest_id": EntryID.new(),
        "user_manifest_key": SecretKey.generate(),
        "local_symkey": SecretKey.generate(),
    }

    py_ba = _PyLocalDevice(**kwargs)
    rs_ba = LocalDevice(**kwargs)
    _assert_local_device_eq(py_ba, rs_ba)
Esempio n. 13
0
def test_available_devices_slughash_uniqueness(organization_factory,
                                               local_device_factory,
                                               config_dir):
    def _to_available(device):
        return AvailableDevice(
            key_file_path=get_default_key_file(config_dir, device),
            organization_id=device.organization_id,
            device_id=device.device_id,
            human_handle=device.human_handle,
            device_label=device.device_label,
            slug=device.slug,
            type=DeviceFileType.PASSWORD,
        )

    def _assert_different_as_available(d1, d2):
        available_device_d1 = _to_available(d1)
        available_device_d2 = _to_available(d2)
        assert available_device_d1.slughash != available_device_d2.slughash
        # Make sure slughash is consistent between LocalDevice and AvailableDevice
        assert available_device_d1.slughash == d1.slughash
        assert available_device_d2.slughash == d2.slughash

    o1 = organization_factory("org1")
    o2 = organization_factory("org2")

    # Different user id
    o1u1d1 = local_device_factory("u1@d1", o1)
    o1u2d1 = local_device_factory("u2@d1", o1)
    _assert_different_as_available(o1u1d1, o1u2d1)

    # Different device name
    o1u1d2 = local_device_factory("u1@d2", o1)
    _assert_different_as_available(o1u1d1, o1u1d2)

    # Different organization id
    o2u1d1 = local_device_factory("u1@d1", o2)
    _assert_different_as_available(o1u1d1, o2u1d1)

    # Same organization_id, but different root verify key !
    dummy_key = SigningKey.generate().verify_key
    o1u1d1_bad_rvk = o1u1d1.evolve(
        organization_addr=o1u1d1.organization_addr.build(
            backend_addr=o1u1d1.organization_addr.get_backend_addr(),
            organization_id=o1u1d1.organization_addr.organization_id,
            root_verify_key=dummy_key,
        ))
    _assert_different_as_available(o1u1d1, o1u1d1_bad_rvk)

    # Finally make sure slughash is stable through save/load
    save_device_with_password_in_config(config_dir, o1u1d1, "S3Cr37")
    key_file = get_key_file(config_dir, o1u1d1)
    o1u1d1_reloaded = load_device_with_password(key_file, "S3Cr37")
    available_device = _to_available(o1u1d1)
    available_device_reloaded = _to_available(o1u1d1_reloaded)
    assert available_device.slughash == available_device_reloaded.slughash
Esempio n. 14
0
    def dump_sign_and_encrypt(self, author_signkey: SigningKey, key: SecretKey) -> bytes:
        """
        Raises:
            DataError
        """
        try:
            signed = author_signkey.sign(self._serialize())
            return key.encrypt(signed)

        except CryptoError as exc:
            raise DataError(str(exc)) from exc
Esempio n. 15
0
def generate_new_device(
        device_id: DeviceID,
        organization_addr: BackendOrganizationAddr) -> LocalDevice:
    return LocalDevice(
        organization_addr=organization_addr,
        device_id=device_id,
        signing_key=SigningKey.generate(),
        private_key=PrivateKey.generate(),
        user_manifest_access=ManifestAccess(),
        local_symkey=generate_secret_key(),
    )
async def _bootstrap_organization(debug, device_id,
                                  organization_bootstrap_addr, config_dir,
                                  force, password):
    root_signing_key = SigningKey.generate()
    root_verify_key = root_signing_key.verify_key
    organization_addr = organization_bootstrap_addr.generate_organization_addr(
        root_verify_key)

    device_display = click.style(device_id, fg="yellow")
    device = generate_new_device(device_id,
                                 organization_addr,
                                 profile=UserProfile.ADMIN)

    with operation(f"Creating locally {device_display}"):
        save_device_with_password(config_dir, device, password, force=force)

    now = pendulum.now()
    user_certificate = UserCertificateContent(
        author=None,
        timestamp=now,
        user_id=device.user_id,
        public_key=device.public_key,
        profile=device.profile,
    )
    redacted_user_certificate = user_certificate.evolve(human_handle=None)
    device_certificate = DeviceCertificateContent(author=None,
                                                  timestamp=now,
                                                  device_id=device_id,
                                                  verify_key=device.verify_key)
    redacted_device_certificate = device_certificate.evolve(device_label=None)

    user_certificate = user_certificate.dump_and_sign(root_signing_key)
    device_certificate = device_certificate.dump_and_sign(root_signing_key)
    redacted_user_certificate = redacted_user_certificate.dump_and_sign(
        root_signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(
        root_signing_key)

    async with spinner(f"Sending {device_display} to server"):
        async with apiv1_backend_anonymous_cmds_factory(
                organization_bootstrap_addr) as cmds:
            await cmds.organization_bootstrap(
                organization_id=organization_bootstrap_addr.organization_id,
                bootstrap_token=organization_bootstrap_addr.token,
                root_verify_key=root_verify_key,
                user_certificate=user_certificate,
                device_certificate=device_certificate,
                redacted_user_certificate=redacted_user_certificate,
                redacted_device_certificate=redacted_device_certificate,
            )

    organization_addr_display = click.style(organization_addr.to_url(),
                                            fg="yellow")
    click.echo(f"Organization url: {organization_addr_display}")
Esempio n. 17
0
async def test_proxy_with_websocket(monkeypatch, connection_type, proxy_type):
    signing_key = SigningKey.generate()
    device_id = DeviceID("zack@pc1")
    proxy_events = []

    def _event_hook(event):
        proxy_events.append(event)

    async with trio.open_nursery() as nursery:
        target_port = await start_port_watchdog(nursery, _event_hook)
        proxy_port = await start_proxy_for_websocket(nursery, target_port,
                                                     _event_hook)

        if proxy_type == "http_proxy":
            proxy_url = f"http://127.0.0.1:{proxy_port}"
            monkeypatch.setitem(os.environ, "http_proxy", proxy_url)
        else:
            assert proxy_type == "http_proxy_pac"
            pac_server_port = await start_pac_server(
                nursery=nursery,
                pac_rule=f"PROXY 127.0.0.1:{proxy_port}",
                event_hook=_event_hook)
            pac_server_url = f"http://127.0.0.1:{pac_server_port}"
            monkeypatch.setitem(os.environ, "http_proxy_pac", pac_server_url)
            # HTTP_PROXY_PAC has priority over HTTP_PROXY
            monkeypatch.setitem(os.environ, "http_proxy",
                                f"http://127.0.0.1:{target_port}")

        async with real_clock_timeout():
            with pytest.raises(BackendNotAvailable):
                if connection_type == "authenticated":
                    await connect_as_authenticated(
                        addr=BackendOrganizationAddr.from_url(
                            f"parsec://127.0.0.1:{target_port}/CoolOrg?no_ssl=true&rvk=7NFDS4VQLP3XPCMTSEN34ZOXKGGIMTY2W2JI2SPIHB2P3M6K4YWAssss"
                        ),
                        device_id=device_id,
                        signing_key=signing_key,
                    )

                else:
                    assert connection_type == "invited"
                    await connect_as_invited(addr=BackendInvitationAddr.from_url(
                        f"parsec://127.0.0.1:{target_port}/CoolOrg?no_ssl=true&action=claim_user&token=3a50b191122b480ebb113b10216ef343"
                    ))

        assert proxy_events == [
            *(["PAC file retreived from server"]
              if proxy_type == "http_proxy_pac" else []),
            "Connected to proxy",
            "Reaching target through proxy",
        ]

        nursery.cancel_scope.cancel()
Esempio n. 18
0
    def dump_sign_and_encrypt_for(self, author_signkey: SigningKey,
                                  recipient_pubkey: PublicKey) -> bytes:
        """
        Raises:
            DataError
        """
        try:
            signed = author_signkey.sign(self._serialize())
            return recipient_pubkey.encrypt_for_self(signed)

        except CryptoError as exc:
            raise DataError(str(exc)) from exc
Esempio n. 19
0
def generate_new_device(device_id: DeviceID,
                        organization_addr: BackendOrganizationAddr,
                        is_admin: bool = False) -> LocalDevice:
    return LocalDevice(
        organization_addr=organization_addr,
        device_id=device_id,
        signing_key=SigningKey.generate(),
        private_key=PrivateKey.generate(),
        is_admin=is_admin,
        user_manifest_id=EntryID(uuid4().hex),
        user_manifest_key=SecretKey.generate(),
        local_symkey=SecretKey.generate(),
    )
Esempio n. 20
0
async def _create_new_device_for_self(
        original_device: LocalDevice,
        new_device_label: DeviceLabel) -> LocalDevice:
    """
    Raises:
        BackendConnectionError
    """
    new_device = LocalDevice(
        organization_addr=original_device.organization_addr,
        device_id=DeviceID(f"{original_device.user_id}@{DeviceName.new()}"),
        device_label=new_device_label,
        human_handle=original_device.human_handle,
        profile=original_device.profile,
        private_key=original_device.private_key,
        signing_key=SigningKey.generate(),
        user_manifest_id=original_device.user_manifest_id,
        user_manifest_key=original_device.user_manifest_key,
        local_symkey=SecretKey.generate(),
    )
    now = pendulum_now()

    device_certificate = DeviceCertificateContent(
        author=original_device.device_id,
        timestamp=now,
        device_id=new_device.device_id,
        device_label=new_device.device_label,
        verify_key=new_device.verify_key,
    )
    redacted_device_certificate = device_certificate.evolve(device_label=None)

    device_certificate = device_certificate.dump_and_sign(
        original_device.signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(
        original_device.signing_key)

    async with backend_authenticated_cmds_factory(
            addr=original_device.organization_addr,
            device_id=original_device.device_id,
            signing_key=original_device.signing_key,
    ) as cmds:
        rep = await cmds.device_create(
            device_certificate=device_certificate,
            redacted_device_certificate=redacted_device_certificate,
        )

    if rep["status"] != "ok":
        raise BackendConnectionError(f"Cannot create recovery device: {rep}")

    return new_device
Esempio n. 21
0
def _check_equal_backend_organization_bootstrap_addrs(rs, py):
    assert rs.to_url() == py.to_url()
    assert rs.hostname == py.hostname
    assert rs.port == py.port
    assert rs.netloc == py.netloc
    assert rs.use_ssl == py.use_ssl
    assert str(rs.organization_id) == str(py.organization_id)
    assert rs.token == py.token
    assert str(rs) == str(py)
    assert hash(rs) == hash(py)
    assert repr(rs) == repr(py)
    vk = SigningKey.generate().verify_key
    assert (rs.generate_organization_addr(
        root_verify_key=vk).to_url() == py.generate_organization_addr(
            root_verify_key=vk).to_url())
Esempio n. 22
0
def test_build_addrs():
    backend_addr = BackendAddr.from_url(BackendAddrTestbed.url)
    assert backend_addr.hostname == "parsec.cloud.com"
    assert backend_addr.port == 443
    assert backend_addr.use_ssl is True

    organization_id = OrganizationID("MyOrg")
    root_verify_key = SigningKey.generate().verify_key

    organization_addr = BackendOrganizationAddr.build(
        backend_addr=backend_addr, organization_id=organization_id, root_verify_key=root_verify_key
    )
    assert organization_addr.organization_id == organization_id
    assert organization_addr.root_verify_key == root_verify_key

    organization_bootstrap_addr = BackendOrganizationBootstrapAddr.build(
        backend_addr=backend_addr,
        organization_id=organization_id,
        token="a0000000000000000000000000000001",
    )
    assert organization_bootstrap_addr.token == "a0000000000000000000000000000001"
    assert organization_bootstrap_addr.organization_id == organization_id

    organization_bootstrap_addr2 = BackendOrganizationBootstrapAddr.build(
        backend_addr=backend_addr, organization_id=organization_id, token=None
    )
    assert organization_bootstrap_addr2.organization_id == organization_id
    assert organization_bootstrap_addr2.token == ""

    organization_file_link_addr = BackendOrganizationFileLinkAddr.build(
        organization_addr=organization_addr,
        workspace_id=EntryID.from_hex("2d4ded12-7406-4608-833b-7f57f01156e2"),
        encrypted_path=b"<encrypted_payload>",
    )
    assert organization_file_link_addr.workspace_id == EntryID.from_hex(
        "2d4ded12-7406-4608-833b-7f57f01156e2"
    )
    assert organization_file_link_addr.encrypted_path == b"<encrypted_payload>"

    invitation_addr = BackendInvitationAddr.build(
        backend_addr=backend_addr,
        organization_id=organization_id,
        invitation_type=InvitationType.USER,
        token=InvitationToken.from_hex("a0000000000000000000000000000001"),
    )
    assert invitation_addr.organization_id == organization_id
    assert invitation_addr.token == InvitationToken.from_hex("a0000000000000000000000000000001")
    assert invitation_addr.invitation_type == InvitationType.USER
Esempio n. 23
0
def _check_equal_backend_pki_enrollment_addrs(rs, py):
    assert rs.to_url() == py.to_url()
    assert rs.hostname == py.hostname
    assert rs.port == py.port
    assert rs.netloc == py.netloc
    assert rs.use_ssl == py.use_ssl
    assert rs.to_http_domain_url() == py.to_http_domain_url() + "/"
    assert rs.to_http_domain_url("/path") == py.to_http_domain_url("/path")
    assert str(rs.organization_id) == str(py.organization_id)
    assert str(rs) == str(py)
    assert hash(rs) == hash(py)
    assert repr(rs) == repr(py)
    vk = SigningKey.generate().verify_key
    assert (rs.generate_organization_addr(
        root_verify_key=vk).to_url() == py.generate_organization_addr(
            root_verify_key=vk).to_url())
Esempio n. 24
0
    def _organization_factory(orgname=None):
        nonlocal count

        if not orgname:
            count += 1
            orgname = f"Org{count}"

        organization_id = OrganizationID(orgname)
        assert organization_id not in organizations
        organizations.add(organization_id)
        bootstrap_token = f"<{orgname}-bootstrap-token>"
        bootstrap_addr = BackendOrganizationBootstrapAddr.build(
            backend_addr, organization_id=organization_id, token=bootstrap_token
        )
        root_signing_key = SigningKey.generate()
        addr = bootstrap_addr.generate_organization_addr(root_signing_key.verify_key)
        return OrganizationFullData(bootstrap_addr, addr, root_signing_key)
Esempio n. 25
0
    async def do_claim_device(
            self, requested_device_label: Optional[str]) -> LocalDevice:
        signing_key = SigningKey.generate()

        try:
            payload = InviteDeviceData(
                requested_device_label=requested_device_label,
                verify_key=signing_key.verify_key).dump_and_encrypt(
                    key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Cannot generate InviteDeviceData payload") from exc

        rep = await self._cmds.invite_4_claimer_communicate(payload=payload)
        _check_rep(rep, step_name="step 4 (data exchange)")

        rep = await self._cmds.invite_4_claimer_communicate(payload=b"")
        _check_rep(rep, step_name="step 4 (confirmation exchange)")

        try:
            confirmation = InviteDeviceConfirmation.decrypt_and_load(
                rep["payload"], key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Invalid InviteDeviceConfirmation payload provided by peer"
            ) from exc

        organization_addr = BackendOrganizationAddr.build(
            backend_addr=self._cmds.addr,
            organization_id=self._cmds.addr.organization_id,
            root_verify_key=confirmation.root_verify_key,
        )

        return LocalDevice(
            organization_addr=organization_addr,
            device_id=confirmation.device_id,
            device_label=confirmation.device_label,
            human_handle=confirmation.human_handle,
            profile=confirmation.profile,
            private_key=confirmation.private_key,
            signing_key=signing_key,
            user_manifest_id=confirmation.user_manifest_id,
            user_manifest_key=confirmation.user_manifest_key,
            local_symkey=SecretKey.generate(),
        )
Esempio n. 26
0
def test_backend_organization_addr_init():
    from parsec.core.types.backend_address import (
        _PyBackendOrganizationAddr,
        _RsBackendOrganizationAddr,
        BackendOrganizationAddr,
    )

    assert BackendOrganizationAddr is _RsBackendOrganizationAddr

    vk = SigningKey.generate().verify_key

    py_ba = _PyBackendOrganizationAddr(OrganizationID("MyOrg"),
                                       vk,
                                       hostname="parsec.cloud")
    rs_ba = BackendOrganizationAddr(OrganizationID("MyOrg"),
                                    vk,
                                    hostname="parsec.cloud")

    _check_equal_backend_organization_addrs(rs_ba, py_ba)
Esempio n. 27
0
def test_backend_organization_addr_build():
    from parsec.core.types.backend_address import (
        _PyBackendOrganizationAddr,
        _RsBackendOrganizationAddr,
        BackendOrganizationAddr,
        BackendAddr,
    )

    assert BackendOrganizationAddr is _RsBackendOrganizationAddr

    BACKEND_ADDR = BackendAddr.from_url("parsec://parsec.cloud:1337")

    vk = SigningKey.generate().verify_key

    py_ba = _PyBackendOrganizationAddr.build(BACKEND_ADDR,
                                             OrganizationID("MyOrg"), vk)
    rs_ba = BackendOrganizationAddr.build(BACKEND_ADDR,
                                          OrganizationID("MyOrg"), vk)
    _check_equal_backend_organization_addrs(rs_ba, py_ba)
Esempio n. 28
0
def test_revoked_user_certificate():
    from parsec.api.data.certif import (
        _RsRevokedUserCertificateContent,
        RevokedUserCertificateContent,
        _PyRevokedUserCertificateContent,
    )

    assert RevokedUserCertificateContent is _RsRevokedUserCertificateContent

    def _assert_revoked_user_certificate_eq(py, rs):
        assert py.author == rs.author
        assert py.timestamp == rs.timestamp
        assert py.user_id == rs.user_id

    kwargs = {"author": DeviceID.new(), "timestamp": pendulum.now(), "user_id": UserID("bob")}

    py_ruc = _PyRevokedUserCertificateContent(**kwargs)
    rs_ruc = RevokedUserCertificateContent(**kwargs)
    _assert_revoked_user_certificate_eq(py_ruc, rs_ruc)

    kwargs = {"author": DeviceID.new(), "timestamp": pendulum.now(), "user_id": UserID("alice")}

    py_ruc = py_ruc.evolve(**kwargs)
    rs_ruc = rs_ruc.evolve(**kwargs)
    _assert_revoked_user_certificate_eq(py_ruc, rs_ruc)

    sign_key = SigningKey.generate()
    py_data = py_ruc.dump_and_sign(sign_key)
    rs_data = rs_ruc.dump_and_sign(sign_key)

    py_ruc = _PyRevokedUserCertificateContent.verify_and_load(
        rs_data, sign_key.verify_key, expected_author=py_ruc.author, expected_user=py_ruc.user_id
    )
    rs_ruc = RevokedUserCertificateContent.verify_and_load(
        py_data, sign_key.verify_key, expected_author=rs_ruc.author, expected_user=rs_ruc.user_id
    )
    _assert_revoked_user_certificate_eq(py_ruc, rs_ruc)

    py_ruc = _PyRevokedUserCertificateContent.unsecure_load(rs_data)
    rs_ruc = RevokedUserCertificateContent.unsecure_load(py_data)
    _assert_revoked_user_certificate_eq(py_ruc, rs_ruc)
Esempio n. 29
0
def generate_new_device(
    organization_addr: BackendOrganizationAddr,
    device_id: Optional[DeviceID] = None,
    profile: UserProfile = UserProfile.STANDARD,
    human_handle: Optional[HumanHandle] = None,
    device_label: Optional[DeviceLabel] = None,
    signing_key: Optional[SigningKey] = None,
    private_key: Optional[PrivateKey] = None,
) -> LocalDevice:
    return LocalDevice(
        organization_addr=organization_addr,
        device_id=device_id or DeviceID.new(),
        device_label=device_label,
        human_handle=human_handle,
        signing_key=signing_key or SigningKey.generate(),
        private_key=private_key or PrivateKey.generate(),
        profile=profile,
        user_manifest_id=EntryID.new(),
        user_manifest_key=SecretKey.generate(),
        local_symkey=SecretKey.generate(),
    )
Esempio n. 30
0
    async def new(
        cls, addr: BackendPkiEnrollmentAddr
    ) -> "PkiEnrollmentSubmitterSubmittedStatusCtx":
        """
        Raises:
            PkiEnrollmentCertificateError
            PkiEnrollmentCertificateCryptoError
            PkiEnrollmentCertificateNotFoundError
        """
        enrollment_id = uuid4()
        signing_key = SigningKey.generate()
        private_key = PrivateKey.generate()

        x509_certificate = await pki_enrollment_select_certificate()

        return cls(
            addr=addr,
            enrollment_id=enrollment_id,
            signing_key=signing_key,
            private_key=private_key,
            x509_certificate=x509_certificate,
        )