A review of the std/security/ndncert cryptographic implementation against the NDNCERT v0.3 specification revealed several compliance issues in AES-GCM IV construction, counter handling, decryption checks, and session key lifecycle.
1. crypto_aes.go: Counter Endianness Mismatch (Little-Endian vs. Big-Endian)
Spec Requirement (Section 2.4.2):
"The last 32 bits is a counter... The counter field is big endian."
Current Behavior:
|
binary.LittleEndian.PutUint32(cblock, counter.block) |
Impact:
Causes interoperability failures with other NDNCERT v0.3 implementations (such as NDNts) that follow the big-endian counter specification.
Fix:
Use binary.BigEndian.PutUint32(cblock, counter.block).
2. crypto_aes.go: Pre-Increment vs. Post-Increment of Block Counter & Float Calculation
Spec Requirement (Section 2.4.2):
"Each entity should initialize the counter to zero at the beginning of the CHALLENGE step. Then, after encrypting a message of $b$ AES blocks, it should increment the counter by $b$."
Current Behavior:
|
counter.block += uint32(math.Ceil(float64(float32(len(plaintext)) / float32(AeadSizeTag)))) |
|
cblock := make([]byte, 4) |
|
binary.LittleEndian.PutUint32(cblock, counter.block) |
Impact:
- The counter is incremented before generating the IV for the current message, causing the first CHALLENGE message to send counter value $b$ instead of 0.
- Division uses
float32/float64/math.Ceil, which risks precision bugs on edge cases.
Fix:
Construct the IV using the current counter.block value first, then increment counter.block after or at the end using integer arithmetic:
b := uint32((len(plaintext) + 15) / 16)
3. crypto_aes.go: Missing IV Validation and Monotonicity Checks on Decryption
Spec Requirement (Section 2.4.2):
"Recipient of each message should verify the uniqueness of initialization vectors. In particular, it should check that the random value portion is consistent across messages... and the counter is monotonically increasing and has not wrapped around."
Current Behavior:
AeadDecrypt decrypts using message.IV[:] directly without validating:
- Whether the 64-bit random prefix of
message.IV matches the session's expected prefix.
- Whether the counter value is strictly increasing relative to previously received messages.
- Whether counter wrap-around occurred ($> 2^{32}-1$).
Fix:
Implement IV prefix matching and monotonic counter tracking during incoming message decryption.
4. client.go: Single ECDH Key Reused Across Multiple Certificate Requests
Spec Requirement (Section 2.3.4):
"This key should be generated with a cryptographically secure pseudo random generator, and each certificate request session must use a unique key."
Current Behavior:
NewClient() generates ecdhKey once during initialization. If a single Client instance is reused to call RequestCert() multiple times, it will reuse the same ephemeral ECDH key.
Fix:
Re-generate ecdhKey (e.g., inside c.New()) for every new request session.
Disclaimer: this report was generated by Google Gemini using 3.6 Flash model based on NDNCERT specification text and the relevant source code in this repository. The same session also analyzed NDNts and ndncert C++ implementation where no defects were found.
A review of the
std/security/ndncertcryptographic implementation against the NDNCERT v0.3 specification revealed several compliance issues in AES-GCM IV construction, counter handling, decryption checks, and session key lifecycle.1.
crypto_aes.go: Counter Endianness Mismatch (Little-Endian vs. Big-Endian)Spec Requirement (Section 2.4.2):
Current Behavior:
ndnd/std/security/ndncert/crypto_aes.go
Line 77 in 2a1ae9e
Impact:
Causes interoperability failures with other NDNCERT v0.3 implementations (such as NDNts) that follow the big-endian counter specification.
Fix:
Use
binary.BigEndian.PutUint32(cblock, counter.block).2.
crypto_aes.go: Pre-Increment vs. Post-Increment of Block Counter & Float CalculationSpec Requirement (Section 2.4.2):
Current Behavior:
ndnd/std/security/ndncert/crypto_aes.go
Lines 75 to 77 in 2a1ae9e
Impact:
float32/float64/math.Ceil, which risks precision bugs on edge cases.Fix:
Construct the IV using the current
counter.blockvalue first, then incrementcounter.blockafter or at the end using integer arithmetic:3.
crypto_aes.go: Missing IV Validation and Monotonicity Checks on DecryptionSpec Requirement (Section 2.4.2):
Current Behavior:
AeadDecryptdecrypts usingmessage.IV[:]directly without validating:message.IVmatches the session's expected prefix.Fix:
Implement IV prefix matching and monotonic counter tracking during incoming message decryption.
4.
client.go: Single ECDH Key Reused Across Multiple Certificate RequestsSpec Requirement (Section 2.3.4):
Current Behavior:
NewClient()generatesecdhKeyonce during initialization. If a singleClientinstance is reused to callRequestCert()multiple times, it will reuse the same ephemeral ECDH key.Fix:
Re-generate ecdhKey (e.g., inside
c.New()) for every new request session.Disclaimer: this report was generated by Google Gemini using 3.6 Flash model based on NDNCERT specification text and the relevant source code in this repository. The same session also analyzed NDNts and ndncert C++ implementation where no defects were found.