Added rekeying (-r secs) client/server

This commit is contained in:
Russ Magee 2023-11-15 00:32:50 -08:00
parent c569a5a3c9
commit 032baf63d6
6 changed files with 80 additions and 30 deletions

View file

@ -57,9 +57,9 @@ func expandKeyMat(keymat []byte, blocksize int) []byte {
return keymat
}
/* Support functionality to set up encryption after a channel has
been negotiated via xsnet.go
*/
/* (Re-)initialize the keystream and hmac state for an xsnet.Conn, returning
a cipherStream and hash
*/
func (hc *Conn) getStream(keymat []byte) (rc cipher.Stream, mc hash.Hash, err error) {
var key []byte
var block cipher.Block

View file

@ -78,6 +78,7 @@ const (
CSOTunDisconn // server -> client: tunnel rport disconnected
CSOTunHangup // client -> server: tunnel lport hung up
CSOKeepAlive // bidir keepalive packet to monitor main connection
CSORekey // TODO: rekey/re-select session cipher/hash algs
)
// TunEndpoint.tunCtl control values - used to control workers for client

View file

@ -88,6 +88,7 @@ type (
Cols uint16
keepalive uint // if this reaches zero, conn is considered dead
rekey uint // if nonzero, rekeying interval in seconds
Pproc int // proc ID of command run on this conn
chaff ChaffConfig
tuns *map[uint16](*TunEndpoint)
@ -1345,6 +1346,12 @@ func (hc *Conn) Read(b []byte) (n int, err error) {
// payload of keepalive (2 bytes) is not currently used (0x55aa fixed)
_ = binary.BigEndian.Uint16(payloadBytes[0:2])
hc.ResetKeepAlive()
case CSORekey:
// rekey
//logger.LogDebug(fmt.Sprintf("[Got rekey [%02x %02x %02x ...]\n",
// payloadBytes[0], payloadBytes[1], payloadBytes[2]))
rekeyData := payloadBytes
hc.r, hc.rm, err = hc.getStream(rekeyData)
case CSOTermSize:
fmt.Sscanf(string(payloadBytes), "%d %d", &hc.Rows, &hc.Cols)
log.Printf("[TermSize pkt: rows %v cols %v]\n", hc.Rows, hc.Cols)
@ -1461,13 +1468,18 @@ func (hc *Conn) Read(b []byte) (n int, err error) {
// Write a byte slice
//
// See go doc io.Writer
func (hc Conn) Write(b []byte) (n int, err error) {
func (hc *Conn) Write(b []byte) (n int, err error) {
//logger.LogDebug("[+Write]")
n, err = hc.WritePacket(b, CSONone)
//logger.LogDebug("[-Write]")
return n, err
}
// Write a byte slice with specified ctrlStatOp byte
func (hc *Conn) WritePacket(b []byte, ctrlStatOp byte) (n int, err error) {
hc.Lock()
defer hc.Unlock()
//log.Printf("[Encrypting...]\r\n")
var hmacOut []uint8
var payloadLen uint32
@ -1495,15 +1507,6 @@ func (hc *Conn) WritePacket(b []byte, ctrlStatOp byte) (n int, err error) {
b = append([]byte{byte(padSide)}, append([]byte{byte(padLen)}, append(b, padBytes...)...)...)
}
// N.B. Originally this Lock() surrounded only the
// calls to binary.Write(hc.c ..) however there appears
// to be some other unshareable state in the Conn
// struct that must be protected to serialize main and
// chaff data written to it.
//
// Would be nice to determine if the mutex scope
// could be tightened.
hc.Lock()
payloadLen = uint32(len(b))
if hc.logPlainText {
log.Printf(" >:ptext:\r\n%s\r\n", hex.Dump(b[0:payloadLen]))
@ -1561,7 +1564,6 @@ func (hc *Conn) WritePacket(b []byte, ctrlStatOp byte) (n int, err error) {
} else {
//fmt.Println("[a]WriteError!")
}
hc.Unlock()
if err != nil {
log.Println(err)
@ -1593,6 +1595,40 @@ func (hc *Conn) SetupChaff(msecsMin uint, msecsMax uint, szMax uint) {
hc.chaff.szMax = szMax
}
func (hc *Conn) ShutdownRekey() {
hc.rekey = 0
}
func (hc *Conn) RekeyHelper(intervalSecs uint) {
go func() {
hc.rekey = intervalSecs
for {
if hc.rekey != 0 {
//logger.LogDebug(fmt.Sprintf("[rekeyHelper Loop]\n"))
time.Sleep(time.Duration(hc.rekey) * time.Second)
// Send rekey to other end
rekeyData := make([]byte, 64)
_, err := crand.Read(rekeyData)
//logger.LogDebug(fmt.Sprintf("[rekey [%02x %02x %02x ...]\n",
// rekeyData[0], rekeyData[1], rekeyData[2]))
//logger.LogDebug("[+rekeyHelper]")
_, err = hc.WritePacket(rekeyData, CSORekey)
hc.Lock()
hc.w, hc.wm, err = hc.getStream(rekeyData)
//logger.LogDebug("[-rekeyHelper]")
hc.Unlock()
if err != nil {
log.Printf("[rekey WritePacket err! (%v) rekey dying ...]\n", err)
return
}
} else {
return
}
}
}()
}
// Helper routine to spawn a chaffing goroutine for each Conn
func (hc *Conn) chaffHelper() {
go func() {
@ -1605,7 +1641,9 @@ func (hc *Conn) chaffHelper() {
min := int(hc.chaff.msecsMin)
nextDuration = rand.Intn(int(hc.chaff.msecsMax)-min) + min
_, _ = rand.Read(bufTmp)
//logger.LogDebug("[+chaffHelper]")
_, err := hc.WritePacket(bufTmp, CSOChaff)
//logger.LogDebug("[-chaffHelper]")
if err != nil {
log.Println("[ *** error - chaffHelper shutting down *** ]")
hc.chaff.shutdown = true
@ -1642,7 +1680,9 @@ func (hc *Conn) keepaliveHelper() {
for {
nextDuration := 10000
bufTmp := []byte{0x55, 0xaa}
//logger.LogDebug("[+keepaliveHelper]")
_, err := hc.WritePacket(bufTmp, CSOKeepAlive)
//logger.LogDebug("[-keepaliveHelper]")
//logger.LogDebug(fmt.Sprintf("[keepalive]\n"))
if err != nil {
logger.LogDebug(fmt.Sprintf("[ *** error - keepaliveHelper quitting *** ]\n"))