Skip to content

fix: NUL-terminate get_hex() output — OCTET STRING / BIT STRING unterminated buffer#65

Merged
jonasbn merged 7 commits into
masterfrom
fix/get-hex-null-termination
Jun 24, 2026
Merged

fix: NUL-terminate get_hex() output — OCTET STRING / BIT STRING unterminated buffer#65
jonasbn merged 7 commits into
masterfrom
fix/get-hex-null-termination

Conversation

@jonasbn

@jonasbn jonasbn commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

get_hex() in PKCS12.xs never wrote a NUL terminator, leaving *attribute unterminated in the V_ASN1_OCTET_STRING and V_ASN1_BIT_STRING branches of print_attribute(). With a zero-length input the buffer was entirely uninitialised, making any downstream strlen() / newSVpvn() call undefined behaviour. Closes #63.

Changes

  • get_hex() — add *out = '\0' after the loop so all callers receive a NUL-terminated string regardless of input length
  • Both Renew call sites — increase allocation from length * 4 to length * 4 + 1 to ensure the terminator byte is always within bounds, and to avoid Renew(ptr, 0) when length is zero

Test plan

  • All 357 existing tests pass on OpenSSL 3.x
  • CI green on Linux / macOS / Windows matrix

Notes

This is a general C correctness fix — not OpenSSL-version-specific. Identified by Copilot review on PR #61 (comments on lines 694 and 707). A similar Copilot comment on PR #59 about V_ASN1_BMPSTRING was correctly dismissed by @timlegge because OPENSSL_uni2asc guarantees NUL termination — that reasoning does not apply to get_hex().

🤖 Generated with Claude Code

get_hex() wrote hex bytes in a loop but never wrote a NUL terminator,
leaving *attribute unterminated when called from the V_ASN1_OCTET_STRING
and V_ASN1_BIT_STRING branches. With a zero-length input the buffer was
entirely uninitialised, making any downstream strlen()/*attribute access
undefined behaviour.

- Add *out = '\0' after the loop in get_hex() so all callers get a
  terminated string regardless of length
- Increase Renew allocation at both call sites from length*4 to
  length*4+1 to ensure the terminator byte is always within bounds;
  this also avoids Renew(ptr, 0) when length is zero

Closes #63

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 19, 2026 13:45

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

Fixes undefined behavior in print_attribute() by ensuring get_hex() always NUL-terminates its output and by guaranteeing the caller allocates space for that terminator (including when the ASN.1 string length is zero). This addresses unterminated/garbage reads for OCTET STRING and BIT STRING attributes (issue #63).

Changes:

  • NUL-terminate get_hex() output unconditionally (*out = '\0' after the loop).
  • Increase OCTET STRING / BIT STRING Renew() allocations from length * 4 to length * 4 + 1 to keep the terminator in-bounds and avoid Renew(..., 0).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread PKCS12.xs
jonasbn and others added 6 commits June 19, 2026 16:50
…ttributes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…utes

Add test/pkcs12-info-zero-length-attributes.t to verify that zero-length
bag attributes (both OCTET STRING and BIT STRING) are correctly handled by
the get_hex() null-termination fix. The test loads the fixture from Task 2
and verifies that info_as_hash() returns empty strings for zero-length attrs.

Also improve the fixture generator script to manually encode the SEQUENCE OF
ContentInfo structure to avoid potential Convert::ASN1 nesting issues.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove unused \$OID_HMAC_SHA256 variable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@timlegge

Copy link
Copy Markdown
Contributor

@jonasbn this looks good to me

@jonasbn

jonasbn commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator Author

Thank!you @timlegge I will make a release shortly 😊

@jonasbn jonasbn merged commit 75f07c1 into master Jun 24, 2026
16 checks passed
jonasbn added a commit that referenced this pull request Jun 24, 2026
Spec covers generation script, fixture, test file, and documentation
for the regression test requested in Copilot review of PR #65.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jonasbn added a commit that referenced this pull request Jun 24, 2026
- Bump version to 1.97
- Add changelog entry: get_hex() NUL-termination fix (#63/#65),
  CertBag.certValue encoding fix, zero-length attribute regression test
- Add Convert::ASN1 as DevelopRequires in dist.ini so it survives dzil
  regeneration of cpanfile

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

get_hex() leaves buffer unterminated when length is zero (OCTET STRING / BIT STRING)

3 participants