From 2d91a0e7c06ca4a012f7057f66271b69daf5fd63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=85=D0=B5=D1=80=D0=B5=D1=82=D0=B8=D0=BA?= Date: Sun, 26 Feb 2023 12:04:15 +0000 Subject: [PATCH] added signature to introduction for spoofing protection --- pkg/messages/hiddenservice/hiddenservice.go | 18 +++---- pkg/messages/intro/intro-message.go | 56 +++++++++++++++++++-- pkg/messages/session/session.go | 2 +- pkg/relay/engine_test.go | 14 +++--- pkg/relay/handler-hiddenservice.go | 6 +-- pkg/relay/handler-session.go | 2 +- pkg/relay/helper-sendintroduction.go | 6 +-- pkg/relay/onion-hiddenservice.go | 5 +- pkg/relay/skins.go | 11 ++-- pkg/splice/splice.go | 11 ++++ 10 files changed, 98 insertions(+), 33 deletions(-) diff --git a/pkg/messages/hiddenservice/hiddenservice.go b/pkg/messages/hiddenservice/hiddenservice.go index 79231e2b..9e61ed13 100644 --- a/pkg/messages/hiddenservice/hiddenservice.go +++ b/pkg/messages/hiddenservice/hiddenservice.go @@ -2,9 +2,9 @@ package hiddenservice import ( "git-indra.lan/indra-labs/indra" - "git-indra.lan/indra-labs/indra/pkg/crypto/key/pub" "git-indra.lan/indra-labs/indra/pkg/crypto/nonce" "git-indra.lan/indra-labs/indra/pkg/crypto/sha256" + "git-indra.lan/indra-labs/indra/pkg/messages/intro" "git-indra.lan/indra-labs/indra/pkg/messages/magicbytes" log2 "git-indra.lan/indra-labs/indra/pkg/proc/log" "git-indra.lan/indra-labs/indra/pkg/splice" @@ -14,7 +14,7 @@ import ( const ( MagicString = "hs" - Len = magicbytes.Len + nonce.IDLen + pub.KeyLen + + Len = magicbytes.Len + nonce.IDLen + intro.Len + 3*sha256.Len + nonce.IVLen*3 ) @@ -30,11 +30,7 @@ var ( // header for any client that requests it. type Layer struct { nonce.ID - // Identity is a public key identifying the hidden service. It is encoded - // into Bech32 encoding to function like an IP address, with a 2 byte - // truncated hash check suffix to eliminate possible human input errors and - // ending in ".indra" to indicate it is an indra hidden service. - Identity *pub.Key + intro.Layer // Ciphers is a set of 3 symmetric ciphers that are to be used in their // given order over the reply message from the service. Ciphers [3]sha256.Hash @@ -56,7 +52,9 @@ func (x *Layer) Encode(b slice.Bytes, c *slice.Cursor) { splice.Splice(b, c). Magic(Magic). ID(x.ID). - Pubkey(x.Identity). + Pubkey(x.Key). + AddrPort(x.AddrPort). + Signature(x.Bytes). Hash(x.Ciphers[0]).Hash(x.Ciphers[1]).Hash(x.Ciphers[2]). IV(x.Nonces[0]).IV(x.Nonces[1]).IV(x.Nonces[2]) } @@ -67,7 +65,9 @@ func (x *Layer) Decode(b slice.Bytes, c *slice.Cursor) (e error) { } splice.Splice(b, c). ReadID(&x.ID). - ReadPubkey(&x.Identity). + ReadPubkey(&x.Key). + ReadAddrPort(&x.AddrPort). + ReadSignature(x.Bytes). ReadHash(&x.Ciphers[0]).ReadHash(&x.Ciphers[1]).ReadHash(&x.Ciphers[2]). ReadIV(&x.Nonces[0]).ReadIV(&x.Nonces[1]).ReadIV(&x.Nonces[2]) return diff --git a/pkg/messages/intro/intro-message.go b/pkg/messages/intro/intro-message.go index ec4b9aca..b445bd01 100644 --- a/pkg/messages/intro/intro-message.go +++ b/pkg/messages/intro/intro-message.go @@ -4,17 +4,27 @@ import ( "net" "net/netip" + "git-indra.lan/indra-labs/indra" + "git-indra.lan/indra-labs/indra/pkg/crypto/key/prv" "git-indra.lan/indra-labs/indra/pkg/crypto/key/pub" + "git-indra.lan/indra-labs/indra/pkg/crypto/key/sig" + "git-indra.lan/indra-labs/indra/pkg/crypto/sha256" "git-indra.lan/indra-labs/indra/pkg/messages/magicbytes" + log2 "git-indra.lan/indra-labs/indra/pkg/proc/log" "git-indra.lan/indra-labs/indra/pkg/splice" "git-indra.lan/indra-labs/indra/pkg/types" "git-indra.lan/indra-labs/indra/pkg/util/slice" ) +var ( + log = log2.GetLogger(indra.PathBase) + check = log.E.Chk +) + const ( MagicString = "in" AddrLen = net.IPv6len + 3 - Len = magicbytes.Len + pub.KeyLen + AddrLen + Len = magicbytes.Len + pub.KeyLen + AddrLen + sig.Len ) var ( @@ -24,17 +34,57 @@ var ( type Layer struct { *pub.Key *netip.AddrPort + sig.Bytes +} + +func New(key *prv.Key, ap *netip.AddrPort) (im *Layer) { + pk := pub.Derive(key) + bap, _ := ap.MarshalBinary() + pkb := pk.ToBytes() + hash := sha256.Single(append(pkb[:], bap...)) + var e error + var sign sig.Bytes + if sign, e = sig.Sign(key, hash); check(e) { + return nil + } + im = &Layer{ + Key: pk, + AddrPort: ap, + Bytes: sign, + } + return +} + +func (im *Layer) Validate() bool { + bap, _ := im.AddrPort.MarshalBinary() + pkb := im.Key.ToBytes() + hash := sha256.Single(append(pkb[:], bap...)) + key, e := im.Bytes.Recover(hash) + if check(e) { + return false + } + kb := key.ToBytes() + if kb.Equals(pkb) { + return true + } + return false } func (im *Layer) Insert(o types.Onion) {} func (im *Layer) Len() int { return Len } func (im *Layer) Encode(b slice.Bytes, c *slice.Cursor) { - splice.Splice(b, c).Magic(Magic).Pubkey(im.Key).AddrPort(im.AddrPort) + splice.Splice(b, c). + Magic(Magic). + Pubkey(im.Key). + AddrPort(im.AddrPort). + Signature(im.Bytes) return } func (im *Layer) Decode(b slice.Bytes, c *slice.Cursor) (e error) { - splice.Splice(b, c).ReadPubkey(&im.Key).ReadAddrPort(&im.AddrPort) + splice.Splice(b, c). + ReadPubkey(&im.Key). + ReadAddrPort(&im.AddrPort).ReadSignature(im.Bytes) return } diff --git a/pkg/messages/session/session.go b/pkg/messages/session/session.go index 32942a53..8a3e8660 100644 --- a/pkg/messages/session/session.go +++ b/pkg/messages/session/session.go @@ -44,7 +44,7 @@ var ( // is concealed to the hops except for the encryption crypt they decrypt using // their Payload key, delivered in this message. type Layer struct { - nonce.ID + nonce.ID // only used by a node Hop byte // only used by a node Header, Payload *prv.Key types.Onion diff --git a/pkg/relay/engine_test.go b/pkg/relay/engine_test.go index d35c3e2a..11b40194 100644 --- a/pkg/relay/engine_test.go +++ b/pkg/relay/engine_test.go @@ -10,9 +10,9 @@ import ( "go.uber.org/atomic" "git-indra.lan/indra-labs/indra/pkg/crypto/key/prv" - "git-indra.lan/indra-labs/indra/pkg/crypto/key/pub" "git-indra.lan/indra-labs/indra/pkg/crypto/nonce" "git-indra.lan/indra-labs/indra/pkg/crypto/sha256" + "git-indra.lan/indra-labs/indra/pkg/messages/intro" log2 "git-indra.lan/indra-labs/indra/pkg/proc/log" "git-indra.lan/indra-labs/indra/pkg/service" "git-indra.lan/indra-labs/indra/pkg/transport" @@ -290,10 +290,10 @@ func TestClient_HiddenService(t *testing.T) { t.Error(e) t.FailNow() } - identPub := pub.Derive(identPrv) id := nonce.NewID() + il := intro.New(identPrv, clients[0].GetLocalNodeAddress()) clients[0].SendIntro(id, clients[0].Sessions[i+returns], - identPub, func(id nonce.ID, b slice.Bytes) { + il, func(id nonce.ID, b slice.Bytes) { log.I.Ln("success") }) } @@ -303,7 +303,7 @@ func TestClient_HiddenService(t *testing.T) { } } func TestClient_HiddenServiceBroadcast(t *testing.T) { - log2.SetLogLevel(log2.Trace) + log2.SetLogLevel(log2.Info) var clients []*Engine var e error const returns = 2 @@ -340,10 +340,12 @@ func TestClient_HiddenServiceBroadcast(t *testing.T) { t.Error(e) t.FailNow() } - identPub := pub.Derive(identPrv) + log2.SetLogLevel(log2.Trace) + // identPub := pub.Derive(identPrv) id := nonce.NewID() + il := intro.New(identPrv, clients[0].GetLocalNodeAddress()) clients[0].SendIntro(id, clients[0].Sessions[returns], - identPub, func(id nonce.ID, b slice.Bytes) { + il, func(id nonce.ID, b slice.Bytes) { log.I.Ln("success") }) time.Sleep(time.Second * 5) diff --git a/pkg/relay/handler-hiddenservice.go b/pkg/relay/handler-hiddenservice.go index 3b8dcc37..c3e58b69 100644 --- a/pkg/relay/handler-hiddenservice.go +++ b/pkg/relay/handler-hiddenservice.go @@ -10,8 +10,8 @@ func (eng *Engine) hiddenservice(hs *hiddenservice.Layer, b slice.Bytes, c *slice.Cursor, prev types.Onion) { log.D.F("%s adding introduction for key %s", eng.GetLocalNodeAddress(), - hs.Identity.ToBase32()) - eng.Introductions.AddIntro(hs.Identity, b[*c:]) + hs.Layer.Key.ToBase32()) + eng.Introductions.AddIntro(hs.Layer.Key, b[*c:]) log.I.Ln("stored new introduction, starting broadcast") - go eng.hiddenserviceBroadcaster(hs.Identity) + go eng.hiddenserviceBroadcaster(hs.Layer.Key) } diff --git a/pkg/relay/handler-session.go b/pkg/relay/handler-session.go index 7ffea44d..b9bfcbaa 100644 --- a/pkg/relay/handler-session.go +++ b/pkg/relay/handler-session.go @@ -10,7 +10,7 @@ func (eng *Engine) session(on *session.Layer, b slice.Bytes, c *slice.Cursor, prev types.Onion) { log.D.Ln(prev == nil) - log.T.F("incoming session %s", on.ID) + log.T.F("incoming session %x", on.PreimageHash()) pi := eng.FindPendingPreimage(on.PreimageHash()) if pi != nil { // We need to delete this first in case somehow two such messages arrive diff --git a/pkg/relay/helper-sendintroduction.go b/pkg/relay/helper-sendintroduction.go index ae9ed60f..19adab01 100644 --- a/pkg/relay/helper-sendintroduction.go +++ b/pkg/relay/helper-sendintroduction.go @@ -1,12 +1,12 @@ package relay import ( - "git-indra.lan/indra-labs/indra/pkg/crypto/key/pub" "git-indra.lan/indra-labs/indra/pkg/crypto/nonce" + "git-indra.lan/indra-labs/indra/pkg/messages/intro" "git-indra.lan/indra-labs/indra/pkg/util/slice" ) -func (eng *Engine) SendIntro(id nonce.ID, target *Session, ident *pub.Key, +func (eng *Engine) SendIntro(id nonce.ID, target *Session, intr *intro.Layer, hook func(id nonce.ID, b slice.Bytes)) { log.I.Ln(target.Hop) @@ -16,7 +16,7 @@ func (eng *Engine) SendIntro(id nonce.ID, target *Session, ident *pub.Key, se := eng.SelectHops(hops, s) var c Circuit copy(c[:], se) - o := HiddenService(id, ident, se[len(se)-1], c, eng.KeySet) + o := HiddenService(id, intr, se[len(se)-1], c, eng.KeySet) log.D.Ln("sending out intro onion") res := eng.PostAcctOnion(o) eng.SendWithOneHook(c[0].AddrPort, res, hook) diff --git a/pkg/relay/onion-hiddenservice.go b/pkg/relay/onion-hiddenservice.go index 6497f25f..18f0c69c 100644 --- a/pkg/relay/onion-hiddenservice.go +++ b/pkg/relay/onion-hiddenservice.go @@ -5,9 +5,10 @@ import ( "git-indra.lan/indra-labs/indra/pkg/crypto/key/pub" "git-indra.lan/indra-labs/indra/pkg/crypto/key/signer" "git-indra.lan/indra-labs/indra/pkg/crypto/nonce" + "git-indra.lan/indra-labs/indra/pkg/messages/intro" ) -func HiddenService(id nonce.ID, ident *pub.Key, client *Session, s Circuit, +func HiddenService(id nonce.ID, il *intro.Layer, client *Session, s Circuit, ks *signer.KeySet) Skins { var prvs [3]*prv.Key @@ -25,7 +26,7 @@ func HiddenService(id nonce.ID, ident *pub.Key, client *Session, s Circuit, ReverseCrypt(s[0], ks.Next(), n[0], 3). ReverseCrypt(s[1], ks.Next(), n[1], 2). ReverseCrypt(s[2], ks.Next(), n[2], 1). - HiddenService(id, ident, prvs, pubs, returnNonces). + HiddenService(id, il, prvs, pubs, returnNonces). ReverseCrypt(s[3], prvs[0], n[3], 3). ReverseCrypt(s[4], prvs[1], n[4], 2). ReverseCrypt(client, prvs[2], n[5], 1) diff --git a/pkg/relay/skins.go b/pkg/relay/skins.go index 51c9c455..d7c5bfde 100644 --- a/pkg/relay/skins.go +++ b/pkg/relay/skins.go @@ -17,6 +17,7 @@ import ( "git-indra.lan/indra-labs/indra/pkg/messages/forward" "git-indra.lan/indra-labs/indra/pkg/messages/getbalance" "git-indra.lan/indra-labs/indra/pkg/messages/hiddenservice" + "git-indra.lan/indra-labs/indra/pkg/messages/intro" "git-indra.lan/indra-labs/indra/pkg/messages/noop" "git-indra.lan/indra-labs/indra/pkg/messages/response" "git-indra.lan/indra-labs/indra/pkg/messages/reverse" @@ -113,13 +114,13 @@ func (o Skins) GetBalance(id, confID nonce.ID, prvs [3]*prv.Key, }) } -func (o Skins) HiddenService(id nonce.ID, addr *pub.Key, prvs [3]*prv.Key, +func (o Skins) HiddenService(id nonce.ID, intr *intro.Layer, prvs [3]*prv.Key, pubs [3]*pub.Key, nonces [3]nonce.IV) Skins { return append(o, &hiddenservice.Layer{ - ID: id, - Identity: addr, - Ciphers: GenCiphers(prvs, pubs), - Nonces: nonces, + ID: id, + Layer: *intr, + Ciphers: GenCiphers(prvs, pubs), + Nonces: nonces, }) } diff --git a/pkg/splice/splice.go b/pkg/splice/splice.go index b4987389..0bb0806f 100644 --- a/pkg/splice/splice.go +++ b/pkg/splice/splice.go @@ -11,6 +11,7 @@ import ( "git-indra.lan/indra-labs/indra/pkg/crypto/key/cloak" "git-indra.lan/indra-labs/indra/pkg/crypto/key/prv" "git-indra.lan/indra-labs/indra/pkg/crypto/key/pub" + "git-indra.lan/indra-labs/indra/pkg/crypto/key/sig" "git-indra.lan/indra-labs/indra/pkg/crypto/nonce" "git-indra.lan/indra-labs/indra/pkg/crypto/sha256" "git-indra.lan/indra-labs/indra/pkg/messages/magicbytes" @@ -177,4 +178,14 @@ func (s *Splicer) Bytes(b []byte) *Splicer { return s } +func (s *Splicer) Signature(sb sig.Bytes) *Splicer { + copy(s.b[*s.c:s.c.Inc(sig.Len)], sb[:]) + return s +} + +func (s *Splicer) ReadSignature(sb sig.Bytes) *Splicer { + copy(sb[:], s.b[*s.c:s.c.Inc(sig.Len)]) + return s +} + func (s *Splicer) Done() {}