feat(gateway): validate encrypted Apollo RTSP frames
Verify Data Plane / gateway (push) Canceled after 1m42s

This commit is contained in:
sechmachine
2026-07-29 11:32:56 +07:00
parent 844e548c95
commit 994fe38fb9
6 changed files with 146 additions and 3 deletions
+56
View File
@@ -0,0 +1,56 @@
package gateway
import (
"crypto/aes"
"crypto/cipher"
"encoding/binary"
"testing"
)
func TestEncryptedRTSPRejectsTagReplayAndReorderedHostFrames(t *testing.T) {
key := []byte("0123456789abcdef")
codec, err := newEncryptedRTSPCodec(key)
if err != nil {
t.Fatal(err)
}
first := hostEncryptedRTSPFrame(t, key, 1, []byte("RTSP/1.0 200 OK\r\n\r\n"))
if plaintext, err := codec.OpenHost(first); err != nil || string(plaintext) != "RTSP/1.0 200 OK\r\n\r\n" {
t.Fatalf("OpenHost() = %q, %v", plaintext, err)
}
if _, err := codec.OpenHost(first); err == nil {
t.Fatal("OpenHost() accepted a replayed frame")
}
tampered := hostEncryptedRTSPFrame(t, key, 2, []byte("RTSP/1.0 200 OK\r\n\r\n"))
tampered[len(tampered)-1] ^= 0x01
if _, err := codec.OpenHost(tampered); err == nil {
t.Fatal("OpenHost() accepted a tag failure")
}
third := hostEncryptedRTSPFrame(t, key, 3, []byte("RTSP/1.0 200 OK\r\n\r\n"))
if _, err := codec.OpenHost(third); err != nil {
t.Fatalf("OpenHost() sequence 3 error = %v", err)
}
second := hostEncryptedRTSPFrame(t, key, 2, []byte("RTSP/1.0 200 OK\r\n\r\n"))
if _, err := codec.OpenHost(second); err == nil {
t.Fatal("OpenHost() accepted an out-of-order frame")
}
}
func hostEncryptedRTSPFrame(t *testing.T, key []byte, sequence uint32, plaintext []byte) []byte {
t.Helper()
block, err := aes.NewCipher(key)
if err != nil {
t.Fatal(err)
}
aead, err := cipher.NewGCM(block)
if err != nil {
t.Fatal(err)
}
nonce := encryptedRTSPNonce(sequence, 'H', 'R')
sealed := aead.Seal(nil, nonce[:], plaintext, nil)
frame := make([]byte, encryptedRTSPHeaderSize+len(plaintext))
binary.BigEndian.PutUint32(frame[:4], uint32(len(plaintext))|0x80000000)
binary.BigEndian.PutUint32(frame[4:8], sequence)
copy(frame[8:24], sealed[len(plaintext):])
copy(frame[24:], sealed[:len(plaintext)])
return frame
}