Security Parameter Indexes (SPIs) can mean different things when referring to IKE and IPsec Security Associations (SAs):
- For IKE two 64-bit SPIs uniquely identify an IKE SA. With IKEv2 the
IKE_SA_INIT
request will only have the locally unique initiator SPI set in the IKE header, the responder SPI is zero. The responder will set that to a likewise locally unique value in its response. The two SPIs will only change when the IKE SA is rekeyed.
The two fields in the IKE header that are now called Initiator/Responder SPI were previously called Initiator/Responder Cookie in RFC 2408 (ISAKMP). This could be confusing as IKEv2 uses COOKIE notification payloads to thwart denial of service attacks.
- For IPsec a 32-bit SPI semi-uniquely identifies an IPsec SA. Since these SAs are unidirectional the ESP/AH header contains only the SPI of the destination's inbound SA (unlike the IKE header which always contains both SPIs). Since the SPIs are locally unique this and the destination address is usually enough to uniquely identify an SA. But it could be problematic e.g. if two clients behind the same NAT allocate the same local SPI when they connect to the same VPN gateway. The combination of SPI and destination address would be the same on the public side of the NAT, which is why UDP encapsulation is required. The UDP ports allow the NAT to direct the inbound packets to the right client. Likewise, the gateway has to take measures to differentiate the two SAs so that the right SA is used when sending traffic to each client.
Does this mean, that the SPI a party sets is the SPI used for the incoming SA, not the outgoing one?
Yes, each peer sends the SPI of its inbound SA to the other peer.
Additionally my notes say that the initiator uses the SAD_ADD
method while the responder uses SAD_GETSPI
and SAD_UPDATE
.
The process of establishing an IPsec SA using e.g. a CREATE_CHILD_SA
exchange in IKEv2 could roughly be visualized like this:
Initiator Responder
SAD_GETSPI (inbound SA) -----------> {select algorithms and derive keys}
SAD_ADD (outbound SA)
SAD_GETSPI (inbound SA)
{derive keys} <----------- SAD_UPDATE (inbound SA)
SAD_UPDATE (inbound SA)
SAD_ADD (outbound SA)
- The initiator sends the SPI of its inbound SA together with a proposal of cryptographic algorithms and, if perfect forward secrecy is used, its Diffie-Hellman factor, to the responder.
- The responder selects suitable algorithms and derives the keys (optionally using DH) and proceeds installing the SAs.
- Then it returns its inbound SPI together with the selected algorithms (and optionally its DH factor) to the initiator, which is now able to install the SAs on its side.
Additionally, the two peers exchange traffic selectors that specify the network traffic that is to be covered by the established SA.
SAD_UPDATE
: "Please update SPI x, set SPI to y."
That's not what SAD_UPDATE
does. It actually does not change the SPI at all, but rather all (or some) of the other aspects of the SA, and these are mainly the encryption/integrity algorithms and keys (but may also include other things, like encapsulation or the anti-replay window size).
The reason you usually want to call SAD_GETSPI
and SAD_UPDATE
instead of simply SAD_ADD
for inbound SAs (even on the responder, where all the information would be available) is that the SAD is usually managed by the operating system's kernel, while IKE daemons operate in userland. And therefore, calling SAD_GETSPI
will ensure that the SPI is actually locally unique. Which might not be guaranteed if e.g. two IKE daemons (for IKEv1 and IKEv2) or even tools to manually manage SAs (like ip xfrm
or setkey
) are used concurrently on a system.
But it is imaginable that on some systems there could be a simplification that would allow a responder to call SAD_ADD
without specifying an SPI, and the SAD would then allocate one, install the SA, and return the new SPI. But that would require special handling for this particular case by the keying daemon (otherwise it could simply call SAD_ADD
for outbound SAs and SAD_GETSPI/SAD_UPDATE
for inbound SAs, no matter if it does so as initiator or responder).
RFC 2367 (PF_KEYv2) provides more information on these operations.