Skip to content

Commit d996f50

Browse files
authored
error handling for invalid curve25519 public keys (#2709)
The function DhSecret which computes a Diffie-Hellman shared secret key now panics on an error. This is an issue as a malicious node could send a low order point public key to intentionally cause the key generation to fail. As this panic doesn't seem to be recovered anywhere it will crash the node. The fix adds back error handling for DH secret generation and a test.
1 parent 91ef5cb commit d996f50

File tree

2 files changed

+25
-11
lines changed

2 files changed

+25
-11
lines changed

sei-tendermint/internal/p2p/conn/evil_secret_connection_test.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ import (
1717
"github.com/tendermint/tendermint/libs/utils/scope"
1818
)
1919

20+
func TestLowOrderPoint(t *testing.T) {
21+
_, err := newSecretConnection(nil, genEphKey(), ephPublic{})
22+
require.True(t, errors.Is(err, errDH))
23+
}
24+
2025
type evilConn struct {
2126
net.Conn
2227
remEphKey utils.AtomicSend[utils.Option[ephPublic]]
@@ -57,11 +62,11 @@ func (c *evilConn) Run(ctx context.Context) error {
5762
return nil
5863
}
5964
loc := genEphKey()
60-
ephKey := loc.public[:]
65+
ephKey := loc.public
6166
if c.badEphKey {
62-
ephKey = []byte("drop users;")
67+
ephKey = ephPublic{}
6368
}
64-
ephKeyMsg := &gogotypes.BytesValue{Value: ephKey}
69+
ephKeyMsg := &gogotypes.BytesValue{Value: ephKey[:]}
6570
if _, err := c.writer.Write(utils.OrPanic1(protoio.MarshalDelimited(ephKeyMsg))); err != nil {
6671
return err
6772
}
@@ -74,7 +79,7 @@ func (c *evilConn) Run(ctx context.Context) error {
7479
if err != nil {
7580
return err
7681
}
77-
sc := newSecretConnection(WriterConn{writer: c.writer}, loc, rem.OrPanic())
82+
sc := utils.OrPanic1(newSecretConnection(WriterConn{writer: c.writer}, loc, rem.OrPanic()))
7883
challenge := sc.challenge[:]
7984
if c.badAuthSignature {
8085
challenge = []byte("invalid challenge")

sei-tendermint/internal/p2p/conn/secret_connection.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,18 @@ type SecretConnection struct {
9494
remPubKey crypto.PubKey
9595
}
9696

97-
func newSecretConnection(conn net.Conn, loc ephSecret, rem ephPublic) *SecretConnection {
97+
func newSecretConnection(conn net.Conn, loc ephSecret, rem ephPublic) (*SecretConnection, error) {
9898
pubs := utils.Slice(loc.public, rem)
9999
if bytes.Compare(pubs[0][:], pubs[1][:]) > 0 {
100100
pubs[0], pubs[1] = pubs[1], pubs[0]
101101
}
102102
transcript := merlin.NewTranscript("TENDERMINT_SECRET_CONNECTION_TRANSCRIPT_HASH")
103103
transcript.AppendMessage(labelEphemeralLowerPublicKey, pubs[0][:])
104104
transcript.AppendMessage(labelEphemeralUpperPublicKey, pubs[1][:])
105-
dh := loc.DhSecret(rem)
105+
dh, err := loc.DhSecret(rem)
106+
if err != nil {
107+
return nil, err
108+
}
106109
transcript.AppendMessage(labelDHSecret, dh[:])
107110
var challenge [32]byte
108111
transcript.ExtractBytes(challenge[:], labelSecretConnectionMac)
@@ -116,7 +119,7 @@ func newSecretConnection(conn net.Conn, loc ephSecret, rem ephPublic) *SecretCon
116119
challenge: challenge,
117120
recvState: utils.NewMutex(newRecvState(aead.recv.Cipher())),
118121
sendState: utils.NewMutex(newSendState(aead.send.Cipher())),
119-
}
122+
}, nil
120123
}
121124

122125
// MakeSecretConnection performs handshake and returns a new authenticated
@@ -135,8 +138,10 @@ func MakeSecretConnection(ctx context.Context, conn net.Conn, locPrivKey crypto.
135138
if err != nil {
136139
return nil, err
137140
}
138-
sc := newSecretConnection(conn, loc, rem)
139-
141+
sc, err := newSecretConnection(conn, loc, rem)
142+
if err != nil {
143+
return nil, err
144+
}
140145
return scope.Run1(ctx, func(ctx context.Context, s scope.Scope) (*SecretConnection, error) {
141146
// Share (in secret) each other's pubkey & challenge signature
142147
s.Spawn(func() error {
@@ -315,8 +320,12 @@ func (s dhSecret) AeadSecrets(locIsLeast bool) aeadSecrets {
315320

316321
// computeDHSecret computes a Diffie-Hellman shared secret key
317322
// from our own local private key and the other's public key.
318-
func (s ephSecret) DhSecret(remPubKey ephPublic) dhSecret {
319-
return dhSecret(utils.OrPanic1(curve25519.X25519(s.secret[:], remPubKey[:])))
323+
func (s ephSecret) DhSecret(remPubKey ephPublic) (dhSecret, error) {
324+
dhSecretRaw, err := curve25519.X25519(s.secret[:], remPubKey[:])
325+
if err != nil {
326+
return dhSecret{}, fmt.Errorf("%w: %v", errDH, err)
327+
}
328+
return dhSecret(dhSecretRaw), nil
320329
}
321330

322331
type authSigMessage struct {

0 commit comments

Comments
 (0)