Description
Bug Report: ACS Authentication (CMAC/HMAC) Unconditionally Calls gcry_mac_setiv, Which Those Algorithms Reject β Every Non-AEAD MAC Operation With a Non-Zero SA IV Fails Before the Tag Is Ever Computed
Summary
| Field |
Value |
| Product |
NASA CryptoLib (SDLS Protocol Implementation) |
| Version |
<=1.5.0 |
| Component |
src/crypto/libgcrypt/cryptography_interface_libgcrypt.template.c β cryptography_authenticate, cryptography_validate_authentication |
| Issue |
Both functions unconditionally call gcry_mac_setiv() whenever the SA's iv_len > 0, but none of the three ACS algorithms CryptoLib actually maps to a libgcrypt MAC ID (CMAC-AES, HMAC-SHA256, HMAC-SHA512) accept an IV in libgcrypt β the call fails with GPG_ERR_INV_ARG before the MAC/tag is ever written or checked |
| Severity |
High |
| Impact |
Every non-AEAD authentication operation (cryptography_authenticate on encrypt, cryptography_validate_authentication on decrypt) β i.e. any SA_AUTHENTICATION or SA_AUTHENTICATED_ENCRYPTION SA using the ACS/CMAC-HMAC engine β fails outright whenever the SA is configured with iv_len > 0, which is a normal, unremarkable SA field. This makes the ACS authentication path functionally unusable for any SA that carries an IV, independent of whether the frame/MAC is otherwise valid. |
Description
cryptography_authenticate (used by Crypto_TC_Encrypt/Crypto_TC_Do_Encrypt for SA_AUTHENTICATION) and cryptography_validate_authentication (used by Crypto_TC_Do_Decrypt for SA_AUTHENTICATION/SA_AUTHENTICATED_ENCRYPTION when the SA's cipher isn't AEAD) both contain the same pattern:
// If MAC needs IV, set it (only for certain ciphers)
if (iv_len > 0)
{
gcry_error = gcry_mac_setiv(tmp_mac_hd, iv, iv_len);
if ((gcry_error & GPG_ERR_CODE_MASK) != GPG_ERR_NO_ERROR)
{
printf(KRED "ERROR: gcry_mac_setiv error code %d\n" RESET, gcry_error & GPG_ERR_CODE_MASK);
printf(KRED "Failure: %s/%s\n", gcry_strsource(gcry_error), gcry_strerror(gcry_error));
status = CRYPTO_LIB_ERROR; // (CRYPTO_LIB_ERR_LIBGCRYPT_ERROR in the validate function)
gcry_mac_close(tmp_mac_hd);
return status;
}
}
(cryptography_authenticate: src/crypto/libgcrypt/cryptography_interface_libgcrypt.template.c:172-184; cryptography_validate_authentication: :281-293)
The comment ("only for certain ciphers") shows the intent was to gate this on the specific MAC algorithm β but the code only checks iv_len > 0, never the algorithm itself. cryptography_get_acs_algo() (:950-973) maps CryptoLib's three supported AuthCipherSuite values to exactly these libgcrypt MAC IDs:
case CRYPTO_MAC_CMAC_AES256: algo = GCRY_MAC_CMAC_AES; break; // libgcrypt ID 201
case CRYPTO_MAC_HMAC_SHA256: algo = GCRY_MAC_HMAC_SHA256; break; // libgcrypt ID 101
case CRYPTO_MAC_HMAC_SHA512: algo = GCRY_MAC_HMAC_SHA512; break; // libgcrypt ID 103
In libgcrypt, gcry_mac_setiv() is only meaningful for the GMAC family (GCRY_MAC_GMAC_*, IDs 4xx) and Poly1305 family (GCRY_MAC_POLY1305*, IDs 5xx) β algorithms that are keyed-nonce constructions. Plain HMAC (1xx) and CMAC (2xx) β the only algorithm families CryptoLib's ACS ever selects β take no IV at all; calling gcry_mac_setiv() on an HMAC or CMAC handle returns GPG_ERR_INV_ARG (libgcrypt error code 45). Since every CryptoLib SA carries an iv field and it is entirely normal for iv_len to be non-zero (e.g. for anti-replay/IV-tracking on the security header) regardless of which ACS algorithm is configured, this branch fires for essentially any real ACS-authenticated SA and aborts before gcry_mac_write/gcry_mac_read/gcry_mac_verify ever run β the actual MAC is never computed or checked.
Discovered using the StratoFuzz protocol fuzzing framework.
Branch Name
1.5.0
Reproduction steps
## Reproduction
Running a triage of a fuzz-generated packet sequence that triggers an `SA_AUTHENTICATED` SA rekey and start, then attempts to use it, produces the following logs:
~$ ./crypto_triage ~/BlindspotFuzz/fuzzer_output/dummy-test/mismatches/0:34:4:1717507963:0_MB_NC.pcap
Key internal interface intialized
Initializing Libgcrypt...
SA Written Successfully to file!
SA Written Successfully to file!
Crypto Lib Intialized. Version 1.4.1.0
Extracted CCSDS Frame 1: 167 bytes
Extracted CCSDS Frame 2: 31 bytes
Extracted CCSDS Frame 3: 19 bytes
Extracted CCSDS Frame 4: 47 bytes
Processing packet 1/4 -> 002c10a6000000001104d0003f4c001001010c000000000000000000000000010200800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058f9
----- Crypto_TC_ProcessSecurity START -----
vcid = 4
spi = 0
DEBUG - Printing local copy of SA Entry for current SPI.
SA status:
spi = 0
sa_state = 0x3
est = 0x0
ast = 0x0
shivf_len = 0
shsnf_len = 0
shplf_len = 0
stmacf_len = 0
ecs_len = 0
ekid = 0
ek_ref =
akid = 0
ak_ref =
iv_len = 0
iv =
acs_len = 0
acs = 0x00
abm_len = 0
arsn_len = 0
arsnw_len = 0
arsnw = 0
DEBUG - Printing local copy of SA Entry for current SPI.
SA status:
spi = 0
sa_state = 0x3
est = 0x0
ast = 0x0
shivf_len = 0
shsnf_len = 0
shplf_len = 0
stmacf_len = 0
ecs_len = 0
ekid = 0
ek_ref =
akid = 0
ak_ref =
iv_len = 0
iv =
acs_len = 0
acs = 0x00
abm_len = 0
arsn_len = 0
arsnw_len = 0
arsnw = 0
SA Index matches SPI
Processing a TC - CLEAR!
Crypto_Calc_FECF: 0x002c10a600, len_ingest = 165
0x002c10a6000000001104d0003f4c001001010c0000000000000000000000000102008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
In Crypto_Calc_FECF! fecf = 0x58f9
Received FECF is 0x58F9
Calculated FECF is 0x58F9
FECF was Calced over 165 bytes
Full IV Value from Frame and SADB (if applicable):
Full ARSN Value from Frame and SADB (if applicable):
TC PDU Calculated Length: 157
Received SDLS command (No Packet Header or PUS): Current CCSDS in memory is:
Primary Header
pvn = 0x0
type = 0x0
shdr = 0x0
appID = 0x000
seq = 0x0
pktid = 0x0000
pkt_length = 0x3f4c
PUS Header
Config not configured for PUS Header, not printing
TLV PDU
type = 0x0
uf = 0x0
sg = 0x1
pid = 0x1
pdu_len = 0x04d0
data[0] = 0x00
data[1] = 0x3f
data[2] = 0x4c
SA Create
spi = 63
DEBUG - Printing local copy of SA Entry for current SPI.
SA status:
spi = 63
sa_state = 0x0
est = 0x0
ast = 0x0
shivf_len = 0
shsnf_len = 0
shplf_len = 0
stmacf_len = 0
ecs_len = 0
ekid = 63
ek_ref =
akid = 63
ak_ref =
iv_len = 0
iv =
acs_len = 0
acs = 0x00
abm_len = 0
arsn_len = 0
arsnw_len = 0
arsnw = 0
SA status:
spi = 63
sa_state = 0x1
est = 0x0
ast = 0x1
shivf_len = 12
shsnf_len = 0
shplf_len = 0
stmacf_len = 16
ecs_len = 1
ecs[0] = 0x01
ekid = 63
ek_ref =
akid = 63
ak_ref =
iv_len = 12
iv[0] = 0x00
iv[1] = 0x00
iv[2] = 0x00
iv[3] = 0x00
iv[4] = 0x00
iv[5] = 0x00
iv[6] = 0x00
iv[7] = 0x00
iv[8] = 0x00
iv[9] = 0x00
iv[10] = 0x00
iv[11] = 0x00
acs_len = 1
acs = 0x02
abm_len = 128
abm = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
arsn_len = 0
arsnw_len = 0
arsnw = 0
Status code: 0
Processing packet 2/4 -> 002c101e00000000160090003f00820082000000000000000000000000551f
----- Crypto_TC_ProcessSecurity START -----
vcid = 4
spi = 0
DEBUG - Printing local copy of SA Entry for current SPI.
SA status:
spi = 0
sa_state = 0x3
est = 0x0
ast = 0x0
shivf_len = 0
shsnf_len = 0
shplf_len = 0
stmacf_len = 0
ecs_len = 0
ekid = 0
ek_ref =
akid = 0
ak_ref =
iv_len = 0
iv =
acs_len = 0
acs = 0x00
abm_len = 0
arsn_len = 0
arsnw_len = 0
arsnw = 0
DEBUG - Printing local copy of SA Entry for current SPI.
SA status:
spi = 0
sa_state = 0x3
est = 0x0
ast = 0x0
shivf_len = 0
shsnf_len = 0
shplf_len = 0
stmacf_len = 0
ecs_len = 0
ekid = 0
ek_ref =
akid = 0
ak_ref =
iv_len = 0
iv =
acs_len = 0
acs = 0x00
abm_len = 0
arsn_len = 0
arsnw_len = 0
arsnw = 0
SA Index matches SPI
Processing a TC - CLEAR!
Crypto_Calc_FECF: 0x002c101e00, len_ingest = 29
0x002c101e00000000160090003f00820082000000000000000000000000
In Crypto_Calc_FECF! fecf = 0x551f
Received FECF is 0x551F
Calculated FECF is 0x551F
FECF was Calced over 29 bytes
Full IV Value from Frame and SADB (if applicable):
Full ARSN Value from Frame and SADB (if applicable):
TC PDU Calculated Length: 21
Received SDLS command (No Packet Header or PUS): Current CCSDS in memory is:
Primary Header
pvn = 0x0
type = 0x0
shdr = 0x0
appID = 0x000
seq = 0x0
pktid = 0x0000
pkt_length = 0x3f00
PUS Header
Config not configured for PUS Header, not printing
TLV PDU
type = 0x0
uf = 0x0
sg = 0x1
pid = 0x6
pdu_len = 0x0090
data[0] = 0x00
data[1] = 0x3f
data[2] = 0x00
SA Rekey
SPI 63 IV updated to: 0x000000000000000000000000
SPI 63 changed to KEYED state with encrypted Key ID 130.
spi = 63
ekid = 130
Status code: 0
Processing packet 3/4 -> 002c1012000000001b0030003f00002c040ac0
----- Crypto_TC_ProcessSecurity START -----
vcid = 4
spi = 0
DEBUG - Printing local copy of SA Entry for current SPI.
SA status:
spi = 0
sa_state = 0x3
est = 0x0
ast = 0x0
shivf_len = 0
shsnf_len = 0
shplf_len = 0
stmacf_len = 0
ecs_len = 0
ekid = 0
ek_ref =
akid = 0
ak_ref =
iv_len = 0
iv =
acs_len = 0
acs = 0x00
abm_len = 0
arsn_len = 0
arsnw_len = 0
arsnw = 0
DEBUG - Printing local copy of SA Entry for current SPI.
SA status:
spi = 0
sa_state = 0x3
est = 0x0
ast = 0x0
shivf_len = 0
shsnf_len = 0
shplf_len = 0
stmacf_len = 0
ecs_len = 0
ekid = 0
ek_ref =
akid = 0
ak_ref =
iv_len = 0
iv =
acs_len = 0
acs = 0x00
abm_len = 0
arsn_len = 0
arsnw_len = 0
arsnw = 0
SA Index matches SPI
Processing a TC - CLEAR!
Crypto_Calc_FECF: 0x002c101200, len_ingest = 17
0x002c1012000000001b0030003f00002c04
In Crypto_Calc_FECF! fecf = 0x0ac0
Received FECF is 0x0AC0
Calculated FECF is 0x0AC0
FECF was Calced over 17 bytes
Full IV Value from Frame and SADB (if applicable):
Full ARSN Value from Frame and SADB (if applicable):
TC PDU Calculated Length: 9
Received SDLS command (No Packet Header or PUS): Current CCSDS in memory is:
Primary Header
pvn = 0x0
type = 0x0
shdr = 0x0
appID = 0x000
seq = 0x0
pktid = 0x0000
pkt_length = 0x3f00
PUS Header
Config not configured for PUS Header, not printing
TLV PDU
type = 0x0
uf = 0x0
sg = 0x1
pid = 0xb
pdu_len = 0x0030
data[0] = 0x00
data[1] = 0x3f
data[2] = 0x00
SA Start
Parsed GVCID: 1
MAPID: 4
SPI 63 changed to OPERATIONAL state.
Type Unknown, MAPID: 0
SPI 63 changed to OPERATIONAL state.
Type TC, spi = 63
Status code: 0
Processing packet 4/4 -> 002c102e0000003f000000000000000000000000ff09c6bbf37c10202ea58487a7a07a5627dc54d1ebaaa0290dd7a1
----- Crypto_TC_ProcessSecurity START -----
vcid = 4
spi = 63
DEBUG - Printing local copy of SA Entry for current SPI.
SA status:
spi = 63
sa_state = 0x3
est = 0x0
ast = 0x1
shivf_len = 12
shsnf_len = 0
shplf_len = 0
stmacf_len = 16
ecs_len = 1
ecs[0] = 0x01
ekid = 130
ek_ref =
akid = 130
ak_ref =
iv_len = 12
iv[0] = 0x00
iv[1] = 0x00
iv[2] = 0x00
iv[3] = 0x00
iv[4] = 0x00
iv[5] = 0x00
iv[6] = 0x00
iv[7] = 0x00
iv[8] = 0x00
iv[9] = 0x00
iv[10] = 0x00
iv[11] = 0x00
acs_len = 1
acs = 0x02
abm_len = 128
abm = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
arsn_len = 0
arsnw_len = 0
arsnw = 0
DEBUG - Printing local copy of SA Entry for current SPI.
SA status:
spi = 63
sa_state = 0x3
est = 0x0
ast = 0x1
shivf_len = 12
shsnf_len = 0
shplf_len = 0
stmacf_len = 16
ecs_len = 1
ecs[0] = 0x01
ekid = 130
ek_ref =
akid = 130
ak_ref =
iv_len = 12
iv[0] = 0x00
iv[1] = 0x00
iv[2] = 0x00
iv[3] = 0x00
iv[4] = 0x00
iv[5] = 0x00
iv[6] = 0x00
iv[7] = 0x00
iv[8] = 0x00
iv[9] = 0x00
iv[10] = 0x00
iv[11] = 0x00
acs_len = 1
acs = 0x02
abm_len = 128
abm = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
arsn_len = 0
arsnw_len = 0
arsnw = 0
SA Index matches SPI
CRYPTO IS AEAD? : TRUE
Processing a TC - AUTHENTICATED!
Crypto_Calc_FECF: 0x002c102e00, len_ingest = 45
0x002c102e0000003f000000000000000000000000ff09c6bbf37c10202ea58487a7a07a5627dc54d1ebaaa0290d
In Crypto_Calc_FECF! fecf = 0xd7a1
Received FECF is 0xD7A1
Calculated FECF is 0xD7A1
FECF was Calced over 45 bytes
Full IV Value from Frame and SADB (if applicable):
000000000000000000000000
Full ARSN Value from Frame and SADB (if applicable):
MAC Parsed from Frame:
a58487a7a07a5627dc54d1ebaaa0290d
AAD before ABM Bitmask:
002c102e0000003f000000000000000000000000ff09c6bbf37c10202e
Preparing AAD:
Using AAD Length of 29
0000000000000000000000000000000000000000000000000000000000
TC PDU Calculated Length: 9
Validate MAC Printing Key:
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210
ERROR: gcry_mac_setiv error code 45
Failure: gcrypt/Invalid argument
MC_Log: Error, [2026713,12:26:18], -1
Status code: -1
Frame 4's SA (SPI 63) is `est=0x0, ast=0x1, acs=0x02 (CRYPTO_MAC_HMAC_SHA256), ekid=akid=130, iv_len=12` β with the routing bug fixed, `cryptography_validate_authentication` is confirmed reached (the "Validate MAC Printing Key" trace only exists in that function) and picks the correct HMAC-SHA256 key. But it never gets as far as `gcry_mac_write`/`gcry_mac_verify`: `gcry_mac_setiv(tmp_mac_hd, iv, 12)` on an HMAC-SHA256 handle immediately fails with libgcrypt error code 45 (`GPG_ERR_INV_ARG`, "Invalid argument"), and the function returns `CRYPTO_LIB_ERROR` (-1) before the actual tag comparison ever happens.
Screenshots
Logs
OS
Linux
Description
Bug Report: ACS Authentication (CMAC/HMAC) Unconditionally Calls
gcry_mac_setiv, Which Those Algorithms Reject β Every Non-AEAD MAC Operation With a Non-Zero SA IV Fails Before the Tag Is Ever ComputedSummary
src/crypto/libgcrypt/cryptography_interface_libgcrypt.template.cβcryptography_authenticate,cryptography_validate_authenticationgcry_mac_setiv()whenever the SA'siv_len > 0, but none of the three ACS algorithms CryptoLib actually maps to a libgcrypt MAC ID (CMAC-AES, HMAC-SHA256, HMAC-SHA512) accept an IV in libgcrypt β the call fails withGPG_ERR_INV_ARGbefore the MAC/tag is ever written or checkedcryptography_authenticateon encrypt,cryptography_validate_authenticationon decrypt) β i.e. anySA_AUTHENTICATIONorSA_AUTHENTICATED_ENCRYPTIONSA using the ACS/CMAC-HMAC engine β fails outright whenever the SA is configured withiv_len > 0, which is a normal, unremarkable SA field. This makes the ACS authentication path functionally unusable for any SA that carries an IV, independent of whether the frame/MAC is otherwise valid.Description
cryptography_authenticate(used byCrypto_TC_Encrypt/Crypto_TC_Do_EncryptforSA_AUTHENTICATION) andcryptography_validate_authentication(used byCrypto_TC_Do_DecryptforSA_AUTHENTICATION/SA_AUTHENTICATED_ENCRYPTIONwhen the SA's cipher isn't AEAD) both contain the same pattern:(
cryptography_authenticate:src/crypto/libgcrypt/cryptography_interface_libgcrypt.template.c:172-184;cryptography_validate_authentication::281-293)The comment ("only for certain ciphers") shows the intent was to gate this on the specific MAC algorithm β but the code only checks
iv_len > 0, never the algorithm itself.cryptography_get_acs_algo()(:950-973) maps CryptoLib's three supportedAuthCipherSuitevalues to exactly these libgcrypt MAC IDs:In libgcrypt,
gcry_mac_setiv()is only meaningful for the GMAC family (GCRY_MAC_GMAC_*, IDs 4xx) and Poly1305 family (GCRY_MAC_POLY1305*, IDs 5xx) β algorithms that are keyed-nonce constructions. Plain HMAC (1xx) and CMAC (2xx) β the only algorithm families CryptoLib's ACS ever selects β take no IV at all; callinggcry_mac_setiv()on an HMAC or CMAC handle returnsGPG_ERR_INV_ARG(libgcrypt error code 45). Since every CryptoLib SA carries anivfield and it is entirely normal foriv_lento be non-zero (e.g. for anti-replay/IV-tracking on the security header) regardless of which ACS algorithm is configured, this branch fires for essentially any real ACS-authenticated SA and aborts beforegcry_mac_write/gcry_mac_read/gcry_mac_verifyever run β the actual MAC is never computed or checked.Discovered using the StratoFuzz protocol fuzzing framework.
Branch Name
1.5.0
Reproduction steps
Screenshots
Logs
OS
Linux