Browse Source

p2p: only allow ed25519 pubkeys when connecting

also, recover from any possible failures in acceptPeers

Refs #4030
pull/4050/head
Anton Kaliaev 5 years ago
parent
commit
fb65d065ae
No known key found for this signature in database GPG Key ID: 7B6881D965918214
4 changed files with 81 additions and 9 deletions
  1. +5
    -0
      crypto/multisig/threshold_pubkey.go
  2. +10
    -9
      p2p/conn/secret_connection.go
  3. +47
    -0
      p2p/conn/secret_connection_test.go
  4. +19
    -0
      p2p/transport.go

+ 5
- 0
crypto/multisig/threshold_pubkey.go View File

@ -21,6 +21,11 @@ func NewPubKeyMultisigThreshold(k int, pubkeys []crypto.PubKey) crypto.PubKey {
if len(pubkeys) < k { if len(pubkeys) < k {
panic("threshold k of n multisignature: len(pubkeys) < k") panic("threshold k of n multisignature: len(pubkeys) < k")
} }
for _, pubkey := range pubkeys {
if pubkey == nil {
panic("nil pubkey")
}
}
return PubKeyMultisigThreshold{uint(k), pubkeys} return PubKeyMultisigThreshold{uint(k), pubkeys}
} }


+ 10
- 9
p2p/conn/secret_connection.go View File

@ -7,21 +7,22 @@ import (
"crypto/sha256" "crypto/sha256"
"crypto/subtle" "crypto/subtle"
"encoding/binary" "encoding/binary"
"errors"
"io" "io"
"math" "math"
"net" "net"
"sync" "sync"
"time" "time"
pool "github.com/libp2p/go-buffer-pool"
"github.com/pkg/errors"
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519" "golang.org/x/crypto/curve25519"
"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/nacl/box" "golang.org/x/crypto/nacl/box"
pool "github.com/libp2p/go-buffer-pool"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
cmn "github.com/tendermint/tendermint/libs/common" cmn "github.com/tendermint/tendermint/libs/common"
"golang.org/x/crypto/hkdf"
) )
// 4 + 1024 == 1028 total frame size // 4 + 1024 == 1028 total frame size
@ -107,11 +108,11 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKey) (*
sendAead, err := chacha20poly1305.New(sendSecret[:]) sendAead, err := chacha20poly1305.New(sendSecret[:])
if err != nil { if err != nil {
return nil, errors.New("Invalid send SecretConnection Key")
return nil, errors.New("invalid send SecretConnection Key")
} }
recvAead, err := chacha20poly1305.New(recvSecret[:]) recvAead, err := chacha20poly1305.New(recvSecret[:])
if err != nil { if err != nil {
return nil, errors.New("Invalid receive SecretConnection Key")
return nil, errors.New("invalid receive SecretConnection Key")
} }
// Construct SecretConnection. // Construct SecretConnection.
sc := &SecretConnection{ sc := &SecretConnection{
@ -134,12 +135,12 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKey) (*
remPubKey, remSignature := authSigMsg.Key, authSigMsg.Sig remPubKey, remSignature := authSigMsg.Key, authSigMsg.Sig
if remPubKey == nil {
return nil, errors.New("peer sent a nil public key")
if _, ok := remPubKey.(ed25519.PubKeyEd25519); !ok {
return nil, errors.Errorf("expected ed25519 pubkey, got %T", remPubKey)
} }
if !remPubKey.VerifyBytes(challenge[:], remSignature) { if !remPubKey.VerifyBytes(challenge[:], remSignature) {
return nil, errors.New("Challenge verification failed")
return nil, errors.New("challenge verification failed")
} }
// We've authorized. // We've authorized.
@ -222,7 +223,7 @@ func (sc *SecretConnection) Read(data []byte) (n int, err error) {
defer pool.Put(frame) defer pool.Put(frame)
_, err = sc.recvAead.Open(frame[:0], sc.recvNonce[:], sealedFrame, nil) _, err = sc.recvAead.Open(frame[:0], sc.recvNonce[:], sealedFrame, nil)
if err != nil { if err != nil {
return n, errors.New("Failed to decrypt SecretConnection")
return n, errors.New("failed to decrypt SecretConnection")
} }
incrNonce(sc.recvNonce) incrNonce(sc.recvNonce)
// end decryption // end decryption


+ 47
- 0
p2p/conn/secret_connection_test.go View File

@ -16,7 +16,9 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
cmn "github.com/tendermint/tendermint/libs/common" cmn "github.com/tendermint/tendermint/libs/common"
) )
@ -365,6 +367,51 @@ func TestDeriveSecretsAndChallengeGolden(t *testing.T) {
} }
} }
type privKeyWithNilPubKey struct {
orig crypto.PrivKey
}
func (pk privKeyWithNilPubKey) Bytes() []byte { return pk.orig.Bytes() }
func (pk privKeyWithNilPubKey) Sign(msg []byte) ([]byte, error) { return pk.orig.Sign(msg) }
func (pk privKeyWithNilPubKey) PubKey() crypto.PubKey { return nil }
func (pk privKeyWithNilPubKey) Equals(pk2 crypto.PrivKey) bool { return pk.orig.Equals(pk2) }
func TestNilPubkey(t *testing.T) {
var fooConn, barConn = makeKVStoreConnPair()
var fooPrvKey = ed25519.GenPrivKey()
var barPrvKey = privKeyWithNilPubKey{ed25519.GenPrivKey()}
go func() {
_, err := MakeSecretConnection(barConn, barPrvKey)
assert.NoError(t, err)
}()
assert.NotPanics(t, func() {
_, err := MakeSecretConnection(fooConn, fooPrvKey)
if assert.Error(t, err) {
assert.Equal(t, "expected ed25519 pubkey, got <nil>", err.Error())
}
})
}
func TestNonEd25519Pubkey(t *testing.T) {
var fooConn, barConn = makeKVStoreConnPair()
var fooPrvKey = ed25519.GenPrivKey()
var barPrvKey = secp256k1.GenPrivKey()
go func() {
_, err := MakeSecretConnection(barConn, barPrvKey)
assert.NoError(t, err)
}()
assert.NotPanics(t, func() {
_, err := MakeSecretConnection(fooConn, fooPrvKey)
if assert.Error(t, err) {
assert.Equal(t, "expected ed25519 pubkey, got secp256k1.PubKeySecp256k1", err.Error())
}
})
}
// Creates the data for a test vector file. // Creates the data for a test vector file.
// The file format is: // The file format is:
// Hex(diffie_hellman_secret), loc_is_least, Hex(recvSecret), Hex(sendSecret), Hex(challenge) // Hex(diffie_hellman_secret), loc_is_least, Hex(recvSecret), Hex(sendSecret), Hex(challenge)


+ 19
- 0
p2p/transport.go View File

@ -6,6 +6,8 @@ import (
"net" "net"
"time" "time"
"github.com/pkg/errors"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/p2p/conn" "github.com/tendermint/tendermint/p2p/conn"
) )
@ -270,6 +272,23 @@ func (mt *MultiplexTransport) acceptPeers() {
// //
// [0] https://en.wikipedia.org/wiki/Head-of-line_blocking // [0] https://en.wikipedia.org/wiki/Head-of-line_blocking
go func(c net.Conn) { go func(c net.Conn) {
defer func() {
if r := recover(); r != nil {
err := ErrRejected{
conn: c,
err: errors.Errorf("recovered from panic: %v", r),
isAuthFailure: true,
}
select {
case mt.acceptc <- accept{err: err}:
case <-mt.closec:
// Give up if the transport was closed.
_ = c.Close()
return
}
}
}()
var ( var (
nodeInfo NodeInfo nodeInfo NodeInfo
secretConn *conn.SecretConnection secretConn *conn.SecretConnection


Loading…
Cancel
Save