Documentation
¶
Overview ¶
Package psp implements the PSP-model cryptographic primitives shared by the icx data plane (package icx) and the key-establishment control plane (package control): the NIST SP 800-108 / AES-CMAC key-derivation function from the PSP Architecture Specification, and the SPI bit layout that partitions the derivation space by master key and allocating role.
The package is a stdlib-only leaf so the data-plane handler can derive its own security-association keys without importing the control plane (and its QUIC/x509 dependency tree).
Index ¶
- Constants
- func DeriveSAKey(masterKey []byte, spi uint32, v ICXVersion) ([]byte, error)
- func EpochSPIs(local Role, epoch uint32) (rxSPI, txSPI uint32, err error)
- func MakeSPI(masterKeyIndex int, role Role, counter uint32) (uint32, error)
- func MasterKeyIndex(spi uint32) int
- func ReservedSPI(spi uint32) bool
- type ICXVersion
- type Role
Constants ¶
const MasterKeyLen = 32
MasterKeyLen is the required length of a PSP master key (256 bits). PSP master keys are always AES-256 keys regardless of the SA key size.
const NumMasterKeys = 2
NumMasterKeys is the PSP master-key count: one active, one retained for in-flight SAs during rotation (the MSB of the SPI selects between them).
const ( // SPICounterMax is the largest usable per-(index,role) counter value // (2^30-1); 0 is reserved. SPICounterMax = (uint32(1) << spiRoleShift) - 1 )
SPI bit layout (PSP keeps the SPI opaque except for the MSB master-key selector; we additionally reserve one bit to partition by allocating role):
bit31 master-key index (PSP) bit30 allocating role (0=initiator, 1=responder) bits[29:0] per-(index,role) counter, 1..2^30-1 (0 reserved)
Variables ¶
This section is empty.
Functions ¶
func DeriveSAKey ¶
func DeriveSAKey(masterKey []byte, spi uint32, v ICXVersion) ([]byte, error)
DeriveSAKey derives a PSP security-association key from a 256-bit master key and a 32-bit SPI, exactly per the PSP Architecture Specification: a NIST SP 800-108 counter-mode KDF whose PRF is AES-CMAC (see cmac.go). Each PRF input block is the 16-byte concatenation
counter(4) || label(4) || context=SPI(4) || length-in-bits(4)
all in network byte order. A 128-bit key needs one block (counter=1); a 256-bit key needs two (counter=1, counter=2) concatenated.
The caller is responsible for selecting which master key to pass based on the SPI's most-significant bit (the PSP master-key selector); the SPI is fed into the KDF context verbatim, MSB included, so the derivation is bound to it.
func EpochSPIs ¶
EpochSPIs maps a symmetric per-connection (epoch, role) pair onto the SPI layout at master-key index 0: the local receive SPI carries the local role's bit, the transmit SPI the peer role's bit, both with counter = epoch. The two peers of a connection call it with opposite roles and the same epoch and obtain mirrored (rxSPI, txSPI) pairs, so each direction derives a distinct key from the shared master secret. Errors if epoch is 0 or above SPICounterMax; it never truncates.
func MakeSPI ¶
MakeSPI composes an SPI from the active master-key index, the allocating role and a per-(index,role) counter.
func MasterKeyIndex ¶
MasterKeyIndex returns which master key (0 or 1) an SPI selects: per PSP, the most-significant bit of the SPI.
func ReservedSPI ¶
ReservedSPI reports whether spi is reserved (low 31 bits zero). PSP reserves the all-zero counter in each master-key half; installs must reject it.
Types ¶
type ICXVersion ¶
type ICXVersion uint8
ICXVersion is an AEAD cipher-suite codepoint for an SA. It selects both the AEAD (AES-GCM-128 vs AES-GCM-256) and, via the KDF label, the size of the derived security-association key. It is a local cipher selector, not a wire-format version (that is ProtocolVersion in the control plane).
const ( // AESGCM128 selects AES-GCM-128: a 16-byte SA key. The ICX default (zero // churn to the [16]byte data plane). AESGCM128 ICXVersion = 0 // AESGCM256 selects AES-GCM-256: a 32-byte SA key. The CNSA / 256-bit path. AESGCM256 ICXVersion = 1 )
func (ICXVersion) KeyLen ¶
func (v ICXVersion) KeyLen() int
KeyLen returns the derived SA key length in bytes for the version: 16 for AESGCM128, 32 for AESGCM256. Only valid versions reach the KDF (guarded by DeriveSAKey).
func (ICXVersion) Valid ¶
func (v ICXVersion) Valid() bool
Valid reports whether v is a supported cipher suite. Callers must reject unsupported versions before deriving keys (fail-closed), so KeyLen/label are never asked to map an unknown version.
type Role ¶
type Role uint8
Role identifies which peer allocated an SPI. The two directions MUST use distinct SPIs, otherwise both directions would derive the same key (txKey == rxKey). Partitioning the SPI space by role guarantees distinctness even though both peers allocate independently from the shared master keys.