added signature to introduction for spoofing protection

This commit is contained in:
херетик
2023-02-26 12:04:15 +00:00
parent 859bbecfe2
commit 2d91a0e7c0
10 changed files with 98 additions and 33 deletions

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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,
})
}

View File

@@ -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() {}