Summary

  • RFC 2367 put a privileged socket API between a key-management application and the local Key Engine. Its replies describe that local interface and database, not a completed security outcome across two endpoints.
  • SADB_GET, SADB_DUMP and the states LARVAL, MATURE, DYING and DEAD are bounded records. MATURE means an SA was added or updated locally; it does not prove peer authentication, current policy applicability or packet use.
  • A defensible result joins caller authority, PF_KEY transaction, local SA, key custody, remote negotiation, policy selection, per-packet AH/ESP processing, remote receipt and application evidence without allowing one layer to impersonate the next.

The important diagram in RFC 2367 has three paths, not one. A key-management daemon speaks PF_KEY to a local Key Engine. The same daemon uses PF_INET or PF_INET6 to communicate with a remote key-management entity. Kernel IPsec processing reaches the Key Engine through another internal interface. A successful event on the first path cannot silently testify for the other two.

That separation made PF_KEY portable. A trusted application could add a complete SA with SADB_ADD, reserve an SPI and finish it with SADB_UPDATE, retrieve it with SADB_GET, or request creation after SADB_ACQUIRE. The API could also report expiration, delete one entry, flush a class, and expose the table for debugging. It standardized a local control surface without pretending to standardize every key exchange, policy engine or packet outcome.

“Mature” names a database transition

The four state names sound operationally conclusive. They are narrower. LARVAL follows SADB_GETSPI; MATURE follows an update or add; DYING records soft-lifetime expiry; DEAD records hard-lifetime expiry before collection. The state answers what happened to one local record. It does not say that the remote endpoint installed its directional companion, that an authenticated identity was authorised for the traffic selectors, or that a packet ever selected the SA.

The same limit applies to fields. An SPI is a lookup coordinate, not a credential. An algorithm identifier says which operation is configured, not that its key remained protected or that processing succeeded. A lifetime counter is local accounting, not bilateral freshness. RFC 2367 even permits zero to mean that authentication or encryption is not used for a given SA. Reading the row accurately therefore matters more than finding reassuring words in it.

SADB_DUMP is the most tempting shortcut. It can return the operating system’s entire Key Table, one SA per message, followed by an end marker. Yet the RFC calls the operation debugging-only, not intended for production use, and says key-management applications must not depend on it for basic operation. A dump is a situated snapshot. It can be incomplete when messages are dropped, stale relative to policy, or accurate locally while the peer has already diverged.

Message transport has its own caveat: PF_KEY delivery is not guaranteed, especially when kernel or socket buffers are exhausted. Most errors arrive in reply messages. A monitor that records only successful rows but loses an error, expiration or deletion notice can construct a cleaner history than the system actually produced.

The privileged caller is part of the proof

PF_KEY was not designed for an ordinary application. Only trusted, privileged processes were to open the raw socket. The manual interface gives those processes broad control over local SAs. RFC 2367’s security considerations are blunt: if an unprivileged user can create, read, modify or delete this state, the operating system cannot provide the related security service.

The audit must therefore begin before the SA. Which executable opened the socket? Under which identity and configuration generation? Who authorised the change? Where did plaintext key material exist? Which process could retrieve it? A correct SADB_UPDATE from the wrong authority is not a secure result. Nor does a broadcast reply prove key custody: RFC 2367 deliberately omits keying material from returned update messages because some listeners may not be allowed to see it.

Policy, negotiation and packets remain separate

Later IPsec architecture sharpens the missing joins. RFC 4301 gives the SPD choices BYPASS, DISCARD and PROTECT; the SAD supplies parameters only after policy selects protection. SAD entries can survive changes to the SPD, and manually keyed entries may exist without a corresponding policy entry. A present SA is therefore not proof that the target flow should or did use it.

RFC 7296 places remote identity, AUTH verification, Peer Authorization Database rules, traffic selectors and directional Child SAs in the IKEv2 exchange. It also acknowledges timing windows in which endpoints disagree about SA state. A local MATURE row cannot reconstruct the peer’s credential decision or its current installation.

RFC 4303 then applies ESP to packets. The chosen services depend on SA options and topology; outbound transformation and inbound integrity verification occur packet by packet. Only after that come forwarding, remote receipt, transport behaviour and application authorisation. A counter increment can support one link in that chain. It cannot finish it.

The useful operational record is therefore a join, not a screenshot: privileged caller; exact PF_KEY request and reply; current local SA and SPD generation; protected key provenance; authenticated and authorised peer exchange; the packet’s policy match; AH/ESP result; independent remote observation; and application response. Each entry needs a timestamp and shared correlation identity. Missing joins should remain visibly missing.

Sources