Why does IPsecSaContextSetSpi0 from the WFP API seem to only accept even SPI values?

Nathan 20 Reputation points
2025-02-13T19:39:45.3633333+00:00

When creating an IPsec SA using the WFP API, IpsecSaContextSetSpi0() doesn't seem to accept an odd SPI value. Why is this the case? RFC 4303 Section 2.1 and RFC 4302 Section 2.4 talk about valid SPI values for an IPsec SA. It makes no mention of odd values being invalid, and states that the only IANA-reserved values are 1-255, with 0 being reserved for implementation-specific use.

If we dump the assembly of C:\Windows\System32\FWPUCLNT.DLL, we can see the following instructions:

$ gdb FWPUCLNT.DLL
(gdb) disassemble IPsecSaContextSetSpi0
Dump of assembler code for function fwpuclnt!IPsecSaContextSetSpi0:
   0x0000000180012140 <+0>:  mov    %r9d,0x20(%rsp)
   0x0000000180012145 <+5>:  push   %rbx
   0x0000000180012146 <+6>:  sub    $0x40,%rsp
   0x000000018001214a <+10>:  xor    %ebx,%ebx
   0x000000018001214c <+12>:  test   %r9d,%r9d
   0x000000018001214f <+15>:  je     0x1800121c2 <fwpuclnt!IPsecSaContextSetSpi0+130>
   0x0000000180012151 <+17>:  test   $0x1,%r9b
   0x0000000180012155 <+21>:  jne    0x1800121c2 <fwpuclnt!IPsecSaContextSetSpi0+130> 
[...]
   0x00000001800121c2 <+130>:  mov    $0x80320035,%eax
   0x00000001800121c7 <+135>:  add    $0x40,%rsp
   0x00000001800121cb <+139>:  pop    %rbx
   0x00000001800121cc <+140>:  retq   



At offset 17, we see a bitwise AND that checks if the least significant bit of a value (likely the SPI) is non-zero. If it's non-zero, we jump to offset 130 and return the value 0x80320035 (which is FWP_E_INVALID_PARAMETER). We can also see the same through a decompiler such as Hex-Rays:

DWORD __stdcall IPsecSaContextSetSpi0(
        HANDLE engineHandle,
        UINT64 id,
        const IPSEC_GETSPI1 *getSpi,
        IPSEC_SA_SPI inboundSpi)
{
  __int64 v4; // rbx
  __int64 v5; // r8
  const char *v6; // rdx
  unsigned int Pointer; // eax
  IPSEC_SA_SPI v9; // [rsp+30h] [rbp-18h] BYREF

  v4 = 0LL;
  v9 = inboundSpi;
  if ( inboundSpi && (inboundSpi & 1) == 0 )
  {
    if ( engineHandle )
    {
      Pointer = (unsigned int)sub_18001F1AC(
                                *(_QWORD *)engineHandle,
                                *((_QWORD *)engineHandle + 1),
                                id,
                                (__int64)getSpi,
                                (__int64)&v9).Pointer;
      if ( !Pointer )
        return sub_180002960(v4);
      v5 = Pointer;
      v6 = "FwppProxyBfeIPsecSaContextGetOrSetSpi";
    }
    else
    {
      v5 = 2150760476LL;
      v6 = "IPsecSaContextSetSpi0";
    }
    v4 = sub_180006520((__int64)engineHandle, v6, v5);
    return sub_180002960(v4);
  }
  if ( off_18007A000 != &off_18007A000
    && *((_BYTE *)off_18007A000 + 25) >= 2u
    && (*((_DWORD *)off_18007A000 + 7) & 0x100) != 0 )
  {
    sub_18001AE58(*((_QWORD *)off_18007A000 + 2), id, (__int64)getSpi, inboundSpi, id);
  }
  return -2144206795; // 0x80320035 aka FWP_E_INVALID_PARAMETER
}

Now the documentation on IPsecSaContextSetSpi0() makes no mention of odd SPI values being invalid, and it doesn't talk about FWP_E_INVALID_PARAMETER being a likely return value:

IPsecSaContextSetSpi0 function (fwpmu.h)

The documentation on WFP error codes also doesn't help:

WFP Error Codes

This goes against the RFCs as linked earlier, and it seriously breaks interoperability with other IPsec implementations such as Linux's XFRM. Is it just an accidental bug or is it an odd, but intentional choice that hasn't been documented anywhere?

IKEv2 implementations such as strongSwan have encountered problems with this when interfacing with WFP. This issue was encountered many years ago on Windows Server 2012: Issue #2750: setting WFP SA SPI failed: 0x80320035

And it is still being encountered in recent times: "setting WFP SA SPI failed" and "unable to install IPsec policies (SPD) in kernel" on Windows #2567

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,736 questions
{count} votes

Accepted answer
  1. Gary Nebbett 6,196 Reputation points
    2025-02-14T14:35:47.5933333+00:00

    Hello Nathan,

    I am inclined to think that this is a bug. If you search IKEEXT.DLL for strings, you might find these two:

    1. Flip even SPI to odd for key dictator inbound SA
    2. Flip even SPI to odd for key dictatee outbound SA

    The strings are referenced from the routine IkeModifyKeyDictSaBundleFlagsAndSPI.

    Key dictation is a feature of AuthIP and it seems possible that the low bit of an AuthIP SPI is used to indicate key dictation.

    The bug might just be testing for this flag bit on a code path used to manage other keying modules, such as IKE and IKEv2.

    Gary

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Jeanine Zhang-MSFT 10,856 Reputation points Microsoft Vendor
    2025-02-17T02:56:39.3233333+00:00

    Hi,

    Welcome to Microsoft Q&A!

    I‘d suggest you could submit a feedback about this issue in the Feedback Hub. You could find the Feedback Hub in the Start Menu. Please select Developer Platform -> API Feedback as the category when you submit your request. The related team will check the request.

    If there are more upward votes, the team will have a greater chance of following.

    Thank you

    Jeanine

    1 person found this answer helpful.
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.