Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multikey peer authentication sender integration #4394

Merged
merged 13 commits into from
Aug 31, 2022
Merged
3 changes: 3 additions & 0 deletions heartbeat/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,6 @@ var ErrNilEnableEpochsHandler = errors.New("nil enable epochs handler")

// ErrShouldSkipValidator signals that the validator should be skipped
var ErrShouldSkipValidator = errors.New("validator should be skipped")

// ErrNilKeysHolder signals that a nil keys holder has been provided
var ErrNilKeysHolder = errors.New("nil keys holder")
21 changes: 21 additions & 0 deletions heartbeat/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import (
// P2PMessenger defines a subset of the p2p.Messenger interface
type P2PMessenger interface {
Broadcast(topic string, buff []byte)
BroadcastWithSk(topic string, buff []byte, pid core.PeerID, skBytes []byte)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we raname this into BroadcastUsingSk (or BroadcastSigningWithSk)? I know that the naming convention follows libp2p's PublishWithSk but I find it very misleading, I really thought we were sending the sk over the wire. (SendableData having an SK member doesn't help either :)) @iulianpascalau thoughts?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, let's rename to BroadcastWithPrivateKey

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushed

ID() core.PeerID
Sign(payload []byte) ([]byte, error)
SignWithPrivateKey(skBytes []byte, payload []byte) ([]byte, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also follow the naming convention above (either abbreviation of secret key, or private key)

IsInterfaceNil() bool
}

Expand Down Expand Up @@ -120,3 +122,22 @@ type NodesCoordinator interface {
GetValidatorWithPublicKey(publicKey []byte) (validator nodesCoordinator.Validator, shardId uint32, err error)
IsInterfaceNil() bool
}

// KeysHolder defines the operations of an entity that holds virtual identities for a node
type KeysHolder interface {
AddVirtualPeer(privateKeyBytes []byte) error
GetPrivateKey(pkBytes []byte) (crypto.PrivateKey, error)
GetP2PIdentity(pkBytes []byte) ([]byte, core.PeerID, error)
GetMachineID(pkBytes []byte) (string, error)
IncrementRoundsWithoutReceivedMessages(pkBytes []byte) error
ResetRoundsWithoutReceivedMessages(pkBytes []byte) error
GetManagedKeysByCurrentNode() map[string]crypto.PrivateKey
IsKeyManagedByCurrentNode(pkBytes []byte) bool
IsKeyRegistered(pkBytes []byte) bool
IsPidManagedByCurrentNode(pid core.PeerID) bool
IsKeyValidator(pkBytes []byte) bool
SetValidatorState(pkBytes []byte, state bool)
GetNextPeerAuthenticationTime(pkBytes []byte) (time.Time, error)
SetNextPeerAuthenticationTime(pkBytes []byte, nextTime time.Time)
IsInterfaceNil() bool
}
26 changes: 22 additions & 4 deletions heartbeat/mock/messengerStub.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import (

// MessengerStub -
type MessengerStub struct {
IDCalled func() core.PeerID
BroadcastCalled func(topic string, buff []byte)
SignCalled func(payload []byte) ([]byte, error)
VerifyCalled func(payload []byte, pid core.PeerID, signature []byte) error
IDCalled func() core.PeerID
BroadcastCalled func(topic string, buff []byte)
BroadcastWithSkCalled func(topic string, buff []byte, pid core.PeerID, skBytes []byte)
SignCalled func(payload []byte) ([]byte, error)
SignWithPrivateKeyCalled func(skBytes []byte, payload []byte) ([]byte, error)
VerifyCalled func(payload []byte, pid core.PeerID, signature []byte) error
}

// ID -
Expand All @@ -28,6 +30,13 @@ func (ms *MessengerStub) Broadcast(topic string, buff []byte) {
}
}

// BroadcastWithSk -
func (ms *MessengerStub) BroadcastWithSk(topic string, buff []byte, pid core.PeerID, skBytes []byte) {
if ms.BroadcastWithSkCalled != nil {
ms.BroadcastWithSkCalled(topic, buff, pid, skBytes)
}
}

// Sign -
func (ms *MessengerStub) Sign(payload []byte) ([]byte, error) {
if ms.SignCalled != nil {
Expand All @@ -37,6 +46,15 @@ func (ms *MessengerStub) Sign(payload []byte) ([]byte, error) {
return make([]byte, 0), nil
}

// SignWithPrivateKey -
func (ms *MessengerStub) SignWithPrivateKey(skBytes []byte, payload []byte) ([]byte, error) {
if ms.SignWithPrivateKeyCalled != nil {
return ms.SignWithPrivateKeyCalled(skBytes, payload)
}

return make([]byte, 0), nil
}

// Verify -
func (ms *MessengerStub) Verify(payload []byte, pid core.PeerID, signature []byte) error {
if ms.VerifyCalled != nil {
Expand Down
93 changes: 93 additions & 0 deletions heartbeat/sender/commonPeerAuthenticationSender.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package sender

import (
"bytes"
"time"

"github.com/ElrondNetwork/elrond-go-core/data/batch"
crypto "github.com/ElrondNetwork/elrond-go-crypto"
"github.com/ElrondNetwork/elrond-go/heartbeat"
)

type commonPeerAuthenticationSender struct {
baseSender
nodesCoordinator heartbeat.NodesCoordinator
peerSignatureHandler crypto.PeerSignatureHandler
hardforkTrigger heartbeat.HardforkTrigger
hardforkTriggerPubKey []byte
}

func (cpas *commonPeerAuthenticationSender) generateMessageBytes(
pkBytes []byte,
privateKey crypto.PrivateKey,
p2pSkBytes []byte,
pidBytes []byte,
) ([]byte, bool, error) {
msg := &heartbeat.PeerAuthentication{
Pid: pidBytes,
Pubkey: pkBytes,
}

hardforkPayload, isTriggered := cpas.getHardforkPayload()
payload := &heartbeat.Payload{
Timestamp: time.Now().Unix(),
HardforkMessage: string(hardforkPayload),
}
payloadBytes, err := cpas.marshaller.Marshal(payload)
if err != nil {
return nil, isTriggered, err
}
msg.Payload = payloadBytes

if p2pSkBytes != nil {
msg.PayloadSignature, err = cpas.messenger.SignWithPrivateKey(p2pSkBytes, payloadBytes)
if err != nil {
return nil, isTriggered, err
}
} else {
msg.PayloadSignature, err = cpas.messenger.Sign(payloadBytes)
if err != nil {
return nil, isTriggered, err
}
}

msg.Signature, err = cpas.peerSignatureHandler.GetPeerSignature(privateKey, msg.Pid)
if err != nil {
return nil, isTriggered, err
}

msgBytes, err := cpas.marshaller.Marshal(msg)
if err != nil {
return nil, isTriggered, err
}

b := &batch.Batch{
Data: make([][]byte, 1),
}
b.Data[0] = msgBytes
data, err := cpas.marshaller.Marshal(b)
if err != nil {
return nil, isTriggered, err
}

return data, isTriggered, nil
}

func (cpas *commonPeerAuthenticationSender) isValidator(pkBytes []byte) bool {
_, _, err := cpas.nodesCoordinator.GetValidatorWithPublicKey(pkBytes)
return err == nil
}

func (cpas *commonPeerAuthenticationSender) isHardforkSource(pkBytes []byte) bool {
return bytes.Equal(pkBytes, cpas.hardforkTriggerPubKey)
}

func (cpas *commonPeerAuthenticationSender) getHardforkPayload() ([]byte, bool) {
payload := make([]byte, 0)
_, isTriggered := cpas.hardforkTrigger.RecordedTriggerMessage()
if isTriggered {
payload = cpas.hardforkTrigger.CreateData()
}

return payload, isTriggered
}