brontide: implement handshake versioning enforcement per the spec

This commit is contained in:
Olaoluwa Osuntokun 2016-11-30 19:11:49 -08:00
parent 71c6e837e3
commit 60f66fe2d7
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
4 changed files with 70 additions and 28 deletions

View File

@ -47,9 +47,11 @@ func Dial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress) (*Conn, error
// Initiate the handshake by sending the first act to the receiver. // Initiate the handshake by sending the first act to the receiver.
actOne, err := b.noise.GenActOne() actOne, err := b.noise.GenActOne()
if err != nil { if err != nil {
b.conn.Close()
return nil, err return nil, err
} }
if _, err := conn.Write(actOne[:]); err != nil { if _, err := conn.Write(actOne[:]); err != nil {
b.conn.Close()
return nil, err return nil, err
} }
@ -59,9 +61,11 @@ func Dial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress) (*Conn, error
// secrecy. // secrecy.
var actTwo [ActTwoSize]byte var actTwo [ActTwoSize]byte
if _, err := io.ReadFull(conn, actTwo[:]); err != nil { if _, err := io.ReadFull(conn, actTwo[:]); err != nil {
b.conn.Close()
return nil, err return nil, err
} }
if err := b.noise.RecvActTwo(actTwo); err != nil { if err := b.noise.RecvActTwo(actTwo); err != nil {
b.conn.Close()
return nil, err return nil, err
} }
@ -69,9 +73,11 @@ func Dial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress) (*Conn, error
// key and execute the final ECDH operation. // key and execute the final ECDH operation.
actThree, err := b.noise.GenActThree() actThree, err := b.noise.GenActThree()
if err != nil { if err != nil {
b.conn.Close()
return nil, err return nil, err
} }
if _, err := conn.Write(actThree[:]); err != nil { if _, err := conn.Write(actThree[:]); err != nil {
b.conn.Close()
return nil, err return nil, err
} }

View File

@ -64,9 +64,11 @@ func (l *Listener) Accept() (net.Conn, error) {
// this portion will fail with a non-nil error. // this portion will fail with a non-nil error.
var actOne [ActOneSize]byte var actOne [ActOneSize]byte
if _, err := io.ReadFull(conn, actOne[:]); err != nil { if _, err := io.ReadFull(conn, actOne[:]); err != nil {
brontideConn.conn.Close()
return nil, err return nil, err
} }
if err := brontideConn.noise.RecvActOne(actOne); err != nil { if err := brontideConn.noise.RecvActOne(actOne); err != nil {
brontideConn.conn.Close()
return nil, err return nil, err
} }
@ -74,9 +76,11 @@ func (l *Listener) Accept() (net.Conn, error) {
// key for the session along with an authenticating tag. // key for the session along with an authenticating tag.
actTwo, err := brontideConn.noise.GenActTwo() actTwo, err := brontideConn.noise.GenActTwo()
if err != nil { if err != nil {
brontideConn.conn.Close()
return nil, err return nil, err
} }
if _, err := conn.Write(actTwo[:]); err != nil { if _, err := conn.Write(actTwo[:]); err != nil {
brontideConn.conn.Close()
return nil, err return nil, err
} }
@ -85,9 +89,11 @@ func (l *Listener) Accept() (net.Conn, error) {
// sides have mutually authenticated each other. // sides have mutually authenticated each other.
var actThree [ActThreeSize]byte var actThree [ActThreeSize]byte
if _, err := io.ReadFull(conn, actThree[:]); err != nil { if _, err := io.ReadFull(conn, actThree[:]); err != nil {
brontideConn.conn.Close()
return nil, err return nil, err
} }
if err := brontideConn.noise.RecvActThree(actThree); err != nil { if err := brontideConn.noise.RecvActThree(actThree); err != nil {
brontideConn.conn.Close()
return nil, err return nil, err
} }

View File

@ -5,6 +5,7 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt"
"io" "io"
"math" "math"
@ -330,30 +331,34 @@ func NewBrontideMachine(initiator bool, localPub *btcec.PrivateKey,
return &BrontideMachine{handshakeState: handshake} return &BrontideMachine{handshakeState: handshake}
} }
// TODO(roasbeef): add version bytes, paramterize in constructor above
const ( const (
// HandshakeVersion is the expected version of the brontide handshake.
// Any messages that carry a different version will cause the handshake
// to abort immediately.
HandshakeVersion = byte(0)
// ActOneSize is the size of the packet sent from initiator to // ActOneSize is the size of the packet sent from initiator to
// responder in ActOne. The packet consists of an ephemeral key in // responder in ActOne. The packet consists of a handshake version, an
// compressed format, and a 16-byte poly1305 tag. // ephemeral key in compressed format, and a 16-byte poly1305 tag.
// //
// 33 + 16 // 1 + 33 + 16
ActOneSize = 49 ActOneSize = 50
// ActTwoSize is the size the packet sent from responder to initiator // ActTwoSize is the size the packet sent from responder to initiator
// in ActTwo. The packet consists of an ephemeral key in compressed // in ActTwo. The packet consists of a handshake version, an ephemeral
// format and a 16-byte poly1305 tag. // key in compressed format and a 16-byte poly1305 tag.
// //
// 33 + 16 // 1 + 33 + 16
ActTwoSize = 49 ActTwoSize = 50
// ActThreeSize is the size of the packet sent from initiator to // ActThreeSize is the size of the packet sent from initiator to
// responder in ActThree. The packet consists of the initiators static // responder in ActThree. The packet consists of a handshake version,
// key encrypted with strong forward secrecy and a 16-byte poly1035 // the initiators static key encrypted with strong forward secrecy and
// a 16-byte poly1035
// tag. // tag.
// //
// 33 + 16 + 16 // 1 + 33 + 16 + 16
ActThreeSize = 65 ActThreeSize = 66
) )
// GenActOne generates the initial packet (act one) to be sent from initiator // GenActOne generates the initial packet (act one) to be sent from initiator
@ -384,8 +389,9 @@ func (b *BrontideMachine) GenActOne() ([ActOneSize]byte, error) {
authPayload := b.EncryptAndHash([]byte{}) authPayload := b.EncryptAndHash([]byte{})
copy(actOne[:33], ephemeral) actOne[0] = HandshakeVersion
copy(actOne[33:], authPayload) copy(actOne[1:34], ephemeral)
copy(actOne[34:], authPayload)
return actOne, nil return actOne, nil
} }
@ -401,8 +407,15 @@ func (b *BrontideMachine) RecvActOne(actOne [ActOneSize]byte) error {
p [16]byte p [16]byte
) )
copy(e[:], actOne[:33]) // If the handshake version is unknown, then the handshake fails
copy(p[:], actOne[33:]) // immediately.
if actOne[0] != HandshakeVersion {
return fmt.Errorf("Invalid handshake version: %v, only %v is "+
"valid", actOne[0], HandshakeVersion)
}
copy(e[:], actOne[1:34])
copy(p[:], actOne[34:])
// e // e
b.remoteEphemeral, err = btcec.ParsePubKey(e[:], btcec.S256()) b.remoteEphemeral, err = btcec.ParsePubKey(e[:], btcec.S256())
@ -451,8 +464,9 @@ func (b *BrontideMachine) GenActTwo() ([ActTwoSize]byte, error) {
authPayload := b.EncryptAndHash([]byte{}) authPayload := b.EncryptAndHash([]byte{})
copy(actTwo[:33], ephemeral) actTwo[0] = HandshakeVersion
copy(actTwo[33:], authPayload) copy(actTwo[1:34], ephemeral)
copy(actTwo[34:], authPayload)
return actTwo, nil return actTwo, nil
} }
@ -467,8 +481,15 @@ func (b *BrontideMachine) RecvActTwo(actTwo [ActTwoSize]byte) error {
p [16]byte p [16]byte
) )
copy(e[:], actTwo[:33]) // If the handshake version is unknown, then the handshake fails
copy(p[:], actTwo[33:]) // immediately.
if actTwo[0] != HandshakeVersion {
return fmt.Errorf("Invalid handshake version: %v, only %v is "+
"valid", actTwo[0], HandshakeVersion)
}
copy(e[:], actTwo[1:34])
copy(p[:], actTwo[34:])
// e // e
b.remoteEphemeral, err = btcec.ParsePubKey(e[:], btcec.S256()) b.remoteEphemeral, err = btcec.ParsePubKey(e[:], btcec.S256())
@ -506,8 +527,9 @@ func (b *BrontideMachine) GenActThree() ([ActThreeSize]byte, error) {
authPayload := b.EncryptAndHash([]byte{}) authPayload := b.EncryptAndHash([]byte{})
copy(actThree[:49], ciphertext) actThree[0] = HandshakeVersion
copy(actThree[49:], authPayload) copy(actThree[1:50], ciphertext)
copy(actThree[50:], authPayload)
// With the final ECDH operation complete, derive the session sending // With the final ECDH operation complete, derive the session sending
// and receiving keys. // and receiving keys.
@ -527,8 +549,15 @@ func (b *BrontideMachine) RecvActThree(actThree [ActThreeSize]byte) error {
p [16]byte p [16]byte
) )
copy(s[:], actThree[:33+16]) // If the handshake version is unknown, then the handshake fails
copy(p[:], actThree[33+16:]) // immediately.
if actThree[0] != HandshakeVersion {
return fmt.Errorf("Invalid handshake version: %v, only %v is "+
"valid", actThree[0], HandshakeVersion)
}
copy(s[:], actThree[1:33+16+1])
copy(p[:], actThree[33+16+1:])
// s // s
remotePub, err := b.DecryptAndHash(s[:]) remotePub, err := b.DecryptAndHash(s[:])

View File

@ -46,16 +46,17 @@ func establishTestConnection() (net.Conn, net.Conn, error) {
connChan := make(chan net.Conn) connChan := make(chan net.Conn)
go func() { go func() {
conn, err := Dial(remotePriv, netAddr) conn, err := Dial(remotePriv, netAddr)
errChan <- err errChan <- err
connChan <- conn connChan <- conn
}() }()
localConn, listenErr := listener.Accept() localConn, listenErr := listener.Accept()
if listenErr != nil { if listenErr != nil {
return nil, nil, err return nil, nil, listenErr
} }
if dialErr := <-errChan; err != nil { if dialErr := <-errChan; dialErr != nil {
return nil, nil, dialErr return nil, nil, dialErr
} }
remoteConn := <-connChan remoteConn := <-connChan