add inner crypto to linkProtoTraffic, using ephemeral keys, to prevent replay attacks from spoofing peer connections

This commit is contained in:
Arceliar 2018-06-08 18:42:56 -05:00
parent 1dcc60f054
commit e5eb6de1f6
5 changed files with 57 additions and 31 deletions

View File

@ -54,10 +54,12 @@ func linkNodes(m, n *Node) {
// Create peers // Create peers
// Buffering reduces packet loss in the sim // Buffering reduces packet loss in the sim
// This slightly speeds up testing (fewer delays before retrying a ping) // This slightly speeds up testing (fewer delays before retrying a ping)
pLinkPub, pLinkPriv := m.core.DEBUG_newBoxKeys()
qLinkPub, qLinkPriv := m.core.DEBUG_newBoxKeys()
p := m.core.DEBUG_getPeers().DEBUG_newPeer(n.core.DEBUG_getEncryptionPublicKey(), p := m.core.DEBUG_getPeers().DEBUG_newPeer(n.core.DEBUG_getEncryptionPublicKey(),
n.core.DEBUG_getSigningPublicKey()) n.core.DEBUG_getSigningPublicKey(), *m.core.DEBUG_getSharedKey(pLinkPriv, qLinkPub))
q := n.core.DEBUG_getPeers().DEBUG_newPeer(m.core.DEBUG_getEncryptionPublicKey(), q := n.core.DEBUG_getPeers().DEBUG_newPeer(m.core.DEBUG_getEncryptionPublicKey(),
m.core.DEBUG_getSigningPublicKey()) m.core.DEBUG_getSigningPublicKey(), *n.core.DEBUG_getSharedKey(qLinkPriv, pLinkPub))
DEBUG_simLinkPeers(p, q) DEBUG_simLinkPeers(p, q)
return return
} }

View File

@ -64,11 +64,10 @@ func (c *Core) DEBUG_getPeers() *peers {
return &c.peers return &c.peers
} }
func (ps *peers) DEBUG_newPeer(box boxPubKey, func (ps *peers) DEBUG_newPeer(box boxPubKey, sig sigPubKey, link boxSharedKey) *peer {
sig sigPubKey) *peer {
//in <-chan []byte, //in <-chan []byte,
//out chan<- []byte) *peer { //out chan<- []byte) *peer {
return ps.newPeer(&box, &sig) //, in, out) return ps.newPeer(&box, &sig, &link) //, in, out)
} }
/* /*
@ -275,6 +274,10 @@ func (c *Core) DEBUG_newBoxKeys() (*boxPubKey, *boxPrivKey) {
return newBoxKeys() return newBoxKeys()
} }
func (c *Core) DEBUG_getSharedKey(myPrivKey *boxPrivKey, othersPubKey *boxPubKey) *boxSharedKey {
return getSharedKey(myPrivKey, othersPubKey)
}
func (c *Core) DEBUG_newSigKeys() (*sigPubKey, *sigPrivKey) { func (c *Core) DEBUG_newSigKeys() (*sigPubKey, *sigPrivKey) {
return newSigKeys() return newSigKeys()
} }

View File

@ -76,17 +76,18 @@ type peer struct {
bytesSent uint64 // To track bandwidth usage for getPeers bytesSent uint64 // To track bandwidth usage for getPeers
bytesRecvd uint64 // To track bandwidth usage for getPeers bytesRecvd uint64 // To track bandwidth usage for getPeers
// BUG: sync/atomic, 32 bit platforms need the above to be the first element // BUG: sync/atomic, 32 bit platforms need the above to be the first element
core *Core core *Core
port switchPort port switchPort
box boxPubKey box boxPubKey
sig sigPubKey sig sigPubKey
shared boxSharedKey shared boxSharedKey
firstSeen time.Time // To track uptime for getPeers linkShared boxSharedKey
linkOut (chan []byte) // used for protocol traffic (to bypass queues) firstSeen time.Time // To track uptime for getPeers
doSend (chan struct{}) // tell the linkLoop to send a switchMsg linkOut (chan []byte) // used for protocol traffic (to bypass queues)
dinfo *dhtInfo // used to keep the DHT working doSend (chan struct{}) // tell the linkLoop to send a switchMsg
out func([]byte) // Set up by whatever created the peers struct, used to send packets to other nodes dinfo *dhtInfo // used to keep the DHT working
close func() // Called when a peer is removed, to close the underlying connection, or via admin api out func([]byte) // Set up by whatever created the peers struct, used to send packets to other nodes
close func() // Called when a peer is removed, to close the underlying connection, or via admin api
} }
func (p *peer) getQueueSize() int64 { func (p *peer) getQueueSize() int64 {
@ -97,14 +98,15 @@ func (p *peer) updateQueueSize(delta int64) {
atomic.AddInt64(&p.queueSize, delta) atomic.AddInt64(&p.queueSize, delta)
} }
func (ps *peers) newPeer(box *boxPubKey, sig *sigPubKey) *peer { func (ps *peers) newPeer(box *boxPubKey, sig *sigPubKey, linkShared *boxSharedKey) *peer {
now := time.Now() now := time.Now()
p := peer{box: *box, p := peer{box: *box,
sig: *sig, sig: *sig,
shared: *getSharedKey(&ps.core.boxPriv, box), shared: *getSharedKey(&ps.core.boxPriv, box),
firstSeen: now, linkShared: *linkShared,
doSend: make(chan struct{}, 1), firstSeen: now,
core: ps.core} doSend: make(chan struct{}, 1),
core: ps.core}
ps.mutex.Lock() ps.mutex.Lock()
defer ps.mutex.Unlock() defer ps.mutex.Unlock()
oldPorts := ps.getPorts() oldPorts := ps.getPorts()
@ -228,7 +230,13 @@ func (p *peer) sendPacket(packet []byte) {
} }
func (p *peer) sendLinkPacket(packet []byte) { func (p *peer) sendLinkPacket(packet []byte) {
bs, nonce := boxSeal(&p.shared, packet, nil) innerPayload, innerNonce := boxSeal(&p.linkShared, packet, nil)
innerLinkPacket := wire_linkProtoTrafficPacket{
Nonce: *innerNonce,
Payload: innerPayload,
}
outerPayload := innerLinkPacket.encode()
bs, nonce := boxSeal(&p.shared, outerPayload, nil)
linkPacket := wire_linkProtoTrafficPacket{ linkPacket := wire_linkProtoTrafficPacket{
Nonce: *nonce, Nonce: *nonce,
Payload: bs, Payload: bs,
@ -242,7 +250,15 @@ func (p *peer) handleLinkTraffic(bs []byte) {
if !packet.decode(bs) { if !packet.decode(bs) {
return return
} }
payload, isOK := boxOpen(&p.shared, packet.Payload, &packet.Nonce) outerPayload, isOK := boxOpen(&p.shared, packet.Payload, &packet.Nonce)
if !isOK {
return
}
innerPacket := wire_linkProtoTrafficPacket{}
if !innerPacket.decode(outerPayload) {
return
}
payload, isOK := boxOpen(&p.linkShared, innerPacket.Payload, &innerPacket.Nonce)
if !isOK { if !isOK {
return return
} }

View File

@ -43,8 +43,8 @@ type router struct {
func (r *router) init(core *Core) { func (r *router) init(core *Core) {
r.core = core r.core = core
r.addr = *address_addrForNodeID(&r.core.dht.nodeID) r.addr = *address_addrForNodeID(&r.core.dht.nodeID)
in := make(chan []byte, 32) // TODO something better than this... in := make(chan []byte, 32) // TODO something better than this...
p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub) //, out, in) p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &boxSharedKey{})
p.out = func(packet []byte) { p.out = func(packet []byte) {
// This is to make very sure it never blocks // This is to make very sure it never blocks
select { select {

View File

@ -141,10 +141,12 @@ func (iface *tcpInterface) call(saddr string) {
func (iface *tcpInterface) handler(sock net.Conn, incoming bool) { func (iface *tcpInterface) handler(sock net.Conn, incoming bool) {
defer sock.Close() defer sock.Close()
// Get our keys // Get our keys
myLinkPub, myLinkPriv := newBoxKeys() // ephemeral link keys
keys := []byte{} keys := []byte{}
keys = append(keys, tcp_key[:]...) keys = append(keys, tcp_key[:]...)
keys = append(keys, iface.core.boxPub[:]...) keys = append(keys, iface.core.boxPub[:]...)
keys = append(keys, iface.core.sigPub[:]...) keys = append(keys, iface.core.sigPub[:]...)
keys = append(keys, myLinkPub[:]...)
_, err := sock.Write(keys) _, err := sock.Write(keys)
if err != nil { if err != nil {
return return
@ -158,8 +160,9 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) {
if n < len(keys) { /*panic("Partial key packet?") ;*/ if n < len(keys) { /*panic("Partial key packet?") ;*/
return return
} }
info := tcpInfo{} info := tcpInfo{} // used as a map key, so don't include ephemeral link eys
if !tcp_chop_keys(&info.box, &info.sig, &keys) { /*panic("Invalid key packet?") ;*/ var theirLinkPub boxPubKey
if !tcp_chop_keys(&info.box, &info.sig, &theirLinkPub, &keys) { /*panic("Invalid key packet?") ;*/
return return
} }
// Quit the parent call if this is a connection to ourself // Quit the parent call if this is a connection to ourself
@ -207,7 +210,7 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) {
}() }()
// Note that multiple connections to the same node are allowed // Note that multiple connections to the same node are allowed
// E.g. over different interfaces // E.g. over different interfaces
p := iface.core.peers.newPeer(&info.box, &info.sig) p := iface.core.peers.newPeer(&info.box, &info.sig, getSharedKey(myLinkPriv, &theirLinkPub))
p.linkOut = make(chan []byte, 1) p.linkOut = make(chan []byte, 1)
in := func(bs []byte) { in := func(bs []byte) {
p.handlePacket(bs) p.handlePacket(bs)
@ -336,10 +339,10 @@ func (iface *tcpInterface) reader(sock net.Conn, in func([]byte)) {
var tcp_key = [...]byte{'k', 'e', 'y', 's'} var tcp_key = [...]byte{'k', 'e', 'y', 's'}
var tcp_msg = [...]byte{0xde, 0xad, 0xb1, 0x75} // "dead bits" var tcp_msg = [...]byte{0xde, 0xad, 0xb1, 0x75} // "dead bits"
func tcp_chop_keys(box *boxPubKey, sig *sigPubKey, bs *[]byte) bool { func tcp_chop_keys(box *boxPubKey, sig *sigPubKey, link *boxPubKey, bs *[]byte) bool {
// This one is pretty simple: we know how long the message should be // This one is pretty simple: we know how long the message should be
// So don't call this with a message that's too short // So don't call this with a message that's too short
if len(*bs) < len(tcp_key)+len(*box)+len(*sig) { if len(*bs) < len(tcp_key)+2*len(*box)+len(*sig) {
return false return false
} }
for idx := range tcp_key { for idx := range tcp_key {
@ -352,6 +355,8 @@ func tcp_chop_keys(box *boxPubKey, sig *sigPubKey, bs *[]byte) bool {
(*bs) = (*bs)[len(box):] (*bs) = (*bs)[len(box):]
copy(sig[:], *bs) copy(sig[:], *bs)
(*bs) = (*bs)[len(sig):] (*bs) = (*bs)[len(sig):]
copy(link[:], *bs)
(*bs) = (*bs)[len(sig):]
return true return true
} }