Example #1
0
def test_public_key_handler_revoke():
    """
    Case: send transaction request to revoke certificate public key.
    Expect: public key storage blockchain record is changed to True.
    """
    revoke_public_key_payload = RevokePubKeyPayload(
        address=ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY,
    )

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.REVOKE
    transaction_payload.data = revoke_public_key_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = generate_header(serialized_transaction_payload, INPUTS, OUTPUTS)

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(private_key=SENDER_PRIVATE_KEY).sign(serialized_header),
    )

    existing_public_key_payload = generate_rsa_payload()

    existing_public_key_storage = PubKeyStorage()
    existing_public_key_storage.owner = SENDER_PUBLIC_KEY
    existing_public_key_storage.payload.CopyFrom(existing_public_key_payload)
    existing_public_key_storage.is_revoked = False
    serialized_existing_public_key_storage = existing_public_key_storage.SerializeToString()

    mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: serialized_existing_public_key_storage,
    })

    expected_public_key_payload = generate_rsa_payload()

    expected_public_key_storage = PubKeyStorage()
    expected_public_key_storage.owner = SENDER_PUBLIC_KEY
    expected_public_key_storage.payload.CopyFrom(expected_public_key_payload)
    expected_public_key_storage.is_revoked = True
    serialized_expected_public_key_storage = expected_public_key_storage.SerializeToString()

    expected_state = {
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: serialized_expected_public_key_storage,
    }

    PubKeyHandler().apply(transaction=transaction_request, context=mock_context)

    state_as_list = mock_context.get_state(addresses=[ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY])
    state_as_dict = {entry.address: entry.data for entry in state_as_list}

    assert expected_state == state_as_dict
Example #2
0
    def test_store_success(self):
        context = self.get_context()

        cert, key, _ = create_certificate(context.pub_key_payload,
                                          signer=context.client.get_signer())
        cert_address, transaction_payload = self._pre_parse_payload_and_exec(
            context, cert, key)
        crt_export, crt_bin, crt_sig, rem_sig, pub_key, \
            valid_from, valid_to = get_crt_export_bin_sig_rem_sig(cert, key, context.client)

        account = AccountClient.get_account_model(PUB_KEY_STORE_PRICE)

        data = PubKeyStorage()
        data.owner = self.account_signer1.get_public_key().as_hex()
        data.payload.CopyFrom(transaction_payload)
        data.revoked = False

        self.expect_get({cert_address: None, self.account_address1: account})
        self.expect_get({_make_settings_key('remme.economy_enabled'): None})

        context.client.store_pub_key(pub_key, rem_sig, crt_sig, valid_from,
                                     valid_to)

        account.balance -= PUB_KEY_STORE_PRICE
        account.pub_keys.append(cert_address)

        self.expect_set({self.account_address1: account, cert_address: data})

        self.expect_ok()
Example #3
0
    def _store_pub_key(self, context, signer_pubkey, transaction_payload):
        address = self.make_address_from_data(transaction_payload.public_key)
        LOGGER.info('Pub key address {}'.format(address))

        account_address = AccountHandler().make_address_from_data(signer_pubkey)
        LOGGER.info('Account address {}'.format(address))
        data, account = get_multiple_data(context, [(address, PubKeyStorage), (account_address, Account)])
        if data:
            raise InvalidTransaction('This pub key is already registered.')

        cert_signer_pubkey = load_pem_public_key(transaction_payload.public_key.encode('utf-8'),
                                                 backend=default_backend())
        try:
            ehs_bytes = binascii.unhexlify(transaction_payload.entity_hash_signature)
            eh_bytes = binascii.unhexlify(transaction_payload.entity_hash)
        except binascii.Error:
            LOGGER.debug(f'entity_hash_signature {transaction_payload.entity_hash_signature}')
            LOGGER.debug(f'entity_hash {transaction_payload.entity_hash}')
            raise InvalidTransaction('Entity hash or signature not a hex format')

        # FIXME: For support PKCS1v15 and PSS
        LOGGER.warn('HAZARD: Detecting padding for verification')
        sigerr = 0
        pkcs = padding.PKCS1v15()
        pss = padding.PSS(mgf=padding.MGF1(hashes.SHA512()), salt_length=padding.PSS.MAX_LENGTH)
        for _padding in (pkcs, pss):
            try:
                cert_signer_pubkey.verify(ehs_bytes, eh_bytes, _padding, hashes.SHA512())
                LOGGER.warn('HAZARD: Padding found: %s', _padding.name)
            except InvalidSignature:
                sigerr += 1

        if sigerr == 2:
            raise InvalidTransaction('Invalid signature')

        valid_from = datetime.fromtimestamp(transaction_payload.valid_from)
        valid_to = datetime.fromtimestamp(transaction_payload.valid_to)

        if valid_to - valid_from > PUB_KEY_MAX_VALIDITY:
            raise InvalidTransaction('The public key validity exceeds the maximum value.')

        data = PubKeyStorage()
        data.owner = signer_pubkey
        data.payload.CopyFrom(transaction_payload)
        data.revoked = False

        if not account:
            account = Account()
        if _get_setting_value(context, 'remme.economy_enabled', 'true').lower() == 'true':
            if account.balance < PUB_KEY_STORE_PRICE:
                raise InvalidTransaction('Not enough tokens to register a new pub key. Current balance: {}'
                                         .format(account.balance))
            account.balance -= PUB_KEY_STORE_PRICE

        if address not in account.pub_keys:
            account.pub_keys.append(address)

        return {address: data,
                account_address: account}
Example #4
0
    def test_store_success(self):
        context = self.get_context()

        cert, key, _ = PubKeyClient.create_certificate(
            context.pub_key_payload, signer=context.client.get_signer())

        transaction_signature, cert_address, transaction_payload = self._pre_parse_payload_and_exec(
            context, cert, key)
        crt_export, crt_bin, crt_sig, rem_sig, pub_key, \
            valid_from, valid_to = PubKeyClient.get_crt_export_bin_sig_rem_sig(cert, key, context.client)

        account = AccountClient.get_account_model(PUB_KEY_STORE_PRICE)

        storage_account = AccountClient.get_account_model(0)
        storage_signer = self.get_new_signer()
        storage_pub_key = storage_signer.get_public_key().as_hex()
        storage_address = AccountHandler().make_address_from_data(
            storage_pub_key)

        data = PubKeyStorage()
        data.owner = self.account_signer1.get_public_key().as_hex()
        data.payload.CopyFrom(transaction_payload)
        data.revoked = False

        self.expect_get({cert_address: None, self.account_address1: account})
        self.expect_get({_make_settings_key('remme.economy_enabled'): None})
        self.expect_get({
            _make_settings_key(SETTINGS_STORAGE_PUB_KEY):
            get_setting_from_key_value(SETTINGS_STORAGE_PUB_KEY,
                                       storage_pub_key)
        })
        self.expect_get({
            self.account_address1: account,
            storage_address: storage_account
        })

        context.client.store_pub_key(pub_key, rem_sig, crt_sig, valid_from,
                                     valid_to)

        account.balance -= PUB_KEY_STORE_PRICE
        account.pub_keys.append(cert_address)
        storage_account.balance += PUB_KEY_STORE_PRICE

        self.expect_set(
            transaction_signature, PubKeyMethod.STORE, {
                self.account_address1: account,
                cert_address: data,
                storage_address: storage_account
            })

        self.expect_ok()
def test_store_public_key_for_other_already_registered_public_key():
    """
    Case: send transaction request to store already registered certificate public key for other.
    Expect: invalid transaction error is raised with public key is already registered error message.
    """
    new_public_key_payload = generate_rsa_payload(key=CERTIFICATE_PUBLIC_KEY)
    serialized_new_public_key_payload = new_public_key_payload.SerializeToString()

    private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY)
    signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key)

    new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload(
        pub_key_payload=new_public_key_payload,
        owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY),
        signature_by_owner=bytes.fromhex(signature_by_owner),
    )

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.STORE_AND_PAY
    transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = generate_header(
        serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY,
    )

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header),
    )

    already_registered_public_key = PubKeyStorage()
    already_registered_public_key.owner = OWNER_PUBLIC_KEY
    already_registered_public_key.payload.CopyFrom(new_public_key_payload)
    already_registered_public_key.is_revoked = False
    serialized_already_registered_public_key = already_registered_public_key.SerializeToString()

    mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: serialized_already_registered_public_key,
    })

    with pytest.raises(InvalidTransaction) as error:
        PubKeyHandler().apply(transaction=transaction_request, context=mock_context)

    assert 'This public key is already registered.' == str(error.value)
Example #6
0
    def test_revoke_fail_wrong_signer(self):
        context = self.get_context()

        cert, key, key_export = create_certificate(context.pub_key_payload,
                                                   org_name='different',
                                                   signer=self.account_signer2)
        cert_address, transaction_payload = self._pre_parse_payload_and_exec(context, cert, key, 'revoke')

        data = PubKeyStorage()
        data.owner = self.account_signer2.get_public_key().as_hex()
        data.payload.CopyFrom(transaction_payload)
        data.revoked = False

        self.expect_get({cert_address: data})

        self.expect_invalid_transaction()
Example #7
0
def test_public_key_handler_store_already_registered_public_key():
    """
    Case: send transaction request to store already registered certificate public key.
    Expect: invalid transaction error is raised with public key is already registered error message.
    """
    new_public_key_payload = generate_rsa_payload()

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.STORE
    transaction_payload.data = new_public_key_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = generate_header(serialized_transaction_payload,
                                         INPUTS, OUTPUTS)

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(
            private_key=SENDER_PRIVATE_KEY).sign(serialized_header),
    )

    already_registered_public_key = PubKeyStorage()
    already_registered_public_key.owner = SENDER_PUBLIC_KEY
    already_registered_public_key.payload.CopyFrom(new_public_key_payload)
    already_registered_public_key.is_revoked = False
    serialized_already_registered_public_key = already_registered_public_key.SerializeToString(
    )

    mock_context = StubContext(inputs=INPUTS,
                               outputs=OUTPUTS,
                               initial_state={
                                   ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY:
                                   serialized_already_registered_public_key,
                               })

    with pytest.raises(InvalidTransaction) as error:
        PubKeyHandler().apply(transaction=transaction_request,
                              context=mock_context)

    assert 'This public key is already registered.' == str(error.value)
Example #8
0
def test_public_key_handler_revoke_already_revoked():
    """
    Case: send transaction request to revoke already revoked certificate public key.
    Expect: invalid transaction error is raised with no certificate public key is presented in chain error message.
    """
    revoke_public_key_payload = RevokePubKeyPayload(
        address=ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY,
    )

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.REVOKE
    transaction_payload.data = revoke_public_key_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = generate_header(serialized_transaction_payload, INPUTS, OUTPUTS)

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(private_key=SENDER_PRIVATE_KEY).sign(serialized_header),
    )

    existing_public_key_payload = generate_rsa_payload()

    existing_public_key_storage = PubKeyStorage()
    existing_public_key_storage.owner = SENDER_PUBLIC_KEY
    existing_public_key_storage.payload.CopyFrom(existing_public_key_payload)
    existing_public_key_storage.is_revoked = True
    serialized_existing_public_key_storage = existing_public_key_storage.SerializeToString()

    mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: serialized_existing_public_key_storage,
    })

    with pytest.raises(InvalidTransaction) as error:
        PubKeyHandler().apply(transaction=transaction_request, context=mock_context)

    assert 'The public key is already revoked.' == str(error.value)
Example #9
0
    def test_revoke_success(self):
        context = self.get_context()

        cert, key, key_export = PubKeyClient.create_certificate(
            context.pub_key_payload,
            org_name='different',
            signer=self.account_signer2)
        transaction_signature, cert_address, transaction_payload = self._pre_parse_payload_and_exec(
            context, cert, key, 'revoke')

        data = PubKeyStorage()
        data.owner = context.client.get_signer().get_public_key().as_hex()
        data.payload.CopyFrom(transaction_payload)
        data.revoked = False

        self.expect_get({cert_address: data})

        data.revoked = True

        self.expect_set(transaction_signature, PubKeyMethod.REVOKE,
                        {cert_address: data})

        self.expect_ok()
Example #10
0
    def test_store_success(self):
        context = self.get_context()

        cert, key, _ = create_certificate(context.pub_key_payload, signer=context.client.get_signer())
        cert_address, transaction_payload = self._pre_parse_payload_and_exec(context, cert, key)
        self.expect_get({cert_address: None})

        account = AccountClient.get_account_model(PUB_KEY_STORE_PRICE)
        self.expect_get({self.account_address1: account})

        data = PubKeyStorage()
        data.owner = self.account_signer1.get_public_key().as_hex()
        data.payload.CopyFrom(transaction_payload)
        data.revoked = False

        account.balance -= PUB_KEY_STORE_PRICE
        account.pub_keys.append(cert_address)

        self.expect_set({
            self.account_address1: account,
            cert_address: data
        })

        self.expect_ok()
def test_store_ecdsa_public_key():
    """
    Case: send transaction request to store certificate public key (ECDSA) for other.
    Expect: public key information is stored to blockchain linked to owner address. Transaction sender paid for storing.
    """
    inputs = outputs = [
        ADDRESS_FROM_ECDSA_PUBLIC_KEY,
        OWNER_ADDRESS,
        PAYER_ADDRESS,
        ZERO_ADDRESS,
        IS_NODE_ECONOMY_ENABLED_ADDRESS,
    ]

    new_public_key_payload = generate_ecdsa_payload(key=ECDSA_PUBLIC_KEY)
    serialized_new_public_key_payload = new_public_key_payload.SerializeToString()

    private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY)
    signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key)

    new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload(
        pub_key_payload=new_public_key_payload,
        owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY),
        signature_by_owner=bytes.fromhex(signature_by_owner),
    )

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.STORE_AND_PAY
    transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = generate_header(
        serialized_transaction_payload, inputs, outputs, signer_public_key=PAYER_PUBLIC_KEY,
    )

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header),
    )

    payer_account = Account()
    payer_account.balance = PAYER_INITIAL_BALANCE
    serialized_payer_account = payer_account.SerializeToString()

    owner_account = Account()
    owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS)
    serialized_owner_account = owner_account.SerializeToString()

    zero_account = Account()
    zero_account.balance = 0
    serialized_zero_account = zero_account.SerializeToString()

    mock_context = StubContext(inputs=inputs, outputs=outputs, initial_state={
        OWNER_ADDRESS: serialized_owner_account,
        PAYER_ADDRESS: serialized_payer_account,
        ZERO_ADDRESS: serialized_zero_account,
    })

    expected_public_key_storage = PubKeyStorage()
    expected_public_key_storage.owner = OWNER_PUBLIC_KEY
    expected_public_key_storage.payload.CopyFrom(new_public_key_payload)
    expected_public_key_storage.is_revoked = False
    expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString()

    expected_payer_account = Account()
    expected_payer_account.balance = PAYER_INITIAL_BALANCE - PUB_KEY_STORE_PRICE
    serialized_expected_payer_account = expected_payer_account.SerializeToString()

    expected_owner_account = Account()
    expected_owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS)
    expected_owner_account.pub_keys.append(ADDRESS_FROM_ECDSA_PUBLIC_KEY)
    serialized_expected_owner_account = expected_owner_account.SerializeToString()

    expected_zero_account = Account()
    expected_zero_account.balance = 0 + PUB_KEY_STORE_PRICE
    expected_serialized_zero_account = expected_zero_account.SerializeToString()

    expected_state = {
        OWNER_ADDRESS: serialized_expected_owner_account,
        PAYER_ADDRESS: serialized_expected_payer_account,
        ADDRESS_FROM_ECDSA_PUBLIC_KEY: expected_serialized_public_key_storage,
        ZERO_ADDRESS: expected_serialized_zero_account,
    }

    PubKeyHandler().apply(transaction=transaction_request, context=mock_context)

    state_as_list = mock_context.get_state(addresses=[
        OWNER_ADDRESS, PAYER_ADDRESS, ADDRESS_FROM_ECDSA_PUBLIC_KEY, ZERO_ADDRESS,
    ])

    state_as_dict = {entry.address: entry.data for entry in state_as_list}

    assert expected_state == state_as_dict
Example #12
0
def test_public_key_handler_rsa_store():
    """
    Case: send transaction request to store certificate public key.
    Expect: public key information is stored to blockchain linked to owner address. Owner paid tokens for storing.
    """
    new_public_key_payload = generate_rsa_payload()

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.STORE
    transaction_payload.data = new_public_key_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = generate_header(serialized_transaction_payload,
                                         INPUTS, OUTPUTS)

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(
            private_key=SENDER_PRIVATE_KEY).sign(serialized_header),
    )

    sender_account = Account()
    sender_account.balance = SENDER_INITIAL_BALANCE
    sender_account.pub_keys.append(RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY)
    serialized_sender_account = sender_account.SerializeToString()

    zero_account = Account()
    zero_account.balance = 0
    serialized_zero_account = zero_account.SerializeToString()

    mock_context = StubContext(inputs=INPUTS,
                               outputs=OUTPUTS,
                               initial_state={
                                   SENDER_ADDRESS: serialized_sender_account,
                                   ZERO_ADDRESS: serialized_zero_account,
                               })

    expected_public_key_storage = PubKeyStorage()
    expected_public_key_storage.owner = SENDER_PUBLIC_KEY
    expected_public_key_storage.payload.CopyFrom(new_public_key_payload)
    expected_public_key_storage.is_revoked = False
    expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString(
    )

    expected_sender_account = Account()
    expected_sender_account.balance = SENDER_INITIAL_BALANCE - PUB_KEY_STORE_PRICE
    expected_sender_account.pub_keys.append(
        RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY)
    expected_sender_account.pub_keys.append(
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY)
    expected_serialized_sender_account = expected_sender_account.SerializeToString(
    )

    expected_zero_account = Account()
    expected_zero_account.balance = 0 + PUB_KEY_STORE_PRICE
    expected_serialized_zero_account = expected_zero_account.SerializeToString(
    )

    expected_state = {
        SENDER_ADDRESS: expected_serialized_sender_account,
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY:
        expected_serialized_public_key_storage,
        ZERO_ADDRESS: expected_serialized_zero_account,
    }

    PubKeyHandler().apply(transaction=transaction_request,
                          context=mock_context)

    state_as_list = mock_context.get_state(addresses=[
        SENDER_ADDRESS,
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY,
        ZERO_ADDRESS,
    ])

    state_as_dict = {entry.address: entry.data for entry in state_as_list}

    assert expected_state == state_as_dict
Example #13
0
def test_public_key_handler_store_sender_is_node():
    """
    Case: send transaction request, to store certificate public key, when sender is node (same addresses).
    Expect: public key information is stored to blockchain linked to owner address. Owner hasn't paid for storing.
    """
    new_public_key_payload = generate_rsa_payload()

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.STORE
    transaction_payload.data = new_public_key_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = generate_header(serialized_transaction_payload,
                                         INPUTS, OUTPUTS)

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(
            private_key=SENDER_PRIVATE_KEY).sign(serialized_header),
    )

    sender_account = Account()
    sender_account.pub_keys.append(RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY)
    serialized_sender_account = sender_account.SerializeToString()

    zero_account = Account()
    serialized_zero_account = zero_account.SerializeToString()

    is_economy_enabled_setting = Setting()
    is_economy_enabled_setting.entries.add(key='remme.economy_enabled',
                                           value='false')
    serialized_is_economy_enabled_setting = is_economy_enabled_setting.SerializeToString(
    )

    mock_context = StubContext(inputs=INPUTS,
                               outputs=OUTPUTS,
                               initial_state={
                                   SENDER_ADDRESS: serialized_sender_account,
                                   IS_NODE_ECONOMY_ENABLED_ADDRESS:
                                   serialized_is_economy_enabled_setting,
                                   ZERO_ADDRESS: serialized_zero_account,
                               })

    expected_public_key_storage = PubKeyStorage()
    expected_public_key_storage.owner = SENDER_PUBLIC_KEY
    expected_public_key_storage.payload.CopyFrom(new_public_key_payload)
    expected_public_key_storage.is_revoked = False
    expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString(
    )

    expected_sender_account = Account()
    expected_sender_account.pub_keys.append(
        RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY)
    expected_sender_account.pub_keys.append(
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY)
    expected_serialized_sender_account = expected_sender_account.SerializeToString(
    )

    expected_zero_account = Account()
    expected_serialized_zero_account = expected_zero_account.SerializeToString(
    )

    expected_state = {
        SENDER_ADDRESS: expected_serialized_sender_account,
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY:
        expected_serialized_public_key_storage,
        ZERO_ADDRESS: expected_serialized_zero_account,
    }

    PubKeyHandler().apply(transaction=transaction_request,
                          context=mock_context)

    state_as_list = mock_context.get_state(addresses=[
        SENDER_ADDRESS,
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY,
        ZERO_ADDRESS,
    ])

    state_as_dict = {entry.address: entry.data for entry in state_as_list}

    assert expected_state == state_as_dict
Example #14
0
    def _store_public_key_for_other(self, context, signer_pubkey, transaction_payload):
        """
        Store public key for other account.

        The transaction for account which want to pay for other account public keys storing.

        A first account -> send payload -> A second account -> send transaction with first account's public key,
        but sign and pay for storing on own -> Remme-core.

        So Remme core charges tokens from a second account, but store a first account's public key.
        Public key owner here is a first account.

        Arguments:
            context (sawtooth_sdk.processor.context): context to store updated state (blockchain data).
            signer_pubkey: transaction sender public key.
            transaction_payload (pub_key_pb2.NewPubKeyStoreAndPayPayload): payload for storing public key for other.
        """
        new_public_key_payload = transaction_payload.pub_key_payload

        owner_public_key_as_bytes = transaction_payload.owner_public_key
        owner_public_key_as_hex = owner_public_key_as_bytes.hex()

        owner_secp256k1_public_key = Secp256k1PublicKey.from_hex(owner_public_key_as_hex)

        is_owner_public_key_payload_signature_valid = Secp256k1Context().verify(
            signature=transaction_payload.signature_by_owner.hex(),
            message=new_public_key_payload.SerializeToString(),
            public_key=owner_secp256k1_public_key,
        )
        if not is_owner_public_key_payload_signature_valid:
            raise InvalidTransaction('Public key owner\'s signature is invalid.')

        processor = self._get_public_key_processor(transaction_payload=transaction_payload.pub_key_payload)

        if not processor.verify():
            raise InvalidTransaction('Payed public key has invalid signature.')

        public_key = processor.get_public_key()
        public_key_to_store_address = self.make_address_from_data(public_key)

        public_key_to_store_owner_address = AccountHandler().make_address_from_data(owner_public_key_as_hex)
        payer_for_storing_address = AccountHandler().make_address_from_data(signer_pubkey)

        public_key_information, public_key_to_store_owner_account, payer_for_storing_account = get_multiple_data(context, [
            (public_key_to_store_address, PubKeyStorage),
            (public_key_to_store_owner_address, Account),
            (payer_for_storing_address, Account),
        ])

        if public_key_information:
            raise InvalidTransaction('This public key is already registered.')

        if public_key_to_store_owner_account is None:
            public_key_to_store_owner_account = Account()

        if payer_for_storing_account is None:
            payer_for_storing_account = Account()

        if not self._is_public_key_validity_exceeded(
            valid_from=new_public_key_payload.valid_from,
            valid_to=new_public_key_payload.valid_to,
        ):
            raise InvalidTransaction('The public key validity exceeds the maximum value.')

        public_key_information = PubKeyStorage()
        public_key_information.owner = owner_public_key_as_hex
        public_key_information.payload.CopyFrom(new_public_key_payload)
        public_key_information.is_revoked = False

        state = {
            public_key_to_store_owner_address: public_key_to_store_owner_account,
            payer_for_storing_address: payer_for_storing_account,
            public_key_to_store_address: public_key_information,
        }

        charging_state = self._charge_for_storing(context=context, address_from=payer_for_storing_address)
        if charging_state is not None:
            state.update(charging_state)

        public_key_to_store_owner_account = self._store_public_key_to_account(
            public_key_to_store_address=public_key_to_store_address,
            public_key_to_store_owner_account=public_key_to_store_owner_account,
        )

        state.update({
            public_key_to_store_owner_address: public_key_to_store_owner_account,
        })

        return state
Example #15
0
    def _store_pub_key(self, context, signer_pubkey, transaction_payload):
        """
        Store public key to the blockchain.

        Flow on client:
        1. Create private and public key (for instance, RSA).
        2. Create random data and sign it with private key to allows node verify signature,
            so ensure the address sent transaction is a real owner of public key.
        3. Send public key, signature, and other information to the node.

        Node does checks: if public key already exists in the blockchain, try to deserialize public key,
        try to verify signature, if validity exceeds.

        If transaction successfully passed checks, node charges fixed tokens price for storing
        public keys (if node economy is enabled) and link public key to the account (address).

        References:
            - https://docs.remme.io/remme-core/docs/family-pub-key.html
            - https://github.com/Remmeauth/remme-client-python/blob/develop/remme/remme_public_key_storage.py
        """
        processor = self._get_public_key_processor(transaction_payload=transaction_payload)

        if not processor.verify():
            raise InvalidTransaction('Invalid signature')

        public_key = processor.get_public_key()

        public_key_to_store_address = self.make_address_from_data(public_key)
        sender_account_address = AccountHandler().make_address_from_data(signer_pubkey)

        public_key_information, sender_account = get_multiple_data(context, [
            (public_key_to_store_address, PubKeyStorage),
            (sender_account_address, Account),
        ])
        if public_key_information:
            raise InvalidTransaction('This public key is already registered.')

        if not sender_account:
            sender_account = Account()

        if not self._is_public_key_validity_exceeded(
            valid_from=transaction_payload.valid_from,
            valid_to=transaction_payload.valid_to,
        ):
            raise InvalidTransaction('The public key validity exceeds the maximum value.')

        public_key_information = PubKeyStorage()
        public_key_information.owner = signer_pubkey
        public_key_information.payload.CopyFrom(transaction_payload)
        public_key_information.is_revoked = False

        state = {
            sender_account_address: sender_account,
            public_key_to_store_address: public_key_information,
        }

        charging_state = self._charge_for_storing(context=context, address_from=sender_account_address)
        if charging_state is not None:
            state.update(charging_state)
            sender_account = state.get(sender_account_address)

        sender_account = self._store_public_key_to_account(
            public_key_to_store_address=public_key_to_store_address,
            public_key_to_store_owner_account=sender_account,
        )

        state.update({
            sender_account_address: sender_account,
        })

        return state
def test_store_rsa_public_key_no_owner_account():
    """
    Case: send transaction request, to store certificate public key (RSA) for other, when owner account does not exist.
    Expect: public key information is stored to blockchain linked to the newly created owner account's address.
    """
    new_public_key_payload = generate_rsa_payload(key=CERTIFICATE_PUBLIC_KEY)
    serialized_new_public_key_payload = new_public_key_payload.SerializeToString()

    private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY)
    signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key)

    new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload(
        pub_key_payload=new_public_key_payload,
        owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY),
        signature_by_owner=bytes.fromhex(signature_by_owner),
    )

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.STORE_AND_PAY
    transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = generate_header(
        serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY,
    )

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header),
    )

    payer_account = Account()
    payer_account.balance = PAYER_INITIAL_BALANCE
    serialized_payer_account = payer_account.SerializeToString()

    zero_account = Account()
    zero_account.balance = 0
    serialized_zero_account = zero_account.SerializeToString()

    mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={
        PAYER_ADDRESS: serialized_payer_account,
        ZERO_ADDRESS: serialized_zero_account,
    })

    expected_public_key_storage = PubKeyStorage()
    expected_public_key_storage.owner = OWNER_PUBLIC_KEY
    expected_public_key_storage.payload.CopyFrom(new_public_key_payload)
    expected_public_key_storage.is_revoked = False
    expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString()

    expected_payer_account = Account()
    expected_payer_account.balance = PAYER_INITIAL_BALANCE - PUB_KEY_STORE_PRICE
    serialized_expected_payer_account = expected_payer_account.SerializeToString()

    expected_owner_account = Account()
    expected_owner_account.pub_keys.append(ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY)
    serialized_expected_owner_account = expected_owner_account.SerializeToString()

    expected_zero_account = Account()
    expected_zero_account.balance = 0 + PUB_KEY_STORE_PRICE
    expected_serialized_zero_account = expected_zero_account.SerializeToString()

    expected_state = {
        OWNER_ADDRESS: serialized_expected_owner_account,
        PAYER_ADDRESS: serialized_expected_payer_account,
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: expected_serialized_public_key_storage,
        ZERO_ADDRESS: expected_serialized_zero_account,
    }

    PubKeyHandler().apply(transaction=transaction_request, context=mock_context)

    state_as_list = mock_context.get_state(addresses=[
        OWNER_ADDRESS, PAYER_ADDRESS, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY, ZERO_ADDRESS,
    ])

    state_as_dict = {entry.address: entry.data for entry in state_as_list}

    assert expected_state == state_as_dict
def test_store_public_key_for_other_economy_is_not_enabled():
    """
    Case: send transaction request, to store certificate public key for other, when economy isn't enabled.
    Expect: public key information is stored to blockchain linked to owner address. Owner hasn't paid for storing.
    """
    new_public_key_payload = generate_rsa_payload(key=CERTIFICATE_PUBLIC_KEY)
    serialized_new_public_key_payload = new_public_key_payload.SerializeToString()

    private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY)
    signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key)

    new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload(
        pub_key_payload=new_public_key_payload,
        owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY),
        signature_by_owner=bytes.fromhex(signature_by_owner),
    )

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.STORE_AND_PAY
    transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = generate_header(
        serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY,
    )

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header),
    )

    payer_account = Account()
    payer_account.balance = PAYER_INITIAL_BALANCE
    serialized_payer_account = payer_account.SerializeToString()

    owner_account = Account()
    owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS)
    serialized_owner_account = owner_account.SerializeToString()

    zero_account = Account()
    zero_account.balance = 0
    serialized_zero_account = zero_account.SerializeToString()

    is_economy_enabled_setting = Setting()
    is_economy_enabled_setting.entries.add(key='remme.economy_enabled', value='false')
    serialized_is_economy_enabled_setting = is_economy_enabled_setting.SerializeToString()

    mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={
        OWNER_ADDRESS: serialized_owner_account,
        PAYER_ADDRESS: serialized_payer_account,
        ZERO_ADDRESS: serialized_zero_account,
        IS_NODE_ECONOMY_ENABLED_ADDRESS: serialized_is_economy_enabled_setting,
    })

    expected_public_key_storage = PubKeyStorage()
    expected_public_key_storage.owner = OWNER_PUBLIC_KEY
    expected_public_key_storage.payload.CopyFrom(new_public_key_payload)
    expected_public_key_storage.is_revoked = False
    expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString()

    expected_payer_account = Account()
    expected_payer_account.balance = PAYER_INITIAL_BALANCE
    serialized_expected_payer_account = expected_payer_account.SerializeToString()

    expected_owner_account = Account()
    expected_owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS)
    expected_owner_account.pub_keys.append(ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY)
    serialized_expected_owner_account = expected_owner_account.SerializeToString()

    expected_zero_account = Account()
    expected_zero_account.balance = 0
    expected_serialized_zero_account = expected_zero_account.SerializeToString()

    expected_state = {
        OWNER_ADDRESS: serialized_expected_owner_account,
        PAYER_ADDRESS: serialized_expected_payer_account,
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: expected_serialized_public_key_storage,
        ZERO_ADDRESS: expected_serialized_zero_account,
    }

    PubKeyHandler().apply(transaction=transaction_request, context=mock_context)

    state_as_list = mock_context.get_state(addresses=[
        OWNER_ADDRESS, PAYER_ADDRESS, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY, ZERO_ADDRESS,
    ])

    state_as_dict = {entry.address: entry.data for entry in state_as_list}

    assert expected_state == state_as_dict