go-p2p/ueps/reader.go
Virgil 643b93da01 refactor(p2p): align AX comments and harden UEPS parsing
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-31 13:48:17 +00:00

115 lines
2.7 KiB
Go

package ueps
import (
"bufio"
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/binary"
"io"
core "dappco.re/go/core"
)
// packet := &ParsedPacket{Header: UEPSHeader{IntentID: 0x01}}
type ParsedPacket struct {
Header UEPSHeader
Payload []byte
}
// packet, err := ReadAndVerify(bufio.NewReader(bytes.NewReader(frame)), sharedSecret)
func ReadAndVerify(r *bufio.Reader, sharedSecret []byte) (*ParsedPacket, error) {
var signedData bytes.Buffer
header := UEPSHeader{}
var signature []byte
var payload []byte
for {
tag, err := r.ReadByte()
if err != nil {
return nil, err
}
lenBuf := make([]byte, 2)
if _, err := io.ReadFull(r, lenBuf); err != nil {
return nil, err
}
length := int(binary.BigEndian.Uint16(lenBuf))
value := make([]byte, length)
if _, err := io.ReadFull(r, value); err != nil {
return nil, err
}
switch tag {
case TagVersion:
if len(value) != 1 {
return nil, core.E("ueps.ReadAndVerify", "malformed version TLV", nil)
}
header.Version = value[0]
signedData.WriteByte(tag)
signedData.Write(lenBuf)
signedData.Write(value)
case TagCurrentLayer:
if len(value) != 1 {
return nil, core.E("ueps.ReadAndVerify", "malformed current layer TLV", nil)
}
header.CurrentLayer = value[0]
signedData.WriteByte(tag)
signedData.Write(lenBuf)
signedData.Write(value)
case TagTargetLayer:
if len(value) != 1 {
return nil, core.E("ueps.ReadAndVerify", "malformed target layer TLV", nil)
}
header.TargetLayer = value[0]
signedData.WriteByte(tag)
signedData.Write(lenBuf)
signedData.Write(value)
case TagIntent:
if len(value) != 1 {
return nil, core.E("ueps.ReadAndVerify", "malformed intent TLV", nil)
}
header.IntentID = value[0]
signedData.WriteByte(tag)
signedData.Write(lenBuf)
signedData.Write(value)
case TagThreatScore:
if len(value) != 2 {
return nil, core.E("ueps.ReadAndVerify", "malformed threat score TLV", nil)
}
header.ThreatScore = binary.BigEndian.Uint16(value)
signedData.WriteByte(tag)
signedData.Write(lenBuf)
signedData.Write(value)
case TagHMAC:
signature = value
case TagPayload:
payload = value
goto verify
default:
signedData.WriteByte(tag)
signedData.Write(lenBuf)
signedData.Write(value)
}
}
verify:
if len(signature) == 0 {
return nil, core.E("ueps.ReadAndVerify", "UEPS packet missing HMAC signature", nil)
}
mac := hmac.New(sha256.New, sharedSecret)
mac.Write(signedData.Bytes())
mac.Write(payload)
expectedMAC := mac.Sum(nil)
if !hmac.Equal(signature, expectedMAC) {
return nil, core.E("ueps.ReadAndVerify", "integrity violation: HMAC mismatch (ThreatScore +100)", nil)
}
return &ParsedPacket{
Header: header,
Payload: payload,
}, nil
}