2015-12-31 08:40:41 +03:00
|
|
|
package lndc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
)
|
|
|
|
|
2016-01-15 10:24:16 +03:00
|
|
|
// New & improved tcp open session.
|
|
|
|
// There's connector A and listener B. Once the connection is set up there's no
|
|
|
|
// difference, but there can be during the setup.
|
|
|
|
// Setup:
|
|
|
|
// 1 -> A sends B ephemeral secp256k1 pubkey (33 bytes)
|
|
|
|
// 2 <- B sends A ephemeral secp256k1 pubkey (33 bytes)
|
|
|
|
// A and B do DH, get a shared secret.
|
|
|
|
// ==========
|
|
|
|
// Seesion is open! Done! Well not quite. Session is confidential but not
|
|
|
|
// yet authenticated. From here on, can use the Send() and Recv() functions with
|
|
|
|
// chacha20poly1305.
|
|
|
|
// ==========
|
|
|
|
|
|
|
|
// Nodes authenticate by doing a DH with their persistent identity keys, and then
|
|
|
|
// exchanging hash based proofs that they got the same shared IDDH secret.
|
|
|
|
// The DH proof is h160(remote eph pubkey, IDDH secret)
|
|
|
|
// A initiates auth.
|
|
|
|
//
|
|
|
|
// If A does not know B's pubkey but only B's pubkey hash:
|
|
|
|
//
|
|
|
|
// 1 -> A sends [PubKeyA, PubKeyHashB] (53 bytes)
|
|
|
|
// B computes ID pubkey DH
|
|
|
|
// 2 <- B sends [PubkeyB, DH proof] (53 bytes)
|
|
|
|
// 3 -> A sends DH proof (20 bytes)
|
|
|
|
// done.
|
|
|
|
//
|
|
|
|
// This exchange can be sped up if A already knows B's pubkey:
|
|
|
|
//
|
|
|
|
// A already knows who they're talking to, or trying to talk to
|
|
|
|
// 1 -> A sends [PubKeyA, PubkeyHashB, DH proof] (73 bytes)
|
|
|
|
// 2 <- B sends DH proof (20 bytes)
|
|
|
|
//
|
|
|
|
// A and B both verify those H160 hashes, and if matching consider their
|
|
|
|
// session counterparty authenticated.
|
|
|
|
//
|
|
|
|
// A possible weakness of the DH proof is if B re-uses eph keys. That potentially
|
|
|
|
// makes *A*'s proof weaker though. A gets to choose the proof B creates. As
|
|
|
|
// long as your software makes new eph keys each time, you should be OK.
|
|
|
|
|
|
|
|
// WhoAreYou...
|
|
|
|
/*func (lndc *LNDConn) WhoAreYou(host string) (*btcec.PublicKey, error) {
|
2015-12-31 08:40:41 +03:00
|
|
|
var err error
|
|
|
|
if lndc.Cn == nil {
|
|
|
|
return nil, fmt.Errorf("no connection to ask on")
|
|
|
|
}
|
|
|
|
fmt.Printf("connecting to address %s\n", host)
|
|
|
|
// make TCP connection to listening host
|
|
|
|
lndc.Cn, err = net.Dial("tcp", host)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = lndc.writeClear([]byte("WHOAREYOU"))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var b bytes.Buffer
|
|
|
|
lndc.Read(b.Bytes())
|
|
|
|
|
|
|
|
IamResp, err := lndc.readClear()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return btcec.ParsePubKey(IamResp[:33], btcec.S256())
|
2016-01-15 10:24:16 +03:00
|
|
|
}*/
|
2015-12-31 08:40:41 +03:00
|
|
|
|
2016-01-15 10:24:16 +03:00
|
|
|
// PbxEncapsulate...
|
|
|
|
// encapsulation for sending to Pbx host.
|
|
|
|
// put FWDMSG, then 16 byte destination ID, then message (with msgtype)
|
|
|
|
//func (lndc *LNDConn) PbxEncapsulate(b *[]byte) {
|
|
|
|
// fmt.Printf("PbxEncapsulate %d byte message, dest ID %x\n",
|
|
|
|
// len(*b), lndc.RemoteLNId)
|
|
|
|
// *b = append(lndc.RemoteLNId[:], *b...)
|
|
|
|
// *b = append([]byte{lnwire.MSGID_FWDMSG}, *b...)
|
|
|
|
//}
|
|
|
|
|
|
|
|
// readClear and writeClear don't encrypt but directly read and write to the
|
|
|
|
// underlying data link, only adding or subtracting a 2 byte length header.
|
|
|
|
// All Read() and Write() calls for lndc's use these functions internally
|
|
|
|
// (they aren't exported). They're also used in the key agreement phase.
|
|
|
|
|
|
|
|
// readClear reads the next length-prefixed message from the underlying raw
|
|
|
|
// TCP connection.
|
|
|
|
func readClear(c net.Conn) ([]byte, error) {
|
|
|
|
var msgLen uint16
|
2015-12-31 08:40:41 +03:00
|
|
|
|
2016-01-15 10:24:16 +03:00
|
|
|
if err := binary.Read(c, binary.BigEndian, &msgLen); err != nil {
|
|
|
|
return nil, err
|
2015-12-31 08:40:41 +03:00
|
|
|
}
|
|
|
|
|
2016-01-15 10:24:16 +03:00
|
|
|
msg := make([]byte, msgLen)
|
|
|
|
if _, err := io.ReadFull(c, msg); err != nil {
|
|
|
|
return nil, err
|
2015-12-31 08:40:41 +03:00
|
|
|
}
|
|
|
|
|
2016-01-15 10:24:16 +03:00
|
|
|
return msg, nil
|
2015-12-31 08:40:41 +03:00
|
|
|
}
|
|
|
|
|
2016-01-15 10:24:16 +03:00
|
|
|
// TODO(roasbeef): incorporate buffer pool
|
|
|
|
|
|
|
|
// writeClear writes the passed message with a prefixed 2-byte length header.
|
|
|
|
func writeClear(conn net.Conn, msg []byte) (int, error) {
|
|
|
|
if len(msg) > 65530 {
|
|
|
|
return 0, fmt.Errorf("lmsg too long, %d bytes", len(msg))
|
2015-12-31 08:40:41 +03:00
|
|
|
}
|
|
|
|
|
2016-01-15 10:24:16 +03:00
|
|
|
// Add 2 byte length header (pbx doesn't need it) and send over TCP.
|
|
|
|
var msgBuf bytes.Buffer
|
|
|
|
if err := binary.Write(&msgBuf, binary.BigEndian, uint16(len(msg))); err != nil {
|
2015-12-31 08:40:41 +03:00
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2016-01-15 10:24:16 +03:00
|
|
|
if _, err := msgBuf.Write(msg); err != nil {
|
|
|
|
return 0, err
|
2015-12-31 08:40:41 +03:00
|
|
|
}
|
|
|
|
|
2016-01-15 10:24:16 +03:00
|
|
|
return conn.Write(msgBuf.Bytes())
|
2015-12-31 08:40:41 +03:00
|
|
|
}
|