actually authenticate messages with challenges and HMACs

This commit is contained in:
2026-07-23 12:39:19 +02:00
parent 4d710fb72b
commit 3f11053834
5 changed files with 165 additions and 52 deletions

View File

@@ -1,7 +1,9 @@
package main
import (
"crypto/hmac"
"crypto/hpke"
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"log"
@@ -26,9 +28,11 @@ var (
iface *water.Interface
conn *net.UDPConn
serverAddr *net.UDPAddr
internalIP net.IP = nil
internalIP net.IP
privKey hpke.PrivateKey
multicastKey []byte
challengeCh = make(chan []byte, 1)
authSecret []byte
establishMutex sync.Mutex
peerPubKeys = shared.NewTMap[string, hpke.PublicKey]()
@@ -70,8 +74,23 @@ func register() {
}
pubKey := privKey.PublicKey()
// TODO: this probably should be repeated until we get RESP_REGISTER
send(shared.BuildPkt(shared.REQ_REGISTER, pubKey.Bytes()))
// TODO: all this probably should be retried until we get RESP_REGISTER
log.Println("requesting register challenge")
send(shared.BuildPkt(shared.REQ_GET_CHALLENGE, pubKey.Bytes()))
challenge := <-challengeCh
log.Println("got register challenge")
authSecret, err = hpke.Open(privKey, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte("baalvpn-challenge"), challenge)
if err != nil {
panic(err)
}
log.Println("registering")
mac := hmac.New(sha256.New, authSecret)
mac.Write(pubKey.Bytes())
send(shared.BuildPkt(shared.REQ_REGISTER, mac.Sum(nil), pubKey.Bytes()))
}
func receivePackets() {
@@ -116,11 +135,13 @@ func handleIncomingPkt(pkt []byte) {
pktType := binary.LittleEndian.Uint16(pkt[2:])
switch pktType {
case shared.RESP_GET_CHALLENGE:
challengeCh <- pkt[4:]
case shared.RESP_REGISTER:
internalIP = net.IP(pkt[4:20])
var err error
multicastKey, err = hpke.Open(privKey, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte("baalvpn"), pkt[20:])
multicastKey, err = hpke.Open(privKey, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte("baalvpn-register"), pkt[20:])
if err != nil {
panic(err)
}
@@ -129,11 +150,11 @@ func handleIncomingPkt(pkt []byte) {
setupInterface()
go relayPackets()
case shared.ENC_PKT:
srcIP := net.IP(pkt[20:36]).String()
srcIP := net.IP(pkt[52:68]).String()
sessionKey := getOrEstablishSessionKey(srcIP)
decryptedPkt, err := DecryptSym(sessionKey, pkt[36:])
decryptedPkt, err := DecryptSym(sessionKey, pkt[68:])
if err != nil {
panic(err)
}
@@ -143,7 +164,7 @@ func handleIncomingPkt(pkt []byte) {
log.Println(err)
}
case shared.BROADCAST_PKT:
decryptedPkt, err := DecryptSym(multicastKey, pkt[4:])
decryptedPkt, err := DecryptSym(multicastKey, pkt[36:])
if err != nil {
panic(err)
}
@@ -159,14 +180,14 @@ func handleIncomingPkt(pkt []byte) {
}
peerPubKeys.Set(respIP, pubKey)
case shared.REQ_ESTABLISH:
srcIP := net.IP(pkt[20:36]).String()
ciphertext := pkt[36:]
srcIP := net.IP(pkt[52:68]).String()
ciphertext := pkt[68:]
r, err := hpke.NewRecipient(ciphertext, privKey, hpke.HKDFSHA256(), hpke.ExportOnly(), nil)
if err != nil {
panic(err)
}
sessionKey, err := r.Export("baalvpn", 32)
sessionKey, err := r.Export("baalvpn-establish", 32)
if err != nil {
panic(err)
}
@@ -174,10 +195,9 @@ func handleIncomingPkt(pkt []byte) {
log.Println("received session key from", srcIP)
peerSessionKeys.Set(srcIP, sessionKey)
reqData := append(net.ParseIP(srcIP), internalIP...)
send(shared.BuildPkt(shared.RESP_ESTABLISH, reqData))
send(buildAuthPkt(shared.RESP_ESTABLISH, net.ParseIP(srcIP), internalIP))
case shared.RESP_ESTABLISH:
srcIP := net.IP(pkt[20:36]).String()
srcIP := net.IP(pkt[52:68]).String()
log.Println("established session key with", srcIP)
peerEstablishAcks.Set(srcIP, true)
default:
@@ -215,13 +235,12 @@ func getOrEstablishSessionKey(ip string) []byte {
if err != nil {
panic(err)
}
sessionKey, err := sender.Export("baalvpn", 32)
sessionKey, err := sender.Export("baalvpn-establish", 32)
if err != nil {
panic(err)
}
reqData := append(net.ParseIP(ip), append(internalIP, ciphertext...)...)
send(shared.BuildPkt(shared.REQ_ESTABLISH, reqData))
send(buildAuthPkt(shared.REQ_ESTABLISH, net.ParseIP(ip), internalIP, ciphertext))
for {
// TODO: eww
@@ -279,7 +298,7 @@ func relayPackets() {
panic(err)
}
send(shared.BuildPkt(shared.BROADCAST_PKT, encryptedPkt))
send(buildAuthPkt(shared.BROADCAST_PKT, encryptedPkt))
} else {
destSessionKey := getOrEstablishSessionKey(destIP)
@@ -288,12 +307,18 @@ func relayPackets() {
panic(err)
}
reqBody := append(net.ParseIP(destIP), append(internalIP, encryptedPkt...)...)
send(shared.BuildPkt(shared.ENC_PKT, reqBody))
send(buildAuthPkt(shared.ENC_PKT, net.ParseIP(destIP), internalIP, encryptedPkt))
}
}
}
func buildAuthPkt(pktType uint16, parts ...[]byte) []byte {
pkt := shared.BuildPkt(pktType, parts...)
mac := hmac.New(sha256.New, authSecret)
mac.Write(pkt[4:])
return append(pkt[:4], append(mac.Sum(nil), pkt[4:]...)...)
}
func send(req []byte) {
if _, err := conn.WriteToUDP(req, serverAddr); err != nil {
panic(err)