nasa / nasa/CryptoLib

🐛 [BUG] - `sa_create` Silently Returns Success for an Out-of-Range SPI

Open Beginner friendly
#545 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
C
Stars
169
Forks
67
PR merge metrics
No merged PRs in 30d

Description

Description

Bug Report: sa_create Silently Returns Success for an Out-of-Range SPI — Rejection Is DEBUG-Print-Only

Summary

Field Value
Product NASA CryptoLib (SDLS Protocol Implementation)
Version Observed on 1.5.0; identical code in 1.4.2.
Component src/sa/internal/sa_interface_inmemory.template.csa_create
Issue sa_create's else branch, taken when spi >= NUM_SA, contains only a #ifdef DEBUG printf. It never assigns status, so the function returns the CRYPTO_LIB_SUCCESS its initializer set at entry.
Bug Type Conformance (uninitialized-intent fall-through / missing error assignment)
Severity Medium — a rejected SA Create is reported to the ground segment as having succeeded
Impact An SDLS-EP SA Create naming an SPI outside the SA table is answered positively while no SA is created. In a release (non-DEBUG) build the rejection is completely invisible — no message, no error code, no log entry. The ground segment believes the SA exists and will proceed to Rekey/Start it; every subsequent operation on that SPI fails for an apparently unrelated reason.

Description

sa_create validates the requested SPI against the SA table bound and branches:

static int32_t sa_create(TC_t *tc_frame)
{
    // Local variables
    int32_t  status      = CRYPTO_LIB_SUCCESS;          // :1428  <-- initialized to success
    ...
    spi = ((uint8_t)sdls_frame.tlv_pdu.data[0] << BYTE_LEN) | (uint8_t)sdls_frame.tlv_pdu.data[1];

    control_spi = tc_frame->tc_sec_header.spi;
    if (spi == control_spi)
    {
        ...
        status = CRYPTO_LIB_ERR_SDLS_EP_WRONG_SPI;       // :1446  <-- this path does set a status
        return status;
    }

    // Check if valid SPI
    if (spi < NUM_SA)                                    // :1451
    {
        ... parse fields, sa_verify_data(), commit to sa[spi] ...   // :1453-1553
    }
    else
    {
#ifdef DEBUG
        printf(KRED "ERROR: SPI %d cannot be created.\n" RESET, spi);   // :1558
#endif
    }                                                    // *** status never assigned ***

    return status;                                       // :1562 -> CRYPTO_LIB_SUCCESS
}

(src/sa/internal/sa_interface_inmemory.template.c:1425-1563)

The rejection at :1555-1560 is a diagnostic, not a result. status still holds the
CRYPTO_LIB_SUCCESS from :1428 when :1562 returns it. The dispatcher propagates that
verbatim:

case PID_CREATE_SA:
#ifdef PDU_DEBUG
    printf(KGRN "SA Create\n" RESET);
#endif
    status = sa_if->sa_create(tc_frame);
    break;

(src/core/crypto.c:709-714)

Note the inconsistency within the same file: sa_create is the outlier, not the norm.

Function Out-of-range SPI handling
sa_create DEBUG printf only → returns CRYPTO_LIB_SUCCESS (:1555-1562)
sa_delete DEBUG printf and status = CRYPTO_LIB_ERR_SPI_INDEX_OOB (:1652-1658)
sa_get_from_spi status = CRYPTO_LIB_ERR_SPI_INDEX_OOB, logs via mc_if->mc_log, early return (:748-756)

Per CCSDS 355.1-B-1 §5.5.1, an SA Create for an SPI the receiving end cannot host must be
answered negatively. sa_delete and sa_get_from_spi already implement exactly the response
sa_create is missing, with a return code that already exists for this purpose.

Affected Code

  • src/sa/internal/sa_interface_inmemory.template.c:1555-1562 (1.5.0) — the else branch and
    the return status it falls through to
  • src/core/crypto.c:709-714 (1.5.0) — dispatcher, propagates the bogus success unchanged
Affected Versions
Version Status
1.5.0 Affected as describedelse branch at :1555-1560, printf only, no status assignment
1.4.2 Affected identically — same else branch, same DEBUG-only printf at :1558, no status assignment

Reproduction Sequence (from the fuzzing logs)

Eight TC frames on VCID 4 (TC_SDLS_EP_VCID).

# Hex Meaning Status
1 002c10a6000000001104d0003f4c001001020c0000…ba17 SA Create, SPI 63 0
2 002c104c000000000102000000…35b9c1422 Key OTAR 0
3 002c100e0000000002001000828a33 Key Activate 0
4 002c101e00000000160090003f00820082000000000000000000000000551f SA Rekey 0
5 002c100e0000000003001000822062 Key Deactivate 0
6 002c1012000000001b0030003f00002c040ac0 SA Start 0
7 002c100e0000000006001000820335 Key Destroy 0
8 002c10b500000000110548cefc0c328401020cfbf13fef8286c9980feff6010200800000…0072df SA Create, SPI 52988 0 ← should be an error

Frames 1-7 exercise SPI 63 and the key table; frame 8 does not depend on any of that state —
it is a clear TC frame on control SPI 0 carrying an SA Create for SPI 52988.

Frame 8's TLV: tag 0x11 (type=0, uf=0, sg=1 SA-Management, pid=1 SA-Create), with
data[0..1] = 0xCEFC = 52988. NUM_SA is 64 (include/crypto_config.h:141), so 52988 is far
outside the table.

Debug replay (-DDEBUG=ON), packet 8:

Processing packet 8/8 -> 002c10b500000000110548cefc0c328401020cfbf13fef8286c9980feff6010200800000...
...
TC PDU Calculated Length: 172
Received SDLS command (No Packet Header or PUS): Current CCSDS in memory is:
	 TLV PDU
		 type       = 0x0
		 uf         = 0x0
		 sg         = 0x1
		 pid        = 0x1            <-- PID_CREATE_SA
		 pdu_len    = 0x0548
		 data[0]    = 0xce
		 data[1]    = 0xfc
		 data[2]    = 0x0c

SA Create
spi = 52988
ERROR: SPI 52988 cannot be created.    <-- target correctly identifies the SPI as unhostable
Status code: 0                         <-- ...and reports success anyway

The target prints the rejection reason and the success status three lines apart. Both the
control-SPI check (:1441-1448, control SPI is 0, passes) and the range check (:1451, fails)
behaved correctly — only the reporting of the second one is broken.

In a build without -DDEBUG, the ERROR: line does not exist and the only externally visible
result is Status code: 0.


Discovered using the StratoFuzz protocol fuzzing framework.

Branch Name

dev

Reproduction steps
## Reproduction Sequence (from the fuzzing logs)

Eight TC frames on VCID 4 (`TC_SDLS_EP_VCID`).

| # | Hex | Meaning | Status |
|---|-----|---------|--------|
| 1 | `002c10a6000000001104d0003f4c001001020c0000…ba17` | SA Create, SPI 63 | 0 |
| 2 | `002c104c000000000102000000…35b9c1422` | Key OTAR | 0 |
| 3 | `002c100e0000000002001000828a33` | Key Activate | 0 |
| 4 | `002c101e00000000160090003f00820082000000000000000000000000551f` | SA Rekey | 0 |
| 5 | `002c100e0000000003001000822062` | Key Deactivate | 0 |
| 6 | `002c1012000000001b0030003f00002c040ac0` | SA Start | 0 |
| 7 | `002c100e0000000006001000820335` | Key Destroy | 0 |
| 8 | `002c10b500000000110548cefc0c328401020cfbf13fef8286c9980feff6010200800000…0072df` | **SA Create, SPI 52988** | **0** ← should be an error |

Frames 1-7 exercise SPI 63 and the key table; frame 8 does not depend on any of that state —
it is a clear TC frame on control SPI 0 carrying an SA Create for SPI 52988.

**Frame 8's TLV**: tag `0x11` (type=0, uf=0, sg=1 SA-Management, pid=1 SA-Create), with
`data[0..1] = 0xCEFC = 52988`. `NUM_SA` is 64 (`include/crypto_config.h:141`), so 52988 is far
outside the table.

**Debug replay (`-DDEBUG=ON`), packet 8:**


Processing packet 8/8 -> 002c10b500000000110548cefc0c328401020cfbf13fef8286c9980feff6010200800000...
...
TC PDU Calculated Length: 172
Received SDLS command (No Packet Header or PUS): Current CCSDS in memory is:
	 TLV PDU
		 type       = 0x0
		 uf         = 0x0
		 sg         = 0x1
		 pid        = 0x1            <-- PID_CREATE_SA
		 pdu_len    = 0x0548
		 data[0]    = 0xce
		 data[1]    = 0xfc
		 data[2]    = 0x0c

SA Create
spi = 52988
ERROR: SPI 52988 cannot be created.    <-- target correctly identifies the SPI as unhostable
Status code: 0                         <-- ...and reports success anyway


The target prints the rejection reason and the success status three lines apart. Both the
control-SPI check (`:1441-1448`, control SPI is 0, passes) and the range check (`:1451`, fails)
behaved correctly — only the reporting of the second one is broken.

In a build without `-DDEBUG`, the `ERROR:` line does not exist and the only externally visible
result is `Status code: 0`.
Screenshots

Logs

OS

Linux

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/sa/internal/sa_interface_inmemory.template.c around sa_create at lines 1425-1563, then read the PID_CREATE_SA dispatch in src/core/crypto.c:709-714 and compare sa_delete’s out-of-range handling. Reproduce with the SPI 52988 frame or the eight-packet sequence; done means an out-of-range SPI returns CRYPTO_LIB_ERR_SPI_INDEX_OOB instead of success, including in a non-DEBUG build.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
security
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
86/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.