Documentation
¶
Overview ¶
Package security provides pluggable transport-security for go-DDS.
Security is applied at the packet level in the RTPS transport: every outbound payload is passed through Plugin.Seal before transmission, and every inbound payload through Plugin.Open before delivery to the application. The mock transport passes payloads through the plugin at the broker level so tests can use the same Plugin implementations without a live network.
Two built-in plugins are provided:
- NullPlugin — identity transform; no confidentiality, no integrity. Use during development and for interop with non-secured peers.
- HMACPlugin — appends an HMAC-SHA-256 tag to each payload. Provides integrity and authentication without confidentiality. Fast; zero payload expansion overhead beyond the 32-byte tag.
- AESGCMPlugin — encrypts with AES-256-GCM (AEAD). Provides full confidentiality, integrity, and authenticity. Payload expands by 12 bytes (nonce) + 16 bytes (GCM tag) = 28 bytes.
Index ¶
- Variables
- func NewRandomKey(n int) []byte
- type AESGCMPlugin
- type AccessPolicy
- type CertPlugin
- type DiscoveryPlugin
- type HMACDiscoveryPlugin
- func (h *HMACDiscoveryPlugin) Rekey(newKey []byte)
- func (h *HMACDiscoveryPlugin) SignDiscovery(guidPrefix []byte) []byte
- func (h *HMACDiscoveryPlugin) SignEndpoint(guidPrefix []byte, topic string) []byte
- func (h *HMACDiscoveryPlugin) VerifyDiscovery(guidPrefix, tag []byte) bool
- func (h *HMACDiscoveryPlugin) VerifyEndpoint(guidPrefix []byte, topic string, tag []byte) bool
- type HMACPlugin
- type NullPlugin
- type Permission
- type Plugin
- type ReplayGuard
- type Rule
Constants ¶
This section is empty.
Variables ¶
var ErrReplay = errors.New("security: replayed sequence number detected")
ErrReplay is returned by ReplayGuard.Check when a sequence number has already been accepted within the replay window.
Functions ¶
func NewRandomKey ¶
NewRandomKey returns n cryptographically random bytes suitable for use as a plugin key. Panics if the OS random source fails (this should never happen on any supported platform).
Types ¶
type AESGCMPlugin ¶
type AESGCMPlugin struct {
// contains filtered or unexported fields
}
AESGCMPlugin encrypts payloads with AES-256-GCM (authenticated encryption). It provides confidentiality, integrity, and authenticity. Each Seal call generates a fresh 12-byte random nonce prepended to the ciphertext.
Wire format: | nonce[12] | ciphertext... | GCM-tag[16] |
Payload overhead: 28 bytes per sample.
func NewAESGCMPlugin ¶
func NewAESGCMPlugin(key []byte) (*AESGCMPlugin, error)
NewAESGCMPlugin creates an AESGCMPlugin. key must be exactly 32 bytes (AES-256); use NewRandomKey to generate one.
type AccessPolicy ¶ added in v0.9.0
type AccessPolicy struct {
// contains filtered or unexported fields
}
AccessPolicy enforces topic-level read/write permissions. Rules are evaluated in order; the first matching rule wins. A topic that matches no rule is denied all access.
func NewAccessPolicy ¶ added in v0.9.0
func NewAccessPolicy(rules ...Rule) *AccessPolicy
NewAccessPolicy creates an AccessPolicy from the given rules. Rules are evaluated in declaration order — the first match wins.
func (*AccessPolicy) CanRead ¶ added in v0.9.0
func (p *AccessPolicy) CanRead(topic string) bool
CanRead returns true if any rule grants PermRead on topic.
func (*AccessPolicy) CanWrite ¶ added in v0.9.0
func (p *AccessPolicy) CanWrite(topic string) bool
CanWrite returns true if any rule grants PermWrite on topic.
type CertPlugin ¶ added in v0.9.0
type CertPlugin struct {
// contains filtered or unexported fields
}
CertPlugin provides asymmetric signing and verification using X.509 certificates and ECDSA private keys.
Seal appends the signer's DER-encoded certificate and an ECDSA signature over SHA-256(plaintext) to the payload, allowing any peer holding a certificate issued by the trusted CA to verify the message.
Wire format (length fields trail their data so parsing from the end is O(1)):
| plaintext | certDER | certLen uint32 BE | sigDER | sigLen uint32 BE |
This provides integrity and peer authentication but NOT confidentiality. Combine with AESGCMPlugin when confidentiality is required.
func NewCertPlugin ¶ added in v0.9.0
func NewCertPlugin(certPEM, keyPEM, caPEM []byte) (*CertPlugin, error)
NewCertPlugin creates a CertPlugin from PEM-encoded certificate, private key, and CA certificate(s). The private key must be ECDSA.
certPEM — PEM block containing the signer's leaf certificate (CERTIFICATE) keyPEM — PEM block containing the signer's ECDSA private key (EC PRIVATE KEY) caPEM — PEM block(s) containing the trusted CA certificate(s)
func (*CertPlugin) Open ¶ added in v0.9.0
func (p *CertPlugin) Open(data []byte) ([]byte, error)
Open verifies the signature appended by Seal and returns the original plaintext. Returns an error if the certificate is not trusted by the CA pool, if the signature is invalid, or if the payload is malformed.
type DiscoveryPlugin ¶ added in v0.9.1
type DiscoveryPlugin interface {
// SignDiscovery returns an authentication tag for guidPrefix (12 bytes).
// The tag is embedded in outbound SPDP announcements as PID 0x8001.
SignDiscovery(guidPrefix []byte) []byte
// VerifyDiscovery returns true when tag is a valid authentication token
// for the given guidPrefix. A nil or empty tag must return false.
VerifyDiscovery(guidPrefix, tag []byte) bool
}
DiscoveryPlugin signs and verifies SPDP participant-discovery announcements. Use with rtps.WithDiscoverySecurity to authenticate the discovery layer.
Only go-DDS participants configured with compatible plugins accept each other's discovery announcements; unauthenticated or wrongly-signed peers are silently discarded at the SPDP layer.
type HMACDiscoveryPlugin ¶ added in v0.9.1
type HMACDiscoveryPlugin struct {
// contains filtered or unexported fields
}
HMACDiscoveryPlugin authenticates SPDP announcements using HMAC-SHA-256. All participants in a discovery group must share the same key.
Usage:
plugin := security.NewHMACDiscoveryPlugin([]byte("shared-secret"))
p, err := rtps.New(0, rtps.WithDiscoverySecurity(plugin))
func NewHMACDiscoveryPlugin ¶ added in v0.9.1
func NewHMACDiscoveryPlugin(key []byte) *HMACDiscoveryPlugin
NewHMACDiscoveryPlugin returns an HMACDiscoveryPlugin keyed with key. The key is copied; the caller may discard or reuse the slice.
func (*HMACDiscoveryPlugin) Rekey ¶ added in v0.11.0
func (h *HMACDiscoveryPlugin) Rekey(newKey []byte)
Rekey atomically replaces the HMAC key. Ongoing sign/verify operations complete before the key is swapped; subsequent operations use the new key. The new key is copied; the caller may discard or reuse the slice.
func (*HMACDiscoveryPlugin) SignDiscovery ¶ added in v0.9.1
func (h *HMACDiscoveryPlugin) SignDiscovery(guidPrefix []byte) []byte
SignDiscovery returns an HMAC-SHA-256 tag for guidPrefix.
func (*HMACDiscoveryPlugin) SignEndpoint ¶ added in v0.10.0
func (h *HMACDiscoveryPlugin) SignEndpoint(guidPrefix []byte, topic string) []byte
SignEndpoint returns an HMAC-SHA-256 tag for the endpoint identified by guidPrefix and topic. Implements rtps.EndpointPlugin.
func (*HMACDiscoveryPlugin) VerifyDiscovery ¶ added in v0.9.1
func (h *HMACDiscoveryPlugin) VerifyDiscovery(guidPrefix, tag []byte) bool
VerifyDiscovery returns true when tag matches the expected HMAC for guidPrefix.
func (*HMACDiscoveryPlugin) VerifyEndpoint ¶ added in v0.10.0
func (h *HMACDiscoveryPlugin) VerifyEndpoint(guidPrefix []byte, topic string, tag []byte) bool
VerifyEndpoint returns true when tag matches the expected HMAC for the endpoint identified by guidPrefix and topic. Implements rtps.EndpointPlugin.
type HMACPlugin ¶
type HMACPlugin struct {
// contains filtered or unexported fields
}
HMACPlugin appends an HMAC-SHA-256 authentication tag to each payload. It provides integrity and peer authentication but NOT confidentiality — the payload travels in plaintext. Use when eavesdropping is not a concern but tampering or spoofing must be detected.
Wire format: | plaintext... | HMAC[32] |
func NewHMACPlugin ¶
func NewHMACPlugin(key []byte) *HMACPlugin
NewHMACPlugin creates an HMACPlugin keyed with key. The key should be at least 32 bytes of random data; use NewRandomKey to generate one.
type NullPlugin ¶
type NullPlugin struct{}
NullPlugin is the identity transform: Seal and Open return the input unchanged. Use it when no security is required (e.g. development, testing, or within a trusted private network).
type Permission ¶ added in v0.9.0
type Permission uint8
Permission is a bitfield of allowed operations on a topic.
const ( // PermRead grants read access (subscribe) to a topic. PermRead Permission = 1 << 0 // PermWrite grants write access (publish) to a topic. PermWrite Permission = 1 << 1 // PermReadWrite grants both read and write access. PermReadWrite = PermRead | PermWrite )
type Plugin ¶
type Plugin interface {
// Seal transforms plaintext into a protected form ready for transmission.
// The returned slice may share memory with plaintext or be newly allocated.
Seal(plaintext []byte) ([]byte, error)
// Open reverses Seal, returning the original plaintext. Returns an error
// if the payload is invalid, tampered, or cannot be decrypted.
Open(ciphertext []byte) ([]byte, error)
}
Plugin is implemented by any type that can seal (encrypt / sign) and open (decrypt / verify) a DDS payload. Seal and Open must be inverses:
plaintext == must(Open(must(Seal(plaintext))))
Implementations must be safe for concurrent use from multiple goroutines.
type ReplayGuard ¶ added in v0.9.0
type ReplayGuard struct {
// contains filtered or unexported fields
}
ReplayGuard protects against replay attacks by tracking recently-seen sequence numbers within a sliding time window.
Each sequence number is associated with the timestamp of the message that carried it. A sequence number is considered a replay if it has been seen within window duration of the current call.
ReplayGuard is safe for concurrent use from multiple goroutines.
func NewReplayGuard ¶ added in v0.9.0
func NewReplayGuard(window time.Duration) *ReplayGuard
NewReplayGuard creates a ReplayGuard with the given sliding window. A window of 0 or negative is replaced with 30 seconds.
func (*ReplayGuard) Check ¶ added in v0.9.0
func (g *ReplayGuard) Check(seq uint64, ts time.Time) error
Check reports whether seq is a replay. If seq has not been seen within window of ts, it is recorded and nil is returned. If seq has already been seen within the window, ErrReplay is returned.
ts is the claimed send timestamp of the message. Entries whose recorded timestamp is more than window before ts are pruned on each Check call.
func (*ReplayGuard) Len ¶ added in v0.9.0
func (g *ReplayGuard) Len() int
Len returns the number of sequence numbers currently tracked.
func (*ReplayGuard) Purge ¶ added in v0.9.0
func (g *ReplayGuard) Purge()
Purge removes all entries older than window before time.Now(). Check calls Purge automatically; call this method explicitly only when driving the clock externally (e.g. in tests).
type Rule ¶ added in v0.9.0
type Rule struct {
Pattern string
Allow Permission
}
Rule pairs a topic pattern with the permissions it grants.
Pattern follows the semantics of path.Match:
- '*' matches any sequence of non-'/' characters (one path segment)
- '?' matches any single non-'/' character
- '[abc]' matches a character class
- Exact strings match literally
Examples:
Rule{Pattern: "vehicle/speed", Allow: PermRead} // exact match, read-only
Rule{Pattern: "vehicle/*", Allow: PermReadWrite} // any single-segment child
Rule{Pattern: "*", Allow: PermRead} // any top-level topic