Skip to content

[ndncert] Cryptographic non-compliance #201

Description

@yoursunny

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions