Skip to content

Commit

Permalink
go/consensus: Hash user-controlled storage key elements
Browse files Browse the repository at this point in the history
  • Loading branch information
kostko committed May 22, 2020
1 parent e26d689 commit d8de6b7
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 53 deletions.
1 change: 1 addition & 0 deletions .changelog/2929.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go/consensus: Hash user-controlled storage key elements
6 changes: 6 additions & 0 deletions go/common/crypto/signature/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/oasislabs/ed25519"

"github.com/oasislabs/oasis-core/go/common/cbor"
"github.com/oasislabs/oasis-core/go/common/crypto/hash"
"github.com/oasislabs/oasis-core/go/common/pem"
"github.com/oasislabs/oasis-core/go/common/prettyprint"
)
Expand Down Expand Up @@ -210,6 +211,11 @@ func (k *PublicKey) LoadPEM(fn string, signer Signer) error {
return nil
}

// Hash returns a cryptographic hash of the public key.
func (k PublicKey) Hash() hash.Hash {
return hash.NewFromBytes(k[:])
}

func (k PublicKey) isBlacklisted() bool {
_, isBlacklisted := blacklistedPublicKeys.Load(k)
return isBlacklisted
Expand Down
4 changes: 4 additions & 0 deletions go/consensus/tendermint/abci/timer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"time"

"github.com/oasislabs/oasis-core/go/common/crypto/hash"
"github.com/oasislabs/oasis-core/go/common/keyformat"
"github.com/oasislabs/oasis-core/go/common/logging"
"github.com/oasislabs/oasis-core/go/consensus/tendermint/api"
Expand Down Expand Up @@ -68,6 +69,9 @@ type Timer struct {
func NewTimer(ctx *api.Context, app Application, kind uint8, id []byte, data []byte) *Timer {
if data == nil {
data = []byte{}
} else {
h := hash.NewFromBytes(data)
data = h[:]
}

state := &timerState{
Expand Down
2 changes: 1 addition & 1 deletion go/consensus/tendermint/apps/keymanager/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var (
// statusKeyFmt is the key manager status key format.
//
// Value is CBOR-serialized key manager status.
statusKeyFmt = keyformat.New(0x70, &common.Namespace{})
statusKeyFmt = keyformat.New(0x70, keyformat.H(&common.Namespace{}))
)

// ImmutableState is the immutable key manager state wrapper.
Expand Down
18 changes: 12 additions & 6 deletions go/consensus/tendermint/apps/registry/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/tendermint/tendermint/abci/types"

"github.com/oasislabs/oasis-core/go/common/cbor"
"github.com/oasislabs/oasis-core/go/common/crypto/signature"
"github.com/oasislabs/oasis-core/go/common/node"
abciAPI "github.com/oasislabs/oasis-core/go/consensus/tendermint/api"
registryState "github.com/oasislabs/oasis-core/go/consensus/tendermint/apps/registry/state"
Expand Down Expand Up @@ -147,20 +148,25 @@ func (rq *registryQuerier) Genesis(ctx context.Context) (*registry.Genesis, erro
// BUG: If the debonding period will apply to other nodes,
// then we need to basically persist everything.
validatorNodes := make([]*node.MultiSignedNode, 0)
nodeStatuses := make(map[signature.PublicKey]*registry.NodeStatus)
for _, sn := range signedNodes {
var n node.Node
if err = cbor.Unmarshal(sn.Blob, &n); err != nil {
return nil, err
}

if n.HasRoles(node.RoleValidator) {
validatorNodes = append(validatorNodes, sn)
if !n.HasRoles(node.RoleValidator) {
continue
}
}

nodeStatuses, err := rq.state.NodeStatuses(ctx)
if err != nil {
return nil, err
var status *registry.NodeStatus
status, err = rq.state.NodeStatus(ctx, n.ID)
if err != nil {
return nil, err
}

validatorNodes = append(validatorNodes, sn)
nodeStatuses[n.ID] = status
}

params, err := rq.state.ConsensusParameters(ctx)
Expand Down
55 changes: 17 additions & 38 deletions go/consensus/tendermint/apps/registry/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@ var (
// signedEntityKeyFmt is the key format used for signed entities.
//
// Value is CBOR-serialized signed entity.
signedEntityKeyFmt = keyformat.New(0x10, &signature.PublicKey{})
signedEntityKeyFmt = keyformat.New(0x10, keyformat.H(&signature.PublicKey{}))
// signedNodeKeyFmt is the key format used for signed nodes.
//
// Value is CBOR-serialized signed node.
signedNodeKeyFmt = keyformat.New(0x11, &signature.PublicKey{})
signedNodeKeyFmt = keyformat.New(0x11, keyformat.H(&signature.PublicKey{}))
// signedNodeByEntityKeyFmt is the key format used for signed node by entity
// index.
//
// Value is empty.
signedNodeByEntityKeyFmt = keyformat.New(0x12, &signature.PublicKey{}, &signature.PublicKey{})
signedNodeByEntityKeyFmt = keyformat.New(0x12, keyformat.H(&signature.PublicKey{}), keyformat.H(&signature.PublicKey{}))
// signedRuntimeKeyFmt is the key format used for signed runtimes.
//
// Value is CBOR-serialized signed runtime.
signedRuntimeKeyFmt = keyformat.New(0x13, &common.Namespace{})
signedRuntimeKeyFmt = keyformat.New(0x13, keyformat.H(&common.Namespace{}))
// nodeByConsAddressKeyFmt is the key format used for the consensus address to
// node public key mapping.
//
Expand All @@ -49,25 +49,26 @@ var (
// nodeStatusKeyFmt is the key format used for node statuses.
//
// Value is CBOR-serialized node status.
nodeStatusKeyFmt = keyformat.New(0x15, &signature.PublicKey{})
nodeStatusKeyFmt = keyformat.New(0x15, keyformat.H(&signature.PublicKey{}))
// parametersKeyFmt is the key format used for consensus parameters.
//
// Value is CBOR-serialized registry.ConsensusParameters.
parametersKeyFmt = keyformat.New(0x16)
// keyMapKeyFmt is the key format used for key-to-node-id map.
// This stores the consensus and P2P to Node ID mappings.
//
// This stores the consensus, P2P and TLS public keys to node ID mappings.
//
// Value is binary signature.PublicKey (node ID).
keyMapKeyFmt = keyformat.New(0x17, &signature.PublicKey{})
keyMapKeyFmt = keyformat.New(0x17, keyformat.H(&signature.PublicKey{}))
// suspendedRuntimeKeyFmt is the key format used for suspended runtimes.
//
// Value is CBOR-serialized signed runtime.
suspendedRuntimeKeyFmt = keyformat.New(0x18, &common.Namespace{})
suspendedRuntimeKeyFmt = keyformat.New(0x18, keyformat.H(&common.Namespace{}))
// signedRuntimeByEntityKeyFmt is the key format used for signed runtime by entity
// index.
//
// Value is empty.
signedRuntimeByEntityKeyFmt = keyformat.New(0x19, &signature.PublicKey{}, &common.Namespace{})
signedRuntimeByEntityKeyFmt = keyformat.New(0x19, keyformat.H(&signature.PublicKey{}), keyformat.H(&common.Namespace{}))
)

// ImmutableState is the immutable registry state wrapper.
Expand Down Expand Up @@ -221,6 +222,7 @@ func (s *ImmutableState) Nodes(ctx context.Context) ([]*node.Node, error) {
if it.Err() != nil {
return nil, abciAPI.UnavailableStateError(it.Err())
}
registry.SortNodeList(nodes)
return nodes, nil
}

Expand Down Expand Up @@ -441,39 +443,15 @@ func (s *ImmutableState) NodeStatus(ctx context.Context, id signature.PublicKey)
return &status, nil
}

// NodeStatuses returns all of the node statuses.
func (s *ImmutableState) NodeStatuses(ctx context.Context) (map[signature.PublicKey]*registry.NodeStatus, error) {
it := s.is.NewIterator(ctx)
defer it.Close()

statuses := make(map[signature.PublicKey]*registry.NodeStatus)
for it.Seek(nodeStatusKeyFmt.Encode()); it.Valid(); it.Next() {
var nodeID signature.PublicKey
if !nodeStatusKeyFmt.Decode(it.Key(), &nodeID) {
break
}

var status registry.NodeStatus
if err := cbor.Unmarshal(it.Value(), &status); err != nil {
return nil, abciAPI.UnavailableStateError(err)
}

statuses[nodeID] = &status
}
if it.Err() != nil {
return nil, abciAPI.UnavailableStateError(it.Err())
}
return statuses, nil
}

// HasEntityNodes checks whether an entity has any registered nodes.
func (s *ImmutableState) HasEntityNodes(ctx context.Context, id signature.PublicKey) (bool, error) {
it := s.is.NewIterator(ctx)
defer it.Close()

hID := keyformat.PreHashed(id.Hash())
if it.Seek(signedNodeByEntityKeyFmt.Encode(&id)); it.Valid() {
var entityID signature.PublicKey
if !signedNodeByEntityKeyFmt.Decode(it.Key(), &entityID) || !entityID.Equal(id) {
var hEntityID keyformat.PreHashed
if !signedNodeByEntityKeyFmt.Decode(it.Key(), &hEntityID) || !hEntityID.Equal(&hID) {
return false, nil
}
return true, nil
Expand All @@ -486,9 +464,10 @@ func (s *ImmutableState) HasEntityRuntimes(ctx context.Context, id signature.Pub
it := s.is.NewIterator(ctx)
defer it.Close()

hID := keyformat.PreHashed(id.Hash())
if it.Seek(signedRuntimeByEntityKeyFmt.Encode(&id)); it.Valid() {
var entityID signature.PublicKey
if !signedRuntimeByEntityKeyFmt.Decode(it.Key(), &entityID) || !entityID.Equal(id) {
var hEntityID keyformat.PreHashed
if !signedRuntimeByEntityKeyFmt.Decode(it.Key(), &hEntityID) || !hEntityID.Equal(&hID) {
return false, nil
}
return true, nil
Expand Down
2 changes: 1 addition & 1 deletion go/consensus/tendermint/apps/roothash/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var (
// runtimeKeyFmt is the key format used for per-runtime roothash state.
//
// Value is CBOR-serialized runtime state.
runtimeKeyFmt = keyformat.New(0x20, &common.Namespace{})
runtimeKeyFmt = keyformat.New(0x20, keyformat.H(&common.Namespace{}))
// parametersKeyFmt is the key format used for consensus parameters.
//
// Value is CBOR-serialized roothash.ConsensusParameters.
Expand Down
14 changes: 7 additions & 7 deletions go/consensus/tendermint/apps/scheduler/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var (
// committeeKeyFmt is the key format used for committees.
//
// Value is CBOR-serialized committee.
committeeKeyFmt = keyformat.New(0x60, uint8(0), &common.Namespace{})
committeeKeyFmt = keyformat.New(0x60, uint8(0), keyformat.H(&common.Namespace{}))
// validatorsCurrentKeyFmt is the key format used for the current set of
// validators.
//
Expand Down Expand Up @@ -64,14 +64,14 @@ func (s *ImmutableState) AllCommittees(ctx context.Context) ([]*api.Committee, e
var committees []*api.Committee
for it.Seek(committeeKeyFmt.Encode()); it.Valid(); it.Next() {
var k uint8
var runtimeID common.Namespace
if !committeeKeyFmt.Decode(it.Key(), &k, &runtimeID) {
var hRuntimeID keyformat.PreHashed
if !committeeKeyFmt.Decode(it.Key(), &k, &hRuntimeID) {
break
}

var c api.Committee
if err := cbor.Unmarshal(it.Value(), &c); err != nil {
err = fmt.Errorf("malformed committee %s (kind %d): %w", runtimeID, k, err)
err = fmt.Errorf("malformed committee %s (kind %d): %w", hRuntimeID, k, err)
return nil, abciAPI.UnavailableStateError(err)
}

Expand All @@ -92,14 +92,14 @@ func (s *ImmutableState) KindsCommittees(ctx context.Context, kinds []api.Commit
for _, kind := range kinds {
for it.Seek(committeeKeyFmt.Encode(uint8(kind))); it.Valid(); it.Next() {
var k uint8
var runtimeID common.Namespace
if !committeeKeyFmt.Decode(it.Key(), &k, &runtimeID) || k != uint8(kind) {
var hRuntimeID keyformat.PreHashed
if !committeeKeyFmt.Decode(it.Key(), &k, &hRuntimeID) || k != uint8(kind) {
break
}

var c api.Committee
if err := cbor.Unmarshal(it.Value(), &c); err != nil {
err = fmt.Errorf("malformed committee %s (kind %d): %w", runtimeID, k, err)
err = fmt.Errorf("malformed committee %s (kind %d): %w", hRuntimeID, k, err)
return nil, abciAPI.UnavailableStateError(err)
}

Expand Down

0 comments on commit d8de6b7

Please sign in to comment.