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
// Buffering reduces packet loss in the sim
// 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(),
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(),
m.core.DEBUG_getSigningPublicKey())
m.core.DEBUG_getSigningPublicKey(), *n.core.DEBUG_getSharedKey(qLinkPriv, pLinkPub))
DEBUG_simLinkPeers(p, q)
return
}

View File

@ -64,11 +64,10 @@ func (c *Core) DEBUG_getPeers() *peers {
return &c.peers
}
func (ps *peers) DEBUG_newPeer(box boxPubKey,
sig sigPubKey) *peer {
func (ps *peers) DEBUG_newPeer(box boxPubKey, sig sigPubKey, link boxSharedKey) *peer {
//in <-chan []byte,
//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()
}
func (c *Core) DEBUG_getSharedKey(myPrivKey *boxPrivKey, othersPubKey *boxPubKey) *boxSharedKey {
return getSharedKey(myPrivKey, othersPubKey)
}
func (c *Core) DEBUG_newSigKeys() (*sigPubKey, *sigPrivKey) {
return newSigKeys()
}

View File

@ -76,17 +76,18 @@ type peer struct {
bytesSent 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
core *Core
port switchPort
box boxPubKey
sig sigPubKey
shared boxSharedKey
firstSeen time.Time // To track uptime for getPeers
linkOut (chan []byte) // used for protocol traffic (to bypass queues)
doSend (chan struct{}) // tell the linkLoop to send a switchMsg
dinfo *dhtInfo // used to keep the DHT working
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
core *Core
port switchPort
box boxPubKey
sig sigPubKey
shared boxSharedKey
linkShared boxSharedKey
firstSeen time.Time // To track uptime for getPeers
linkOut (chan []byte) // used for protocol traffic (to bypass queues)
doSend (chan struct{}) // tell the linkLoop to send a switchMsg
dinfo *dhtInfo // used to keep the DHT working
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 {
@ -97,14 +98,15 @@ func (p *peer) updateQueueSize(delta int64) {
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()
p := peer{box: *box,
sig: *sig,
shared: *getSharedKey(&ps.core.boxPriv, box),
firstSeen: now,
doSend: make(chan struct{}, 1),
core: ps.core}
sig: *sig,
shared: *getSharedKey(&ps.core.boxPriv, box),
linkShared: *linkShared,
firstSeen: now,
doSend: make(chan struct{}, 1),
core: ps.core}
ps.mutex.Lock()
defer ps.mutex.Unlock()
oldPorts := ps.getPorts()
@ -228,7 +230,13 @@ func (p *peer) sendPacket(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{
Nonce: *nonce,
Payload: bs,
@ -242,7 +250,15 @@ func (p *peer) handleLinkTraffic(bs []byte) {
if !packet.decode(bs) {
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 {
return
}

View File

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

View File

@ -141,10 +141,12 @@ func (iface *tcpInterface) call(saddr string) {
func (iface *tcpInterface) handler(sock net.Conn, incoming bool) {
defer sock.Close()
// Get our keys
myLinkPub, myLinkPriv := newBoxKeys() // ephemeral link keys
keys := []byte{}
keys = append(keys, tcp_key[:]...)
keys = append(keys, iface.core.boxPub[:]...)
keys = append(keys, iface.core.sigPub[:]...)
keys = append(keys, myLinkPub[:]...)
_, err := sock.Write(keys)
if err != nil {
return
@ -158,8 +160,9 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) {
if n < len(keys) { /*panic("Partial key packet?") ;*/
return
}
info := tcpInfo{}
if !tcp_chop_keys(&info.box, &info.sig, &keys) { /*panic("Invalid key packet?") ;*/
info := tcpInfo{} // used as a map key, so don't include ephemeral link eys
var theirLinkPub boxPubKey
if !tcp_chop_keys(&info.box, &info.sig, &theirLinkPub, &keys) { /*panic("Invalid key packet?") ;*/
return
}
// 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
// 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)
in := func(bs []byte) {
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_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
// 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
}
for idx := range tcp_key {
@ -352,6 +355,8 @@ func tcp_chop_keys(box *boxPubKey, sig *sigPubKey, bs *[]byte) bool {
(*bs) = (*bs)[len(box):]
copy(sig[:], *bs)
(*bs) = (*bs)[len(sig):]
copy(link[:], *bs)
(*bs) = (*bs)[len(sig):]
return true
}