Skip to content

F-8045 - Reject duplicate SCEP signed attributes - #20

Open
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:mainfrom
yosuke-wolfssl:fix/f_8045
Open

F-8045 - Reject duplicate SCEP signed attributes#20
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:mainfrom
yosuke-wolfssl:fix/f_8045

Conversation

@yosuke-wolfssl

Copy link
Copy Markdown

Problem

wolfcert_scep_parse_pki_message walked the whole decoded signed-attribute list and, for each of the six recognised SCEP OIDs, allocated a copy and assigned it straight over the out-parameter with no check that the parameter was already populated. wolfSSL's PKCS#7 decoder does not de-duplicate attributes by OID, so a pkiMessage carrying N copies of one orphaned N-1 allocations — the caller only ever received, and freed, the last pointer. The peer also decided which copy won.

Both sides of the protocol reach it. Server: handle_pki_op parses a client-supplied body, and since the client self-signs its pkiMessage it controls the attribute SET while still satisfying wc_PKCS7_VerifySignedData. Client: scep_finish parses the response before the signer trust check, so an attacker answering a plaintext SCEP endpoint leaks memory on every attempt even though the forged CertRep is ultimately rejected. The 1 MiB body cap bounds each request, making this memory exhaustion under sustained traffic rather than an immediate crash.

The finding lists three production call sites; only two leak. wolfcert_scep_verify_next_ca_response passes NULL for every attribute out-parameter and never allocated.

Fix (src/scep/scep_msg.c)

  • scep_attr_bit() maps a decoded attribute OID to one of six bits, so the OID list exists in exactly one place.
  • seen accumulates those bits; a repeat returns WOLFCERT_ERR_PROTOCOL. RFC 8894 defines each attribute as singular, so rejecting also removes the attribute-confusion primitive that first-wins-skip would leave behind.
  • The check runs before the DER unwrap, so a deliberately malformed copy cannot smuggle a second one past it.
  • The reject path frees and NULLs every requested out-parameter plus the envelope, preserving the contract the function's existing early returns already had — callers need not free on error.
  • The six near-identical copy branches collapse into a switch selecting the target out-parameter.

Closes f-8045.

Test harness

test_duplicate_signed_attrib in tests/unit/test_scep_msg.c drives wc_PKCS7_EncodeSignedData with a messageType plus two transactionID attributes — well-formed DER that is protocol-malformed, so it survives signature verification and reaches the walk. It requests every out-parameter and requires WOLFCERT_ERR_PROTOCOL with all of them returned NULL.

Verification

  • Full suite 26/26; clean under -Werror.
  • Negative control: the unfixed tree returns WOLFCERT_OK, and leaks reports the orphaned copy.
  • Rollback branches proven live — neutering the messageType and signer-certificate frees yields exactly two orphans, 16 B and 768 B.

Not in this PR

The copy sites still leave the out-parameter NULL when WOLFCERT_XMALLOC fails instead of returning WOLFCERT_ERR_MEMORY. Pre-existing, unrelated to this finding, and unfiled.

@yosuke-wolfssl yosuke-wolfssl self-assigned this Aug 21, 2026
Copilot AI lite review requested due to automatic review settings August 21, 2026 02:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens SCEP pkiMessage parsing by rejecting duplicate signed attributes (per RFC 8894) to prevent memory leaks and attribute-confusion behavior when wolfSSL’s PKCS#7 decoder returns multiple attributes with the same OID.

Changes:

  • Add per-OID “seen” tracking in wolfcert_scep_parse_pki_message and return WOLFCERT_ERR_PROTOCOL on duplicate signed attributes.
  • Centralize OID→attribute mapping via scep_attr_bit() and simplify per-attribute output handling.
  • Add a unit test that constructs a SignedData with duplicate transactionID attributes and asserts rejection with no leftover allocations.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/scep/scep_msg.c Rejects duplicate SCEP signed attributes and rolls back any outputs on protocol-malformed input.
tests/unit/test_scep_msg.c Adds a regression test that encodes a pkiMessage with duplicate transactionID to ensure it is rejected and outputs are cleared.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/unit/test_scep_msg.c
- scep_attr_bit() maps a decoded attribute OID to one of six bits for
  messageType, pkiStatus, failInfo, transactionID, senderNonce and
  recipientNonce, and returns 0 for anything else.
- wolfcert_scep_parse_pki_message() accumulates those bits in
  and returns WOLFCERT_ERR_PROTOCOL on a repeat; that path frees and
  NULLs every requested out-parameter and the envelope.
- The six copy branches become a switch selecting the out-parameter,
  and the walk's locals move to the top of the function.
- test_scep_msg gains make_dup_tid_signed() and
  test_duplicate_signed_attrib(), which build a SignedData carrying a
  messageType and two transactionID attributes, request every
  out-parameter, and require the parse to reject it with all of them
  returned NULL.

Issue: F-8045

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #20

Scan targets checked: wolfcert-bugs, wolfcert-src

No new issues found in the changed files. ✅

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants