remove ID private key from LNDConn struct

This commit is contained in:
Tadge Dryja 2016-01-17 11:20:40 -08:00
parent 9e5f302288
commit b0a402bc4f
3 changed files with 90 additions and 87 deletions

@ -16,18 +16,16 @@ import (
) )
// Conn... // Conn...
type Conn struct { type LNDConn struct {
longTermPriv *btcec.PrivateKey RemotePub *btcec.PublicKey
RemoteLNId [16]byte
remotePub *btcec.PublicKey
remoteLNId [16]byte
myNonceInt uint64 myNonceInt uint64
remoteNonceInt uint64 remoteNonceInt uint64
// If Authed == false, the remotePub is the EPHEMERAL key. // If Authed == false, the remotePub is the EPHEMERAL key.
// once authed == true, remotePub is who you're actually talking to. // once authed == true, remotePub is who you're actually talking to.
authed bool Authed bool
// chachaStream saves some time as you don't have to init it with // chachaStream saves some time as you don't have to init it with
// the session key every time. Make SessionKey redundant; remove later. // the session key every time. Make SessionKey redundant; remove later.
@ -37,26 +35,27 @@ type Conn struct {
// encapsulated PBX connection. // encapsulated PBX connection.
// If going ViaPbx, Cn isn't used channels are used for Read() and // If going ViaPbx, Cn isn't used channels are used for Read() and
// Write(), which are filled by the PBXhandler. // Write(), which are filled by the PBXhandler.
viaPbx bool ViaPbx bool
pbxIncoming chan []byte PbxIncoming chan []byte
pbxOutgoing chan []byte PbxOutgoing chan []byte
version uint8 version uint8
readBuf bytes.Buffer readBuf bytes.Buffer
conn net.Conn Conn net.Conn
} }
// NewConn... // NewConn...
func NewConn(connPrivKey *btcec.PrivateKey, conn net.Conn) *Conn { func NewConn(conn net.Conn) *LNDConn {
return &Conn{longTermPriv: connPrivKey, conn: conn} return &LNDConn{Conn: conn}
} }
// Dial... // Dial...
func (c *Conn) Dial(address string, remoteId []byte) error { func (c *LNDConn) Dial(
myId *btcec.PrivateKey, address string, remoteId []byte) error {
var err error var err error
if c.conn != nil { if c.Conn != nil {
return fmt.Errorf("connection already established") return fmt.Errorf("connection already established")
} }
@ -68,7 +67,7 @@ func (c *Conn) Dial(address string, remoteId []byte) error {
} }
// First, open the TCP connection itself. // First, open the TCP connection itself.
c.conn, err = net.Dial("tcp", address) c.Conn, err = net.Dial("tcp", address)
if err != nil { if err != nil {
return err return err
} }
@ -76,10 +75,10 @@ func (c *Conn) Dial(address string, remoteId []byte) error {
// Calc remote LNId; need this for creating pbx connections just because // Calc remote LNId; need this for creating pbx connections just because
// LNid is in the struct does not mean it's authed! // LNid is in the struct does not mean it's authed!
if len(remoteId) == 20 { if len(remoteId) == 20 {
copy(c.remoteLNId[:], remoteId[:16]) copy(c.RemoteLNId[:], remoteId[:16])
} else { } else {
theirAdr := btcutil.Hash160(remoteId) theirAdr := btcutil.Hash160(remoteId)
copy(c.remoteLNId[:], theirAdr[:16]) copy(c.RemoteLNId[:], theirAdr[:16])
} }
// Make up an ephemeral keypair for this session. // Make up an ephemeral keypair for this session.
@ -90,12 +89,12 @@ func (c *Conn) Dial(address string, remoteId []byte) error {
ourEphemeralPub := ourEphemeralPriv.PubKey() ourEphemeralPub := ourEphemeralPriv.PubKey()
// Sned 1. Send my ephemeral pubkey. Can add version bits. // Sned 1. Send my ephemeral pubkey. Can add version bits.
if _, err = writeClear(c.conn, ourEphemeralPub.SerializeCompressed()); err != nil { if _, err = writeClear(c.Conn, ourEphemeralPub.SerializeCompressed()); err != nil {
return err return err
} }
// Read, then deserialize their ephemeral public key. // Read, then deserialize their ephemeral public key.
theirEphPubBytes, err := readClear(c.conn) theirEphPubBytes, err := readClear(c.Conn)
if err != nil { if err != nil {
return err return err
} }
@ -124,17 +123,17 @@ func (c *Conn) Dial(address string, remoteId []byte) error {
c.myNonceInt = 1 << 63 c.myNonceInt = 1 << 63
c.remoteNonceInt = 0 c.remoteNonceInt = 0
c.remotePub = theirEphPub c.RemotePub = theirEphPub
c.authed = false c.Authed = false
// Session is now open and confidential but not yet authenticated... // Session is now open and confidential but not yet authenticated...
// So auth! // So auth!
if len(remoteId) == 20 { if len(remoteId) == 20 {
// Only know pubkey hash (20 bytes). // Only know pubkey hash (20 bytes).
err = c.authPKH(remoteId, ourEphemeralPub.SerializeCompressed()) err = c.authPKH(myId, remoteId, ourEphemeralPub.SerializeCompressed())
} else { } else {
// Must be 33 byte pubkey. // Must be 33 byte pubkey.
err = c.authPubKey(remoteId, ourEphemeralPub.SerializeCompressed()) err = c.authPubKey(myId, remoteId, ourEphemeralPub.SerializeCompressed())
} }
if err != nil { if err != nil {
return err return err
@ -144,9 +143,10 @@ func (c *Conn) Dial(address string, remoteId []byte) error {
} }
// authPubKey... // authPubKey...
func (c *Conn) authPubKey(remotePubBytes, localEphPubBytes []byte) error { func (c *LNDConn) authPubKey(
if c.authed { myId *btcec.PrivateKey, remotePubBytes, localEphPubBytes []byte) error {
return fmt.Errorf("%s already authed", c.remotePub) if c.Authed {
return fmt.Errorf("%s already authed", c.RemotePub)
} }
// Since we already know their public key, we can immediately generate // Since we already know their public key, we can immediately generate
@ -156,22 +156,22 @@ func (c *Conn) authPubKey(remotePubBytes, localEphPubBytes []byte) error {
return err return err
} }
theirPKH := btcutil.Hash160(remotePubBytes) theirPKH := btcutil.Hash160(remotePubBytes)
idDH := fastsha256.Sum256(btcec.GenerateSharedSecret(c.longTermPriv, theirPub)) idDH := fastsha256.Sum256(btcec.GenerateSharedSecret(myId, theirPub))
myDHproof := btcutil.Hash160(append(c.remotePub.SerializeCompressed(), idDH[:]...)) myDHproof := btcutil.Hash160(append(c.RemotePub.SerializeCompressed(), idDH[:]...))
// Send over the 73 byte authentication message: my pubkey, their // Send over the 73 byte authentication message: my pubkey, their
// pubkey hash, DH proof. // pubkey hash, DH proof.
var authMsg [73]byte var authMsg [73]byte
copy(authMsg[:33], c.longTermPriv.PubKey().SerializeCompressed()) copy(authMsg[:33], myId.PubKey().SerializeCompressed())
copy(authMsg[33:], theirPKH) copy(authMsg[33:], theirPKH)
copy(authMsg[53:], myDHproof) copy(authMsg[53:], myDHproof)
if _, err = c.conn.Write(authMsg[:]); err != nil { if _, err = c.Conn.Write(authMsg[:]); err != nil {
return nil return nil
} }
// Await, their response. They should send only the 20-byte DH proof. // Await, their response. They should send only the 20-byte DH proof.
resp := make([]byte, 20) resp := make([]byte, 20)
_, err = c.conn.Read(resp) _, err = c.Conn.Read(resp)
if err != nil { if err != nil {
return err return err
} }
@ -183,18 +183,19 @@ func (c *Conn) authPubKey(remotePubBytes, localEphPubBytes []byte) error {
} }
// Proof checks out, auth complete. // Proof checks out, auth complete.
c.remotePub = theirPub c.RemotePub = theirPub
theirAdr := btcutil.Hash160(theirPub.SerializeCompressed()) theirAdr := btcutil.Hash160(theirPub.SerializeCompressed())
copy(c.remoteLNId[:], theirAdr[:16]) copy(c.RemoteLNId[:], theirAdr[:16])
c.authed = true c.Authed = true
return nil return nil
} }
// authPKH... // authPKH...
func (c *Conn) authPKH(theirPKH, localEphPubBytes []byte) error { func (c *LNDConn) authPKH(
if c.authed { myId *btcec.PrivateKey, theirPKH, localEphPubBytes []byte) error {
return fmt.Errorf("%s already authed", c.remotePub) if c.Authed {
return fmt.Errorf("%s already authed", c.RemotePub)
} }
if len(theirPKH) != 20 { if len(theirPKH) != 20 {
return fmt.Errorf("remote PKH must be 20 bytes, got %d", return fmt.Errorf("remote PKH must be 20 bytes, got %d",
@ -203,9 +204,9 @@ func (c *Conn) authPKH(theirPKH, localEphPubBytes []byte) error {
// Send 53 bytes: our pubkey, and the remote's pubkey hash. // Send 53 bytes: our pubkey, and the remote's pubkey hash.
var greetingMsg [53]byte var greetingMsg [53]byte
copy(greetingMsg[:33], c.longTermPriv.PubKey().SerializeCompressed()) copy(greetingMsg[:33], myId.PubKey().SerializeCompressed())
copy(greetingMsg[:33], theirPKH) copy(greetingMsg[:33], theirPKH)
if _, err := c.conn.Write(greetingMsg[:]); err != nil { if _, err := c.Conn.Write(greetingMsg[:]); err != nil {
return err return err
} }
@ -214,7 +215,7 @@ func (c *Conn) authPKH(theirPKH, localEphPubBytes []byte) error {
// * NOTE(roasbeef): read timeout should be set on the underlying // * NOTE(roasbeef): read timeout should be set on the underlying
// net.Conn. // net.Conn.
resp := make([]byte, 53) resp := make([]byte, 53)
if _, err := c.conn.Read(resp); err != nil { if _, err := c.Conn.Read(resp); err != nil {
return err return err
} }
@ -223,7 +224,7 @@ func (c *Conn) authPKH(theirPKH, localEphPubBytes []byte) error {
if err != nil { if err != nil {
return err return err
} }
idDH := fastsha256.Sum256(btcec.GenerateSharedSecret(c.longTermPriv, theirPub)) idDH := fastsha256.Sum256(btcec.GenerateSharedSecret(myId, theirPub))
fmt.Printf("made idDH %x\n", idDH) fmt.Printf("made idDH %x\n", idDH)
theirDHproof := btcutil.Hash160(append(localEphPubBytes, idDH[:]...)) theirDHproof := btcutil.Hash160(append(localEphPubBytes, idDH[:]...))
@ -233,16 +234,16 @@ func (c *Conn) authPKH(theirPKH, localEphPubBytes []byte) error {
} }
// If their DH proof checks out, then send our own. // If their DH proof checks out, then send our own.
myDHproof := btcutil.Hash160(append(c.remotePub.SerializeCompressed(), idDH[:]...)) myDHproof := btcutil.Hash160(append(c.RemotePub.SerializeCompressed(), idDH[:]...))
if _, err = c.conn.Write(myDHproof); err != nil { if _, err = c.Conn.Write(myDHproof); err != nil {
return err return err
} }
// Proof sent, auth complete. // Proof sent, auth complete.
c.remotePub = theirPub c.RemotePub = theirPub
theirAdr := btcutil.Hash160(theirPub.SerializeCompressed()) theirAdr := btcutil.Hash160(theirPub.SerializeCompressed())
copy(c.remoteLNId[:], theirAdr[:16]) copy(c.RemoteLNId[:], theirAdr[:16])
c.authed = true c.Authed = true
return nil return nil
} }
@ -251,7 +252,7 @@ func (c *Conn) authPKH(theirPKH, localEphPubBytes []byte) error {
// Read can be made to time out and return a Error with Timeout() == true // Read can be made to time out and return a Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetReadDeadline. // after a fixed time limit; see SetDeadline and SetReadDeadline.
// Part of the net.Conn interface. // Part of the net.Conn interface.
func (c *Conn) Read(b []byte) (n int, err error) { func (c *LNDConn) Read(b []byte) (n int, err error) {
// In order to reconcile the differences between the record abstraction // In order to reconcile the differences between the record abstraction
// of our AEAD connection, and the stream abstraction of TCP, we maintain // of our AEAD connection, and the stream abstraction of TCP, we maintain
// an intermediate read buffer. If this buffer becomes depleated, then // an intermediate read buffer. If this buffer becomes depleated, then
@ -259,7 +260,7 @@ func (c *Conn) Read(b []byte) (n int, err error) {
// read directly from the buffer. // read directly from the buffer.
if c.readBuf.Len() == 0 { if c.readBuf.Len() == 0 {
// The buffer is empty, so read the next cipher text. // The buffer is empty, so read the next cipher text.
ctext, err := readClear(c.conn) ctext, err := readClear(c.Conn)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -270,7 +271,7 @@ func (c *Conn) Read(b []byte) (n int, err error) {
binary.BigEndian.PutUint64(nonceBuf[:], c.remoteNonceInt) binary.BigEndian.PutUint64(nonceBuf[:], c.remoteNonceInt)
fmt.Printf("decrypt %d byte from %x nonce %d\n", fmt.Printf("decrypt %d byte from %x nonce %d\n",
len(ctext), c.remoteLNId, c.remoteNonceInt) len(ctext), c.RemoteLNId, c.remoteNonceInt)
c.remoteNonceInt++ // increment remote nonce, no matter what... c.remoteNonceInt++ // increment remote nonce, no matter what...
@ -292,12 +293,12 @@ func (c *Conn) Read(b []byte) (n int, err error) {
// Write can be made to time out and return a Error with Timeout() == true // Write can be made to time out and return a Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetWriteDeadline. // after a fixed time limit; see SetDeadline and SetWriteDeadline.
// Part of the net.Conn interface. // Part of the net.Conn interface.
func (c *Conn) Write(b []byte) (n int, err error) { func (c *LNDConn) Write(b []byte) (n int, err error) {
if b == nil { if b == nil {
return 0, fmt.Errorf("write to %x nil", c.remoteLNId) return 0, fmt.Errorf("write to %x nil", c.RemoteLNId)
} }
fmt.Printf("Encrypt %d byte plaintext to %x nonce %d\n", fmt.Printf("Encrypt %d byte plaintext to %x nonce %d\n",
len(b), c.remoteLNId, c.myNonceInt) len(b), c.RemoteLNId, c.myNonceInt)
// first encrypt message with shared key // first encrypt message with shared key
var nonceBuf [8]byte var nonceBuf [8]byte
@ -310,50 +311,50 @@ func (c *Conn) Write(b []byte) (n int, err error) {
} }
if len(ctext) > 65530 { if len(ctext) > 65530 {
return 0, fmt.Errorf("Write to %x too long, %d bytes", return 0, fmt.Errorf("Write to %x too long, %d bytes",
c.remoteLNId, len(ctext)) c.RemoteLNId, len(ctext))
} }
// use writeClear to prepend length / destination header // use writeClear to prepend length / destination header
return writeClear(c.conn, ctext) return writeClear(c.Conn, ctext)
} }
// Close closes the connection. // Close closes the connection.
// Any blocked Read or Write operations will be unblocked and return errors. // Any blocked Read or Write operations will be unblocked and return errors.
// Part of the net.Conn interface. // Part of the net.Conn interface.
func (c *Conn) Close() error { func (c *LNDConn) Close() error {
c.myNonceInt = 0 c.myNonceInt = 0
c.remoteNonceInt = 0 c.remoteNonceInt = 0
c.remotePub = nil c.RemotePub = nil
return c.conn.Close() return c.Conn.Close()
} }
// LocalAddr returns the local network address. // LocalAddr returns the local network address.
// Part of the net.Conn interface. // Part of the net.Conn interface.
// If PBX reports address of pbx host. // If PBX reports address of pbx host.
func (c *Conn) LocalAddr() net.Addr { func (c *LNDConn) LocalAddr() net.Addr {
return c.conn.LocalAddr() return c.Conn.LocalAddr()
} }
// RemoteAddr returns the remote network address. // RemoteAddr returns the remote network address.
// Part of the net.Conn interface. // Part of the net.Conn interface.
func (c *Conn) RemoteAddr() net.Addr { func (c *LNDConn) RemoteAddr() net.Addr {
return c.conn.RemoteAddr() return c.Conn.RemoteAddr()
} }
// SetDeadline sets the read and write deadlines associated // SetDeadline sets the read and write deadlines associated
// with the connection. It is equivalent to calling both // with the connection. It is equivalent to calling both
// SetReadDeadline and SetWriteDeadline. // SetReadDeadline and SetWriteDeadline.
// Part of the net.Conn interface. // Part of the net.Conn interface.
func (c *Conn) SetDeadline(t time.Time) error { func (c *LNDConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t) return c.Conn.SetDeadline(t)
} }
// SetReadDeadline sets the deadline for future Read calls. // SetReadDeadline sets the deadline for future Read calls.
// A zero value for t means Read will not time out. // A zero value for t means Read will not time out.
// Part of the net.Conn interface. // Part of the net.Conn interface.
func (c *Conn) SetReadDeadline(t time.Time) error { func (c *LNDConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t) return c.Conn.SetReadDeadline(t)
} }
// SetWriteDeadline sets the deadline for future Write calls. // SetWriteDeadline sets the deadline for future Write calls.
@ -361,8 +362,8 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
// some of the data was successfully written. // some of the data was successfully written.
// A zero value for t means Write will not time out. // A zero value for t means Write will not time out.
// Part of the net.Conn interface. // Part of the net.Conn interface.
func (c *Conn) SetWriteDeadline(t time.Time) error { func (c *LNDConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t) return c.Conn.SetWriteDeadline(t)
} }
var _ net.Conn = (*Conn)(nil) var _ net.Conn = (*LNDConn)(nil)

@ -43,7 +43,7 @@ func (l *Listener) Accept() (c net.Conn, err error) {
return nil, nil return nil, nil
} }
lndc := NewConn(l.longTermPriv, conn) lndc := NewConn(conn)
// Exchange an ephemeral public key with the remote connection in order // Exchange an ephemeral public key with the remote connection in order
// to establish a confidential connection before we attempt to // to establish a confidential connection before we attempt to
@ -56,7 +56,7 @@ func (l *Listener) Accept() (c net.Conn, err error) {
// Now that we've established an encrypted connection, authenticate the // Now that we've established an encrypted connection, authenticate the
// identity of the remote host. // identity of the remote host.
ephemeralPub := ephemeralKey.PubKey().SerializeCompressed() ephemeralPub := ephemeralKey.PubKey().SerializeCompressed()
if err := l.authenticateConnection(lndc, ephemeralPub); err != nil { if err := l.authenticateConnection(l.longTermPriv, lndc, ephemeralPub); err != nil {
lndc.Close() lndc.Close()
return nil, err return nil, err
} }
@ -65,12 +65,12 @@ func (l *Listener) Accept() (c net.Conn, err error) {
} }
// createCipherConn.... // createCipherConn....
func (l *Listener) createCipherConn(lnConn *Conn) (*btcec.PrivateKey, error) { func (l *Listener) createCipherConn(lnConn *LNDConn) (*btcec.PrivateKey, error) {
var err error var err error
var theirEphPubBytes []byte var theirEphPubBytes []byte
// First, read and deserialize their ephemeral public key. // First, read and deserialize their ephemeral public key.
theirEphPubBytes, err = readClear(lnConn.conn) theirEphPubBytes, err = readClear(lnConn.Conn)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -89,7 +89,7 @@ func (l *Listener) createCipherConn(lnConn *Conn) (*btcec.PrivateKey, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if _, err := writeClear(lnConn.conn, myEph.PubKey().SerializeCompressed()); err != nil { if _, err := writeClear(lnConn.Conn, myEph.PubKey().SerializeCompressed()); err != nil {
return nil, err return nil, err
} }
@ -107,19 +107,20 @@ func (l *Listener) createCipherConn(lnConn *Conn) (*btcec.PrivateKey, error) {
lnConn.remoteNonceInt = 1 << 63 lnConn.remoteNonceInt = 1 << 63
lnConn.myNonceInt = 0 lnConn.myNonceInt = 0
lnConn.remotePub = theirEphPub lnConn.RemotePub = theirEphPub
lnConn.authed = false lnConn.Authed = false
return myEph, nil return myEph, nil
} }
// AuthListen... // AuthListen...
func (l *Listener) authenticateConnection(lnConn *Conn, localEphPubBytes []byte) error { func (l *Listener) authenticateConnection(
myId *btcec.PrivateKey, lnConn *LNDConn, localEphPubBytes []byte) error {
var err error var err error
// TODO(roasbeef): should be using read/write clear here? // TODO(roasbeef): should be using read/write clear here?
slice := make([]byte, 73) slice := make([]byte, 73)
n, err := lnConn.conn.Read(slice) n, err := lnConn.Conn.Read(slice)
if err != nil { if err != nil {
fmt.Printf("Read error: %s\n", err.Error()) fmt.Printf("Read error: %s\n", err.Error())
return err return err
@ -144,11 +145,11 @@ func (l *Listener) authenticateConnection(lnConn *Conn, localEphPubBytes []byte)
return err return err
} }
idDH := fastsha256.Sum256( idDH := fastsha256.Sum256(
btcec.GenerateSharedSecret(lnConn.longTermPriv, theirPub), btcec.GenerateSharedSecret(l.longTermPriv, theirPub),
) )
myDHproof := btcutil.Hash160( myDHproof := btcutil.Hash160(
append(lnConn.remotePub.SerializeCompressed(), idDH[:]...), append(lnConn.RemotePub.SerializeCompressed(), idDH[:]...),
) )
theirDHproof := btcutil.Hash160(append(localEphPubBytes, idDH[:]...)) theirDHproof := btcutil.Hash160(append(localEphPubBytes, idDH[:]...))
@ -162,19 +163,19 @@ func (l *Listener) authenticateConnection(lnConn *Conn, localEphPubBytes []byte)
} }
// Their DH proof checks out, so send ours now. // Their DH proof checks out, so send ours now.
if _, err = lnConn.conn.Write(myDHproof); err != nil { if _, err = lnConn.Conn.Write(myDHproof); err != nil {
return err return err
} }
} else { } else {
// Otherwise, they don't yet know our public key. So we'll send // Otherwise, they don't yet know our public key. So we'll send
// it over to them, so we can both compute the DH proof. // it over to them, so we can both compute the DH proof.
msg := append(l.longTermPriv.PubKey().SerializeCompressed(), myDHproof...) msg := append(l.longTermPriv.PubKey().SerializeCompressed(), myDHproof...)
if _, err = lnConn.conn.Write(msg); err != nil { if _, err = lnConn.Conn.Write(msg); err != nil {
return err return err
} }
resp := make([]byte, 20) resp := make([]byte, 20)
if _, err := lnConn.conn.Read(resp); err != nil { if _, err := lnConn.Conn.Read(resp); err != nil {
return err return err
} }
@ -185,9 +186,9 @@ func (l *Listener) authenticateConnection(lnConn *Conn, localEphPubBytes []byte)
} }
theirAdr := btcutil.Hash160(theirPub.SerializeCompressed()) theirAdr := btcutil.Hash160(theirPub.SerializeCompressed())
copy(lnConn.remoteLNId[:], theirAdr[:16]) copy(lnConn.RemoteLNId[:], theirAdr[:16])
lnConn.remotePub = theirPub lnConn.RemotePub = theirPub
lnConn.authed = true lnConn.Authed = true
return nil return nil
} }

@ -155,8 +155,9 @@ out:
// breaks down, then return an error to the // breaks down, then return an error to the
// caller. // caller.
ipAddr := addr.NetAddr.String() ipAddr := addr.NetAddr.String()
conn := lndc.NewConn(s.longTermPriv, nil) conn := lndc.NewConn(nil)
if err := conn.Dial(ipAddr, remoteId); err != nil { if err := conn.Dial(
s.longTermPriv, ipAddr, remoteId); err != nil {
msg.reply <- err msg.reply <- err
} }