Files
lneto/x/nts/nts_test.go
T
Pat Whittingslow 5a674a4ad1 fix for #124 (#125)
2026-06-17 15:16:55 -03:00

752 lines
20 KiB
Go

package nts
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/binary"
"math/big"
"net"
"testing"
"time"
"github.com/soypat/lneto"
"github.com/soypat/lneto/ntp"
// NOTE: tests exercising AES-SIV-CMAC-256 are skipped pending
// due to missing stdlib support.
)
func TestKERecord_RoundTrip(t *testing.T) {
body := []byte("hello NTS-KE")
buf := AppendKERecord(nil, true, RecordNewCookie, body)
rec, err := NewKERecord(buf)
if err != nil {
t.Fatal(err)
}
if rec.RecordType() != RecordNewCookie {
t.Errorf("RecordType = %v; want %v", rec.RecordType(), RecordNewCookie)
}
if !rec.IsCritical() {
t.Error("IsCritical = false; want true")
}
if !bytes.Equal(rec.Body(), body) {
t.Errorf("Body mismatch: got %x want %x", rec.Body(), body)
}
}
func TestKERecord_NonCritical(t *testing.T) {
buf := AppendKERecord(nil, false, RecordWarning, []byte{0, 1})
rec, err := NewKERecord(buf)
if err != nil {
t.Fatal(err)
}
if rec.IsCritical() {
t.Error("IsCritical = true; want false")
}
if rec.RecordType() != RecordWarning {
t.Errorf("RecordType = %v; want %v", rec.RecordType(), RecordWarning)
}
}
func TestKERecord_TruncatedBuffer(t *testing.T) {
buf := AppendKERecord(nil, true, RecordEndOfMessage, nil)
for i := range buf {
if _, err := NewKERecord(buf[:i]); err == nil {
t.Errorf("NewKERecord(buf[:%d]): expected error", i)
}
}
}
func TestKERecord_ValidateSize(t *testing.T) {
buf := AppendKERecord(nil, false, RecordAEADAlgNeg, []byte{0, 15})
rec, _ := NewKERecord(buf)
var v lneto.Validator
rec.ValidateSize(&v)
if v.HasError() {
t.Errorf("ValidateSize: unexpected error: %v", v.ErrPop())
}
}
// generateSelfSignedCert returns a TLS certificate for localhost, suitable
// for in-process testing.
func generateSelfSignedCert(t *testing.T) tls.Certificate {
t.Helper()
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
tmpl := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "localhost"},
NotBefore: time.Now().Add(-time.Hour),
NotAfter: time.Now().Add(time.Hour),
DNSNames: []string{"localhost"},
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
}
certDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key)
if err != nil {
t.Fatal(err)
}
cert, err := x509.ParseCertificate(certDER)
if err != nil {
t.Fatal(err)
}
pool := x509.NewCertPool()
pool.AddCert(cert)
return tls.Certificate{Certificate: [][]byte{certDER}, PrivateKey: key, Leaf: cert}
}
// runMockKEServer runs a minimal NTS-KE server over conn that responds with
// one cookie and the chosen algorithm.
func runMockKEServer(t *testing.T, conn net.Conn, tlsCfg *tls.Config, cookie []byte) {
t.Helper()
tc := tls.Server(conn, tlsCfg)
if err := tc.Handshake(); err != nil {
t.Errorf("server TLS handshake: %v", err)
return
}
defer tc.Close()
// Read client records until EndOfMessage.
hdr := make([]byte, 4)
for {
if _, err := tc.Read(hdr); err != nil {
return
}
bodyLen := int(binary.BigEndian.Uint16(hdr[2:4]))
recType := KERecordType(binary.BigEndian.Uint16(hdr[0:2]) & 0x7FFF)
if bodyLen > 0 {
body := make([]byte, bodyLen)
tc.Read(body)
}
if recType == RecordEndOfMessage {
break
}
}
// Send response per RFC 8915 §4.1: NextProtoNeg + AEAD + Cookie + EndOfMessage.
var resp []byte
var protoBody [2]byte
binary.BigEndian.PutUint16(protoBody[:], ntpv4ProtocolID)
resp = AppendKERecord(resp, true, RecordNextProtoNeg, protoBody[:])
var algBody [2]byte
binary.BigEndian.PutUint16(algBody[:], uint16(AlgAESSIVCMAC256))
resp = AppendKERecord(resp, true, RecordAEADAlgNeg, algBody[:])
resp = AppendKERecord(resp, false, RecordNewCookie, cookie)
resp = AppendKERecord(resp, true, RecordEndOfMessage, nil)
tc.Write(resp)
}
func TestPerformKE_E2E(t *testing.T) {
cert := generateSelfSignedCert(t)
pool := x509.NewCertPool()
leaf, _ := x509.ParseCertificate(cert.Certificate[0])
pool.AddCert(leaf)
serverCfg := &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS13,
NextProtos: []string{"ntske/1"},
}
clientCfg := &tls.Config{
RootCAs: pool,
ServerName: "localhost",
MinVersion: tls.VersionTLS13,
NextProtos: []string{"ntske/1"},
}
wantCookie := []byte("test-cookie-data-1234")
serverConn, clientConn := net.Pipe()
done := make(chan struct{})
go func() {
defer close(done)
runMockKEServer(t, serverConn, serverCfg, wantCookie)
}()
tc := tls.Client(clientConn, clientCfg)
if err := tc.Handshake(); err != nil {
t.Fatal(err)
}
secrets, err := PerformKE(tc, KEConfig{})
// Close the underlying pipe rather than tc.Close(): a TLS close_notify
// write over the synchronous net.Pipe would otherwise block on crypto/tls'
// 5s close deadline since the peer is no longer reading.
clientConn.Close()
<-done
if err != nil {
t.Fatalf("PerformKE: %v", err)
}
if secrets.NumCookies != 1 {
t.Errorf("NumCookies = %d; want 1", secrets.NumCookies)
}
if !bytes.Equal(secrets.Cookies[0][:secrets.CookieLens[0]], wantCookie) {
t.Errorf("cookie mismatch: got %q want %q",
secrets.Cookies[0][:secrets.CookieLens[0]], wantCookie)
}
if secrets.ChosenAlg != AlgAESSIVCMAC256 {
t.Errorf("ChosenAlg = %v; want %v", secrets.ChosenAlg, AlgAESSIVCMAC256)
}
// Keys must be non-zero.
var zeroKey [32]byte
if secrets.C2SKey == zeroKey || secrets.S2CKey == zeroKey {
t.Error("derived keys are all-zero")
}
}
/*
DISABLED: missing AES-SIV-CMAC-256 in stdlib
// TestClient_E2E runs a full NTS Encapsulate→Demux cycle using
// AES-SIV-CMAC-256 as the AEAD.
func TestClient_E2E(t *testing.T) {
c2sKey := make([]byte, 32)
s2cKey := make([]byte, 32)
rand.Read(c2sKey)
rand.Read(s2cKey)
c2s, _ := siv.NewAESSIVCMAC256(c2sKey)
s2c, _ := siv.NewAESSIVCMAC256(s2cKey)
cookie := []byte("nts-cookie-12345678901234")
var cfg ClientConfig
cfg.C2S = c2s
cfg.S2C = s2c
cfg.ChosenAlg = AlgAESSIVCMAC256
for i := range 2 {
copy(cfg.Cookies[i][:], cookie)
cfg.CookieLens[i] = len(cookie)
}
cfg.NumCookies = 2
baseTime := ntp.BaseTime()
clockTime := baseTime.Add(10 * time.Second)
serverOffset := 200 * time.Millisecond
cfg.Now = func() time.Time { return clockTime }
cfg.Sysprec = -20
var client Client
if err := client.Reset(cfg); err != nil {
t.Fatalf("Reset: %v", err)
}
if client.IsDone() {
t.Fatal("should not be done before exchange")
}
carrier := make([]byte, 1500)
// --- First exchange ---
n, err := client.Encapsulate(carrier, 0, 0)
if err != nil {
t.Fatalf("Encapsulate 1: %v", err)
}
if n < ntp.SizeHeader {
t.Fatalf("Encapsulate 1: n=%d too small", n)
}
// Simulate server response: build an NTP response and re-encrypt.
resp1 := buildTestResponse(t, carrier[:n], clockTime.Add(serverOffset), clockTime.Add(serverOffset+5*time.Millisecond), s2cKey)
clockTime = baseTime.Add(10*time.Second + 110*time.Millisecond)
if err = client.Demux(resp1, 0); err != nil {
t.Fatalf("Demux 1: %v", err)
}
if client.IsDone() {
t.Fatal("should not be done after first exchange only")
}
// --- Second exchange ---
carrier2 := make([]byte, 1500)
clockTime = baseTime.Add(10*time.Second + 200*time.Millisecond)
n2, err := client.Encapsulate(carrier2, 0, 0)
if err != nil {
t.Fatalf("Encapsulate 2: %v", err)
}
if n2 == 0 {
t.Fatal("Encapsulate 2 returned 0 bytes")
}
resp2 := buildTestResponse(t, carrier2[:n2], clockTime.Add(serverOffset), clockTime.Add(serverOffset+5*time.Millisecond), s2cKey)
clockTime = baseTime.Add(10*time.Second + 310*time.Millisecond)
if err = client.Demux(resp2, 0); err != nil {
t.Fatalf("Demux 2: %v", err)
}
if !client.IsDone() {
t.Fatal("should be done after second exchange")
}
if client.RoundTripDelay() < 0 {
t.Errorf("RoundTripDelay = %v; want >= 0", client.RoundTripDelay())
}
}
func TestClient_Reset_Validation(t *testing.T) {
key := make([]byte, 32)
aead, _ := siv.NewAESSIVCMAC256(key)
cookie := [MaxCookieLen]byte{}
cfg := ClientConfig{
C2S: aead, S2C: aead, NumCookies: 1,
Cookies: [MaxCookies][MaxCookieLen]byte{cookie},
CookieLens: [MaxCookies]int{8},
}
var c Client
if err := c.Reset(cfg); err != nil {
t.Fatalf("valid Reset: %v", err)
}
prevID := *c.ConnectionID()
cfg2 := cfg
cfg2.C2S = nil
if err := c.Reset(cfg2); err == nil {
t.Error("nil C2S: expected error")
}
if *c.ConnectionID() != prevID {
t.Error("connID should not increment on failed Reset")
}
cfg3 := cfg
cfg3.NumCookies = 0
if err := c.Reset(cfg3); err == nil {
t.Error("zero cookies: expected error")
}
}
func TestClient_ExhaustedCookies(t *testing.T) {
key := make([]byte, 32)
aead, _ := siv.NewAESSIVCMAC256(key)
cfg := ClientConfig{
C2S: aead, S2C: aead, NumCookies: 1,
Cookies: [MaxCookies][MaxCookieLen]byte{[MaxCookieLen]byte{}},
CookieLens: [MaxCookies]int{8},
}
var c Client
c.Reset(cfg)
carrier := make([]byte, 1500)
if _, err := c.Encapsulate(carrier, 0, 0); err != nil {
t.Fatalf("first Encapsulate: %v", err)
}
if c.numCookies != 0 {
t.Fatalf("numCookies = %d; want 0", c.numCookies)
}
if _, err := c.Encapsulate(carrier, 0, 0); err != lneto.ErrExhausted {
t.Errorf("second Encapsulate: got %v; want ErrExhausted", err)
}
}
func TestClient_DemuxBadTag(t *testing.T) {
key := make([]byte, 32)
aead, _ := siv.NewAESSIVCMAC256(key)
cookie := make([]byte, 16)
var cookies [MaxCookies][MaxCookieLen]byte
copy(cookies[0][:], cookie)
cfg := ClientConfig{
C2S: aead, S2C: aead, NumCookies: 1,
Cookies: cookies,
CookieLens: [MaxCookies]int{16},
}
var c Client
c.Reset(cfg)
carrier := make([]byte, 1500)
n, _ := c.Encapsulate(carrier, 0, 0)
resp := buildTestResponse(t, carrier[:n],
time.Now(), time.Now().Add(time.Millisecond), key)
// Tamper a byte in the NTP header (part of the AAD); this must cause
// the authentication tag to be rejected.
resp[ntp.SizeHeader-1] ^= 0xff
if err := c.Demux(resp, 0); err != lneto.ErrBadCRC {
t.Errorf("tampered Demux: got %v; want ErrBadCRC", err)
}
}
// buildTestResponse constructs a minimal NTS-authenticated NTP server response
// by echoing the client's UniqueID and re-sealing with s2cKey.
// The returned slice contains exactly the response bytes (no trailing zeros).
func buildTestResponse(t *testing.T, request []byte, serverRecv, serverXmt time.Time, s2cKey []byte) []byte {
t.Helper()
reqFrm, err := ntp.NewFrame(request)
if err != nil {
t.Fatal(err)
}
// Extract the Unique-ID from the request so the response can echo it.
var uniqueID []byte
extBuf := reqFrm.ExtensionFields()
for off := 0; off < len(extBuf); {
field, n, e := ntp.NextExtField(extBuf[off:])
if e != nil || len(field.RawData()) == 0 {
break
}
if field.Type() == ntp.ExtNTSUniqueID {
uniqueID = field.Value()
break
}
off += n
}
// Build response in a new buffer.
resp := make([]byte, 1500)
respFrm, _ := ntp.NewFrame(resp)
respFrm.SetFlags(ntp.ModeServer, ntp.Version4, ntp.LeapNoWarning)
respFrm.SetStratum(ntp.StratumPrimary)
respFrm.SetPrecision(-20)
respFrm.SetOriginTime(reqFrm.TransmitTime())
recvTS, _ := ntp.TimestampFromTime(serverRecv)
xmtTS, _ := ntp.TimestampFromTime(serverXmt)
respFrm.SetReceiveTime(recvTS)
respFrm.SetTransmitTime(xmtTS)
// Append UniqueID extension field (echo).
respBuf := resp[:ntp.SizeHeader]
if len(uniqueID) > 0 {
respBuf = ntp.AppendExtField(respBuf, ntp.ExtNTSUniqueID, uniqueID)
}
// Build NTS-Auth field sealed with S2C key.
s2c, err := siv.NewAESSIVCMAC256(s2cKey)
if err != nil {
t.Fatal(err)
}
nonceLen := s2c.NonceSize()
overhead := s2c.Overhead()
var nonce [maxNonceLen]byte
rand.Read(nonce[:nonceLen])
aad := respBuf
var authBody [maxAuthBody]byte
binary.BigEndian.PutUint16(authBody[0:2], uint16(nonceLen))
binary.BigEndian.PutUint16(authBody[2:4], uint16(overhead))
copy(authBody[4:4+nonceLen], nonce[:nonceLen])
s2c.Seal(authBody[4+nonceLen:4+nonceLen], nonce[:nonceLen], nil, aad)
respBuf = ntp.AppendExtField(respBuf, ntp.ExtNTSAuthAndEEF, authBody[:4+nonceLen+overhead])
result := make([]byte, len(respBuf))
copy(result, respBuf)
return result
}
*/
func FuzzKERecord(f *testing.F) {
// Seed with valid records.
f.Add(AppendKERecord(nil, true, RecordEndOfMessage, nil))
f.Add(AppendKERecord(nil, false, RecordNewCookie, []byte("cookie")))
f.Add(AppendKERecord(nil, true, RecordAEADAlgNeg, []byte{0, 15}))
// Seed with short inputs.
f.Add([]byte{})
f.Add([]byte{0x80, 0x01})
f.Fuzz(func(t *testing.T, data []byte) {
rec, err := NewKERecord(data)
if err != nil {
return
}
var v lneto.Validator
rec.ValidateSize(&v)
_ = rec.RecordType()
_ = rec.IsCritical()
_ = rec.Body()
})
}
func FuzzNextExtField(f *testing.F) {
f.Add(ntp.AppendExtField(nil, ntp.ExtNTSUniqueID, make([]byte, 32)))
f.Add(ntp.AppendExtField(nil, ntp.ExtNTSCookie, make([]byte, 64)))
f.Add([]byte{})
f.Add([]byte{0, 1, 0, 0})
f.Fuzz(func(t *testing.T, data []byte) {
field, n, _ := ntp.NextExtField(data)
_ = field.RawData()
_ = n
})
}
/*
DISABLED: depends on github.com/soypat/lneto/x/siv (see note above).
func TestServer_Reset_Validation(t *testing.T) {
key := make([]byte, 32)
aead, _ := siv.NewAESSIVCMAC256(key)
var s Server
if err := s.Reset(ServerConfig{C2S: aead, S2C: aead, Stratum: ntp.StratumPrimary}); err != nil {
t.Fatalf("valid Reset: %v", err)
}
prevID := *s.ConnectionID()
if err := s.Reset(ServerConfig{C2S: nil, S2C: aead}); err == nil {
t.Error("nil C2S: expected error")
}
if *s.ConnectionID() != prevID {
t.Error("connID should not increment on failed Reset")
}
}
func TestServer_NoPendingReturnsZero(t *testing.T) {
key := make([]byte, 32)
aead, _ := siv.NewAESSIVCMAC256(key)
var s Server
s.Reset(ServerConfig{C2S: aead, S2C: aead, Stratum: ntp.StratumPrimary})
carrier := make([]byte, 1500)
n, err := s.Encapsulate(carrier, 0, 0)
if err != nil {
t.Fatal(err)
}
if n != 0 {
t.Fatalf("expected 0, got %d", n)
}
}
func TestClientServer_E2E(t *testing.T) {
c2sKey := make([]byte, 32)
s2cKey := make([]byte, 32)
rand.Read(c2sKey)
rand.Read(s2cKey)
c2s, _ := siv.NewAESSIVCMAC256(c2sKey)
s2c, _ := siv.NewAESSIVCMAC256(s2cKey)
cookie := []byte("nts-cookie-round-trip-test")
baseTime := ntp.BaseTime()
clientTime := baseTime.Add(10 * time.Second)
serverTime := clientTime.Add(200 * time.Millisecond)
var clientCfg ClientConfig
clientCfg.C2S = c2s
clientCfg.S2C = s2c
clientCfg.ChosenAlg = AlgAESSIVCMAC256
clientCfg.Now = func() time.Time { return clientTime }
clientCfg.Sysprec = -20
for i := range 2 {
copy(clientCfg.Cookies[i][:], cookie)
clientCfg.CookieLens[i] = len(cookie)
}
clientCfg.NumCookies = 2
var client Client
if err := client.Reset(clientCfg); err != nil {
t.Fatal(err)
}
// Server uses same keys (C2S to verify client, S2C to seal responses).
var server Server
if err := server.Reset(ServerConfig{
C2S: c2s,
S2C: s2c,
Now: func() time.Time { return serverTime },
Stratum: ntp.StratumPrimary,
Prec: -20,
RefID: [4]byte{'G', 'P', 'S', 0},
}); err != nil {
t.Fatal(err)
}
for exchange := range 2 {
carrier := make([]byte, 1500)
n, err := client.Encapsulate(carrier, 0, 0)
if err != nil || n == 0 {
t.Fatalf("exchange %d: client Encapsulate: n=%d err=%v", exchange, n, err)
}
if err = server.Demux(carrier[:n], 0); err != nil {
t.Fatalf("exchange %d: server Demux: %v", exchange, err)
}
resp := make([]byte, 1500)
rn, err := server.Encapsulate(resp, 0, 0)
if err != nil || rn == 0 {
t.Fatalf("exchange %d: server Encapsulate: rn=%d err=%v", exchange, rn, err)
}
clientTime = clientTime.Add(100 * time.Millisecond)
serverTime = serverTime.Add(100 * time.Millisecond)
if err = client.Demux(resp[:rn], 0); err != nil {
t.Fatalf("exchange %d: client Demux: %v", exchange, err)
}
}
if !client.IsDone() {
t.Fatal("client should be done after two exchanges")
}
if client.RoundTripDelay() < 0 {
t.Errorf("RTD = %v; want >= 0", client.RoundTripDelay())
}
}
func TestClientServer_TamperedAADRejected(t *testing.T) {
c2sKey := make([]byte, 32)
s2cKey := make([]byte, 32)
rand.Read(c2sKey)
rand.Read(s2cKey)
c2s, _ := siv.NewAESSIVCMAC256(c2sKey)
s2c, _ := siv.NewAESSIVCMAC256(s2cKey)
cookie := []byte("cookie-tamper-test")
var cfg ClientConfig
cfg.C2S = c2s
cfg.S2C = s2c
cfg.NumCookies = 1
copy(cfg.Cookies[0][:], cookie)
cfg.CookieLens[0] = len(cookie)
var client Client
client.Reset(cfg)
carrier := make([]byte, 1500)
n, _ := client.Encapsulate(carrier, 0, 0)
// Tamper with NTP header (part of AAD).
carrier[ntp.SizeHeader-1] ^= 0xff
var server Server
server.Reset(ServerConfig{C2S: c2s, S2C: s2c, Stratum: ntp.StratumPrimary})
if err := server.Demux(carrier[:n], 0); err != lneto.ErrBadCRC {
t.Errorf("tampered Demux: got %v; want ErrBadCRC", err)
}
}
*/
func TestHandleKE_E2E(t *testing.T) {
cert := generateSelfSignedCert(t)
pool := x509.NewCertPool()
leaf, _ := x509.ParseCertificate(cert.Certificate[0])
pool.AddCert(leaf)
serverTLSCfg := &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS13,
NextProtos: []string{"ntske/1"},
}
clientTLSCfg := &tls.Config{
RootCAs: pool,
ServerName: "localhost",
MinVersion: tls.VersionTLS13,
NextProtos: []string{"ntske/1"},
}
wantCookie := []byte("ke-server-cookie-data")
serverConn, clientConn := net.Pipe()
done := make(chan KESecrets, 1)
errc := make(chan error, 1)
go func() {
tc := tls.Server(serverConn, serverTLSCfg)
if err := tc.Handshake(); err != nil {
errc <- err
return
}
defer tc.Close()
secrets, err := HandleKE(tc, KEServerConfig{
Cookies: [][]byte{wantCookie},
})
if err != nil {
errc <- err
return
}
done <- secrets
}()
tc := tls.Client(clientConn, clientTLSCfg)
if err := tc.Handshake(); err != nil {
t.Fatal(err)
}
clientSecrets, err := PerformKE(tc, KEConfig{})
// Close the underlying pipe rather than tc.Close(): a TLS close_notify
// write over the synchronous net.Pipe would otherwise block on crypto/tls'
// 5s close deadline since the peer is no longer reading.
clientConn.Close()
select {
case err := <-errc:
t.Fatalf("server KE: %v", err)
case serverSecrets := <-done:
if err != nil {
t.Fatalf("client KE: %v", err)
}
if clientSecrets.ChosenAlg != serverSecrets.ChosenAlg {
t.Errorf("ChosenAlg: client=%v server=%v; want equal", clientSecrets.ChosenAlg, serverSecrets.ChosenAlg)
}
if clientSecrets.C2SKey != serverSecrets.C2SKey {
t.Errorf("C2SKey mismatch: client and server derived different keys")
}
if clientSecrets.S2CKey != serverSecrets.S2CKey {
t.Errorf("S2CKey mismatch: client and server derived different keys")
}
if clientSecrets.NumCookies != 1 {
t.Errorf("NumCookies = %d; want 1", clientSecrets.NumCookies)
}
gotCookie := clientSecrets.Cookies[0][:clientSecrets.CookieLens[0]]
if !bytes.Equal(gotCookie, wantCookie) {
t.Errorf("cookie = %q; want %q", gotCookie, wantCookie)
}
case <-time.After(10 * time.Second):
t.Fatal("HandleKE server goroutine timed out")
}
}
/*
DISABLED: missing AES-SIV-CMAC-256 in stdlib
func FuzzServerDemux(f *testing.F) {
key := make([]byte, 32)
aead, _ := siv.NewAESSIVCMAC256(key)
// Seed with a valid NTS request built by the client.
var c Client
c.Reset(ClientConfig{
C2S: aead, S2C: aead, NumCookies: 1,
Cookies: [MaxCookies][MaxCookieLen]byte{},
CookieLens: [MaxCookies]int{16},
})
carrier := make([]byte, 1500)
n, _ := c.Encapsulate(carrier, 0, 0)
if n > 0 {
f.Add(carrier[:n])
}
f.Add(make([]byte, ntp.SizeHeader))
f.Add([]byte{})
f.Add(make([]byte, 10))
f.Fuzz(func(t *testing.T, data []byte) {
fuzzKey := make([]byte, 32)
fuzzAEAD, _ := siv.NewAESSIVCMAC256(fuzzKey)
var s Server
s.Reset(ServerConfig{C2S: fuzzAEAD, S2C: fuzzAEAD, Stratum: ntp.StratumPrimary})
_ = s.Demux(data, 0)
})
}
func BenchmarkClient_Encapsulate(b *testing.B) {
key := make([]byte, 32)
aead, _ := siv.NewAESSIVCMAC256(key)
carrier := make([]byte, 1500)
var c Client
newCfg := func() ClientConfig {
var cookies [MaxCookies][MaxCookieLen]byte
var lens [MaxCookies]int
for i := range cookies {
copy(cookies[i][:], make([]byte, 32))
lens[i] = 32
}
return ClientConfig{
C2S: aead, S2C: aead, ChosenAlg: AlgAESSIVCMAC256,
NumCookies: MaxCookies, Cookies: cookies, CookieLens: lens,
Now: time.Now,
}
}
c.Reset(newCfg())
b.ResetTimer()
for b.Loop() {
if c.numCookies == 0 {
c.Reset(newCfg())
}
c.Encapsulate(carrier, 0, 0)
}
}
*/