Beispiel #1
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"
            )),
    )
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(),
    )
Beispiel #3
0
def correct_addr(to_correct: Union[BackendAddr, LocalDevice,
                                   OrganizationFullData],
                 port: int) -> BackendAddr:
    """
    Helper to fix a backend address so that it will reach the current server.
    This not needed when using `running_backend` (given in this case the
    alice/bob/coolorg etc. fixtures are created with the correct port), but
    must be used when the test has to manually start server (e.g. in
    the hypothesis tests)
    """
    if isinstance(to_correct, LocalDevice):
        return LocalDevice(
            organization_addr=correct_addr(to_correct.organization_addr, port),
            device_id=to_correct.device_id,
            device_label=to_correct.device_label,
            human_handle=to_correct.human_handle,
            signing_key=to_correct.signing_key,
            private_key=to_correct.private_key,
            profile=to_correct.profile,
            user_manifest_id=to_correct.user_manifest_id,
            user_manifest_key=to_correct.user_manifest_key,
            local_symkey=to_correct.local_symkey,
        )
    elif isinstance(to_correct, OrganizationFullData):
        return OrganizationFullData(
            bootstrap_addr=correct_addr(to_correct.bootstrap_addr, port),
            addr=correct_addr(to_correct.addr, port),
            root_signing_key=to_correct.root_signing_key,
        )
    else:
        # Consider it's a regular addr
        *_, to_keep = to_correct.to_url().removeprefix("parsec://").split(
            "/", 1)
        url = f"parsec://127.0.0.1:{port}/{to_keep}"
        return to_correct.__class__.from_url(url)
Beispiel #4
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"
            )),
    )
Beispiel #5
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(),
    )
Beispiel #6
0
    async def do_claim_device(
            self,
            requested_device_label: Optional[DeviceLabel]) -> LocalDevice:
        # Device key is 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 certificate in
        # the server.
        # This is considered acceptable given 1) the error window is small and
        # 2) if this occurs the inviter can revoke the device and retry the
        # enrollment process to fix this
        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.get_backend_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(),
        )
Beispiel #7
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)
        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 = 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(),
        )
Beispiel #8
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(),
    )
Beispiel #9
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
Beispiel #10
0
 def _correct_local_device_backend_addr(device):
     organization_addr = BackendOrganizationAddr.build(
         backend_addr,
         organization_id=device.organization_addr.organization_id,
         root_verify_key=device.organization_addr.root_verify_key,
     )
     return LocalDevice(
         organization_addr=organization_addr,
         device_id=device.device_id,
         device_label=device.device_label,
         human_handle=device.human_handle,
         signing_key=device.signing_key,
         private_key=device.private_key,
         profile=device.profile,
         user_manifest_id=device.user_manifest_id,
         user_manifest_key=device.user_manifest_key,
         local_symkey=device.local_symkey,
     )
Beispiel #11
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(),
    )
Beispiel #12
0
async def _register_new_device(cmds: BackendAuthenticatedCmds,
                               author: LocalDevice,
                               device_label: Optional[str]):
    new_device = LocalDevice(
        organization_addr=author.organization_addr,
        device_id=DeviceID(f"{author.user_id}@{DeviceName.new()}"),
        device_label=device_label,
        human_handle=author.human_handle,
        profile=author.profile,
        private_key=author.private_key,
        signing_key=SigningKey.generate(),
        user_manifest_id=author.user_manifest_id,
        user_manifest_key=author.user_manifest_key,
        local_symkey=author.local_symkey,
    )
    now = pendulum_now()

    device_certificate = DeviceCertificateContent(
        author=author.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(author.signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(
        author.signing_key)

    rep = await cmds.device_create(
        device_certificate=device_certificate,
        redacted_device_certificate=redacted_device_certificate,
    )

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

    return new_device
Beispiel #13
0
async def claim_device(
    organization_addr: BackendOrganizationAddr,
    new_device_id: DeviceID,
    token: str,
    keepalive: Optional[int] = None,
) -> LocalDevice:
    """
    Raises:
        InviteClaimError
        InviteClaimBackendOfflineError
        InviteClaimValidationError
        InviteClaimPackingError
        InviteClaimCryptoError
    """
    device_signing_key = SigningKey.generate()
    answer_private_key = PrivateKey.generate()

    try:
        async with backend_anonymous_cmds_factory(organization_addr,
                                                  keepalive=keepalive) as cmds:
            # 1) Retrieve invitation creator
            try:
                invitation_creator_user, invitation_creator_device = await get_device_invitation_creator(
                    cmds, organization_addr.root_verify_key, new_device_id)

            except RemoteDevicesManagerBackendOfflineError as exc:
                raise InviteClaimBackendOfflineError(str(exc)) from exc

            except RemoteDevicesManagerError as exc:
                raise InviteClaimError(
                    f"Cannot retrieve invitation creator: {exc}") from exc

            # 2) Generate claim info for invitation creator
            try:
                encrypted_claim = DeviceClaimContent(
                    token=token,
                    device_id=new_device_id,
                    verify_key=device_signing_key.verify_key,
                    answer_public_key=answer_private_key.public_key,
                ).dump_and_encrypt_for(
                    recipient_pubkey=invitation_creator_user.public_key)

            except DataError as exc:
                raise InviteClaimError(
                    f"Cannot generate device claim message: {exc}") from exc

            # 3) Send claim
            rep = await cmds.device_claim(new_device_id, encrypted_claim)
            if rep["status"] != "ok":
                raise InviteClaimError(f"Claim request error: {rep}")

            # 4) Verify device certificate
            try:
                DeviceCertificateContent.verify_and_load(
                    rep["device_certificate"],
                    author_verify_key=invitation_creator_device.verify_key,
                    expected_author=invitation_creator_device.device_id,
                    expected_device=new_device_id,
                )

            except DataError as exc:
                raise InviteClaimCryptoError(str(exc)) from exc

            try:
                answer = DeviceClaimAnswerContent.decrypt_and_load_for(
                    rep["encrypted_answer"],
                    recipient_privkey=answer_private_key)

            except DataError as exc:
                raise InviteClaimCryptoError(
                    f"Cannot decrypt device claim answer: {exc}") from exc

    except BackendNotAvailable as exc:
        raise InviteClaimBackendOfflineError(str(exc)) from exc

    except BackendConnectionError as exc:
        raise InviteClaimError(f"Cannot claim device: {exc}") from exc

    return LocalDevice(
        organization_addr=organization_addr,
        device_id=new_device_id,
        signing_key=device_signing_key,
        private_key=answer.private_key,
        is_admin=invitation_creator_user.is_admin,
        user_manifest_id=answer.user_manifest_id,
        user_manifest_key=answer.user_manifest_key,
        local_symkey=SecretKey.generate(),
    )