From bda1fb770804f424b9bfb93a7250330fd20d1f98 Mon Sep 17 00:00:00 2001 From: Vanshdeep Singh Date: Wed, 5 Sep 2018 12:21:49 +0200 Subject: [PATCH] Problem: Public key type not verfied during validation Solution: Validate public key type and write correspoding tests --- bigchaindb/commands/bigchaindb.py | 2 +- bigchaindb/common/exceptions.py | 4 ++++ .../upsert_validator/validator_election.py | 5 +++- .../upsert_validator/validator_utils.py | 24 +++++++++++++++++++ tests/commands/test_commands.py | 4 +++- tests/conftest.py | 2 +- tests/tendermint/test_core.py | 4 ++-- .../test_validator_election.py | 13 ++++++++++ .../test_validator_election_vote.py | 6 ++--- 9 files changed, 55 insertions(+), 9 deletions(-) diff --git a/bigchaindb/commands/bigchaindb.py b/bigchaindb/commands/bigchaindb.py index 9f2cd7ad..5f23953b 100644 --- a/bigchaindb/commands/bigchaindb.py +++ b/bigchaindb/commands/bigchaindb.py @@ -125,7 +125,7 @@ def run_upsert_validator_new(args, bigchain): new_validator = { 'public_key': {'value': public_key_from_base64(args.public_key), - 'type': 'ed25519-base58'}, + 'type': 'ed25519-base16'}, 'power': args.power, 'node_id': args.node_id } diff --git a/bigchaindb/common/exceptions.py b/bigchaindb/common/exceptions.py index adaff5c6..b2fc970d 100644 --- a/bigchaindb/common/exceptions.py +++ b/bigchaindb/common/exceptions.py @@ -112,3 +112,7 @@ class UnequalValidatorSet(ValidationError): class InvalidPowerChange(ValidationError): """Raised if proposed power change in validator set is >=1/3 total power""" + + +class InvalidPublicKey(ValidationError): + """Raised if proposed power change in validator set is >=1/3 total power""" diff --git a/bigchaindb/upsert_validator/validator_election.py b/bigchaindb/upsert_validator/validator_election.py index 11139d8f..0bf052ad 100644 --- a/bigchaindb/upsert_validator/validator_election.py +++ b/bigchaindb/upsert_validator/validator_election.py @@ -19,7 +19,9 @@ from bigchaindb.common.schema import (_validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_CREATE) from . import ValidatorElectionVote -from .validator_utils import (new_validator_set, encode_validator) +from .validator_utils import (new_validator_set, + encode_validator, + validate_asset_public_key) class ValidatorElection(Transaction): @@ -155,6 +157,7 @@ class ValidatorElection(Transaction): _validate_schema(TX_SCHEMA_COMMON, tx) _validate_schema(TX_SCHEMA_CREATE, tx) _validate_schema(TX_SCHEMA_VALIDATOR_ELECTION, tx) + validate_asset_public_key(tx['asset']['data']['public_key']) @classmethod def create(cls, tx_signers, recipients, metadata=None, asset=None): diff --git a/bigchaindb/upsert_validator/validator_utils.py b/bigchaindb/upsert_validator/validator_utils.py index 47f96b3d..a2849c64 100644 --- a/bigchaindb/upsert_validator/validator_utils.py +++ b/bigchaindb/upsert_validator/validator_utils.py @@ -1,8 +1,11 @@ import codecs +import base64 +import binascii from abci.types_pb2 import (Validator, PubKey) from bigchaindb.tendermint_utils import public_key_to_base64 +from bigchaindb.common.exceptions import InvalidPublicKey def encode_validator(v): @@ -35,3 +38,24 @@ def new_validator_set(validators, updates): new_validators_dict = {**validators_dict, **updates_dict} return list(new_validators_dict.values()) + + +def validate_asset_public_key(pk): + pk_binary = pk['value'].encode('utf-8') + encoding = pk['type'] + decoder = base64.b64decode + + if encoding == 'ed25519-base16': + decoder = base64.b16decode + elif encoding == 'ed25519-base32': + decoder = base64.b32decode + elif encoding == 'ed25519-base64': + decoder = base64.b64decode + + try: + pk_decoded = decoder(pk_binary) + if len(pk_decoded) != 32: + raise InvalidPublicKey('Public key should be of size 32 bytes') + + except binascii.Error as e: + raise InvalidPublicKey('Invalid `type` specified for public key `value`') diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 957fe85c..b530fd4c 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -352,7 +352,7 @@ def test_upsert_validator_new_with_tendermint(b, priv_validator_path, user_sk, v from bigchaindb.commands.bigchaindb import run_upsert_validator_new new_args = Namespace(action='new', - public_key='8eJ8q9ZQpReWyQT5aFCiwtZ5wDZC4eDnCen88p3tQ6ie', + public_key='HHG0IQRybpT6nJMIWWFWhMczCLHt6xcm7eP52GnGuPY=', power=1, node_id='unique_node_id_for_test_upsert_validator_new_with_tendermint', sk=priv_validator_path, @@ -429,6 +429,7 @@ def test_upsert_validator_new_election_invalid_power(caplog, b, priv_validator_p assert caplog.records[0].msg.__class__ == InvalidPowerChange +@pytest.mark.google @pytest.mark.abci def test_upsert_validator_approve_with_tendermint(b, priv_validator_path, user_sk, validators): from bigchaindb.commands.bigchaindb import (run_upsert_validator_new, @@ -443,6 +444,7 @@ def test_upsert_validator_approve_with_tendermint(b, priv_validator_path, user_s config={}) election_id = run_upsert_validator_new(new_args, b) + assert election_id args = Namespace(action='approve', election_id=election_id, diff --git a/tests/conftest.py b/tests/conftest.py index 6ab19509..9ef51e21 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -687,6 +687,6 @@ def new_validator(): node_id = 'fake_node_id' return {'public_key': {'value': public_key, - 'type': 'ed25519-base58'}, + 'type': 'ed25519-base16'}, 'power': power, 'node_id': node_id} diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 8617d849..c98ee1ea 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -419,10 +419,10 @@ def test_new_validator_set(b): 'value': 'FxjS2/8AFYoIUqF6AcePTc87qOT7e4WGgH+sGCpTUDQ='}, 'voting_power': 10} node1_new_power = {'public_key': {'value': '1718D2DBFF00158A0852A17A01C78F4DCF3BA8E4FB7B8586807FAC182A535034', - 'type': 'ed25519-base58'}, + 'type': 'ed25519-base16'}, 'power': 20} node2 = {'public_key': {'value': '1888A353B181715CA2554701D06C1665BC42C5D936C55EA9C5DBCBDB8B3F02A3', - 'type': 'ed25519-base58'}, + 'type': 'ed25519-base16'}, 'power': 10} validators = [node1] diff --git a/tests/upsert_validator/test_validator_election.py b/tests/upsert_validator/test_validator_election.py index 596c245f..4c3849e4 100644 --- a/tests/upsert_validator/test_validator_election.py +++ b/tests/upsert_validator/test_validator_election.py @@ -24,6 +24,19 @@ def test_upsert_validator_valid_election(b_mock, new_validator, node_key): assert election.validate(b_mock) +def test_upsert_validator_invalid_election_public_key(b_mock, new_validator, node_key): + from bigchaindb.common.exceptions import InvalidPublicKey + + for iv in ['ed25519-base32', 'ed25519-base64']: + new_validator['public_key']['type'] = iv + voters = ValidatorElection.recipients(b_mock) + + with pytest.raises(InvalidPublicKey): + ValidatorElection.generate([node_key.public_key], + voters, + new_validator, None).sign([node_key.private_key]) + + def test_upsert_validator_invalid_power_election(b_mock, new_validator, node_key): voters = ValidatorElection.recipients(b_mock) new_validator['power'] = 30 diff --git a/tests/upsert_validator/test_validator_election_vote.py b/tests/upsert_validator/test_validator_election_vote.py index 87088074..4504977a 100644 --- a/tests/upsert_validator/test_validator_election_vote.py +++ b/tests/upsert_validator/test_validator_election_vote.py @@ -238,7 +238,7 @@ def test_upsert_validator(b, node_key, node_keys, ed25519_node_keys): power = 1 public_key = '9B3119650DF82B9A5D8A12E38953EA47475C09F0C48A4E6A0ECE182944B24403' public_key64 = public_key_to_base64(public_key) - new_validator = {'public_key': {'value': public_key, 'type': 'ed25519-base58'}, + new_validator = {'public_key': {'value': public_key, 'type': 'ed25519-base16'}, 'node_id': 'some_node_id', 'power': power} @@ -280,7 +280,7 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys): power = 1 public_key = '9B3119650DF82B9A5D8A12E38953EA47475C09F0C48A4E6A0ECE182944B24403' public_key64 = public_key_to_base64(public_key) - new_validator = {'public_key': {'value': public_key, 'type': 'ed25519-base58'}, + new_validator = {'public_key': {'value': public_key, 'type': 'ed25519-base16'}, 'node_id': 'some_node_id', 'power': power} voters = ValidatorElection.recipients(b) @@ -315,7 +315,7 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys): # remove validator power = 0 - new_validator = {'public_key': {'value': public_key, 'type': 'ed25519-base58'}, + new_validator = {'public_key': {'value': public_key, 'type': 'ed25519-base16'}, 'node_id': 'some_node_id', 'power': power} voters = ValidatorElection.recipients(b)