Skip to content

🐛 [BUG] - SA Create Does Not Validate SA State (Conformance issue) #507

@VissaMoutafis

Description

@VissaMoutafis

Description

Description

The sa_rekey() / SA-Create handler in
src/sa/internal/sa_interface_inmemory.template.c overwrites an existing Security
Association entry without first verifying that the target SPI is in SA_NONE state.
This means an operator can silently replace a live, operational SA — including its cryptographic
parameters — while the SA remains in service.

According to the CCSDS SDLS-EP standard (CCSDS 355.2-B-1, §3.3.1), the SA Create
procedure is only permitted when the target SPI is in the Unoccupied (NONE) state. All
other states must cause the command to be rejected.

Status on dev/main (as of 2026-03-31): The state-check guard (if (temp_sa->sa_state != SA_NONE) { return CRYPTO_LIB_ERROR; }) does not appear in
the current dev branch's sa_interface_inmemory.template.c. This issue should be
considered unpatched in the current dev branch.


Branch / Affected Version

  • Affected: v1.4.2 (src/sa/internal/sa_interface_inmemory.template.c, ~line 1453)
  • Latest tested dev commit: dev branch as of 2026-03-31

Reproduction Steps

Use the following packet sequence. Observe that Packet 3 (SA Create for SPI
20) succeeds unconditionally even if SPI 20 already exists in any state other than
SA_NONE.

Packet 1 – Key OTAR

002c104c000000000102000000000000000000000000000000719405af7fcd82f5c1073e5c81455b28e37b2e8b4cada60ec40bd3eea8585e2fb2e22726654fed87b83a4a912feffdf35b9c1422

Packet 2 – Key Activate

002c100e0000000002001000828a33

Packet 3 – SA Create (SPI 20) — send twice to demonstrate no state guard

002c1046000000001101d00014cc001001010c00000000000000000000000001010020000000000000000000000000000000000000000000000000000000000000000000002384
  1. Send Packet 1 and Packet 2 as prerequisites.
  2. Send Packet 3 the first time — SPI 20 is created successfully (sa_state = 0x1 UNKEYED).
  3. Advance SPI 20 to OPERATIONAL (Packets 4, 5 below).
  4. Send Packet 3 again — SPI 20 is overwritten without error. An operational SA is
    silently replaced.

Expected Behaviour

The second SA Create for SPI 20 (already in a non-NONE state) should be rejected with an
error code (e.g. CRYPTO_LIB_ERROR_SA) and the existing SA should be left untouched.

Actual Behaviour

The SA Create succeeds unconditionally, silently overwriting the live SA entry and resetting
all of its cryptographic parameters.


Logs

SA Create
spi = 20
SA status:
     spi        = 20
     sa_state   = 0x1      ← UNKEYED, regardless of prior state
     est        = 0x1
     ast        = 0x1
     shivf_len  = 12
     ...
Status code: 0             ← no error even when overwriting an operational SA

Proposed Fix

In src/sa/internal/sa_interface_inmemory.template.c, immediately after the lpid field
is populated (around line 1458 in v1.4.2, offsets may differ in dev), add a state-guard
block:

*** 1453,1458 ****
--- 1456,1470 ----
  // 5-8 : Procedure Identification Field (pid)
  temp_sa->lpid = (sdls_frame.tlv_pdu.hdr.type << 7) |
                  (sdls_frame.tlv_pdu.hdr.uf   << 6) |
                  (sdls_frame.tlv_pdu.hdr.sg   << 4) |
                   sdls_frame.tlv_pdu.hdr.pid;
+
+ // Check that the SA is in NONE state before creating
+ if (temp_sa->sa_state != SA_NONE)
+ {
+ #ifdef DEBUG
+     printf(KRED "ERROR: SPI %d is not in the NONE state.\n" RESET, spi);
+ #endif
+     return CRYPTO_LIB_ERROR_SA;
+ }
 
  // Write SA Configuration
  temp_sa->est = ...

References

  • CCSDS 355.2-B-1 – SDLS Extended Procedures, §3.3.1 (SA Create state machine
    requirements)
  • CCSDS 355.0-B-2 – Space Data Link Security Protocol, §4 (SA state transitions)

Environment

  • OS: Linux (Ubuntu 22.04 / tested in Docker)
  • CryptoLib version: v1.4.2
  • Crypto backend: LibGcrypt 1.4.1 (internal SA/Key)
  • Build flags: TC_PROCESS_SDLS_PDUS_TRUE, CRYPTO_EPROC=1

Branch Name

v1.4.2 and dev

Reproduction steps

Use the following packet sequence. Observe that **Packet 3** (SA Create for SPI
20) succeeds unconditionally even if SPI 20 already exists in any state other than
`SA_NONE`.
 
**Packet 1 – Key OTAR**

002c104c000000000102000000000000000000000000000000719405af7fcd82f5c1073e5c81455b28e37b2e8b4cada60ec40bd3eea8585e2fb2e22726654fed87b83a4a912feffdf35b9c1422

**Packet 2 – Key Activate**

002c100e0000000002001000828a33

**Packet 3 – SA Create (SPI 20) — send twice to demonstrate no state guard**

002c1046000000001101d00014cc001001010c00000000000000000000000001010020000000000000000000000000000000000000000000000000000000000000000000002384

1. Send Packet 1 and Packet 2 as prerequisites.
2. Send Packet 3 the first time — SPI 20 is created successfully (`sa_state = 0x1 UNKEYED`).
3. Advance SPI 20 to `OPERATIONAL` (Packets 4, 5 below).
4. Send **Packet 3 again** — SPI 20 is overwritten without error. An operational SA is
   silently replaced.

Screenshots

Logs

OS

Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions