Skip to content

fix: skip subjects with odd-length backslash runs in sync guard (#30)#31

Open
spbsoluble wants to merge 4 commits into
release-1.3from
fix/issue-30-subject-guard-backslash
Open

fix: skip subjects with odd-length backslash runs in sync guard (#30)#31
spbsoluble wants to merge 4 commits into
release-1.3from
fix/issue-30-subject-guard-backslash

Conversation

@spbsoluble

@spbsoluble spbsoluble commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Fixes #30.

Problem

GCP CAS issues certificates whose subject is not valid RFC 4514 (e.g. a CN ending in a dangling \). The AnyCA Gateway parses the subject with BouncyCastle's X509Name when building its /v2/certificate/search response; on such a subject that call throws badly formatted directory string, the search page 500s, and Command's Full Scan aborts. Deterministic and recurs every scan.

The 1.3.3 guard tried to pre-empt this by running the same X509Name parse locally — but the plugin bundled BouncyCastle 2.0.0, whose parser is lenient and never throws on these shapes, so they were admitted and still broke the downstream sync.

Fix — match the gateway's parser instead of guessing

Pin BouncyCastle.Cryptography 2.6.2, the same strict build the gateway uses, and let the guard run the gateway's exact parse:

  • Verified 2.6.2 throws on precisely the shapes the gateway rejects (CN=…\, CN=…\, OU=…) with the identical error-message spelling the gateway logged, and accepts valid escapes the gateway accepts (\HH hex, \,, \\). Our old 2.0.0 threw on none of them.
  • The guard is now a faithful reproduction of the gateway's accept/reject decision — no structural heuristic, no assumptions about .NET escaping. It skips only certs the gateway genuinely can't parse and no longer drops valid ones (the earlier odd-backslash-run heuristic wrongly skipped valid \HH/\, subjects).
  • Skips are logged at error level ([SYNC-SKIP], with request ID + subject + reason); a [SYNC-DIAG] summary reports handed/skipped counts; sync continues so a full sync completes.
  • Bonus: clears the known BouncyCastle 2.0.0 security advisories (NU1902).

Tests

GCPCAS.Tests/SubjectGuardTests.cs — pure unit tests (no GCP), via InternalsVisibleTo:

  • classifies dangling-backslash shapes as rejected (CN=…\, CN=…\, OU=…, bare CN=a,b) and valid ones as accepted (baselines, \\, \\\\, and notably \bc hex + \, — the false positives the old heuristic produced);
  • two real self-signed certs (trailing-backslash CN rejected, well-formed accepted).

12 unit tests pass, 0 fail, 4 integration skipped. Builds clean on net6.0/net8.0/net10.0.

Base branch note

Branched off tag 1.3.3 behavior and targets release-1.3, whose committed merge-conflict markers (CHANGELOG.md, GCPCAS/Client/GCPCASClient.cs) are resolved here the same way #27 does — keeping the release-1.3 side.

* chore: Update integration-manifest.json (#16)

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* release: 1.3.0

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* fixed sans issue passed to extension data (#23)

* fixed sans issue passed to extension data

* fixed change log

---------

Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>

* 200dayfixes (#25)

* chore: Update integration-manifest.json

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Merge 1.3.1 to main


Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Merge 1.3.2 to main (#24)

* chore: Update integration-manifest.json (#16)

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* release: 1.3.0

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* fixed sans issue passed to extension data (#23)

* fixed sans issue passed to extension data

* fixed change log

---------

Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Add FlowLogger and sync diagnostics for certificate metadata troubleshooting

Port the FlowLogger workflow-tracing utility from the cscglobal-caplugin
200dayfixes branch and wire it into the plugin's Synchronize, Enroll, and
GetSingleRecord operations to render step-by-step, timed flow diagrams to
Trace logs.

Add [SYNC-DIAG] instrumentation in GCPCASClient that, for every certificate
handed to the AnyCA Gateway during sync, parses the PEM content and logs the
fingerprint (thumbprint), NotBefore (as epoch ms), NotAfter, serial number,
and subject - i.e. the exact metadata the Gateway must surface to Command on
/v2/certificate/search and that the incremental sync gates on. Records whose
content is null/empty or unparseable are flagged, pinpointing whether empty
fingerprint / notBefore=0 values originate in the plugin.

* Add net10.0 to target frameworks

* Skip certs with gateway-unparseable subjects during sync

During Synchronize, mirror the subject parsing the AnyCA Gateway performs
when building its /v2/certificate/search response
(new X509Name(true, netCert.Subject)). That call throws on subjects
BouncyCastle cannot re-parse from .NET's string representation, which returns
a 500 for the entire search page and aborts Command's CA sync.

GatewayCanParseSubject runs the same parse on each certificate before it is
added to the sync buffer. Certificates that would throw are skipped with a
[SYNC-SKIP] warning and counted, so a single unparseable subject never lands
in the gateway database and can never break the downstream Command sync. The
gateway-side fix (try/catch or reading the subject from DER) will be handled
separately.

* update changelog

---------

Co-authored-by: Sean <1661003+spbsoluble@users.noreply.github.com>
Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>
Co-authored-by: Sean <1661003+spbsoluble@users.noreply.github.com>
PR #26 squash-merged release-1.3 commit f4fbf10, which had been
committed with unresolved conflict markers in CHANGELOG.md and
GCPCASClient.cs, leaving main uncompilable (CS8300 x27).

The intended resolution of every conflict block is the release-1.3
side, whose content is byte-identical to the 1.3.3 tag. Restore both
files from the 1.3.3 tag.
@spbsoluble
spbsoluble force-pushed the fix/issue-30-subject-guard-backslash branch 3 times, most recently from 1d2a3cf to acab53a Compare July 23, 2026 18:47
GCP CAS will issue certificates whose subject is not valid RFC 4514 (e.g.
a CN ending in a dangling backslash). The AnyCA Gateway parses the subject
with BouncyCastle's X509Name on its /v2/certificate/search response; on
such a subject that call throws 'badly formatted directory string', the
search page 500s, and Command's Full Scan aborts.

The 1.3.3 guard tried to pre-empt this by running the same X509Name parse
locally, but the plugin bundled BouncyCastle 2.0.0, whose parser is lenient
and never throws on these shapes - so they were admitted and still broke
the downstream sync.

Fix: pin BouncyCastle.Cryptography to 2.6.2, the same strict build the
gateway uses (verified: it throws on exactly the shapes the gateway
rejects, with the identical message spelling, and accepts valid escapes
such as \HH hex and \, that the gateway accepts). The guard now
faithfully reproduces the gateway's accept/reject decision - no structural
heuristic and no assumptions about .NET escaping - so it skips only certs
the gateway genuinely cannot parse and stops dropping valid ones. Skips are
logged at error level and sync continues. The upgrade also clears the known
BouncyCastle 2.0.0 security advisories.

Tests: pure unit regression tests for the guard predicate, plus a sync-loop
test (SyncSkipContinuationTests) that streams good/bad/good pages through
DownloadAllIssuedCertificates via a fake CertificateAuthorityServiceClient
and asserts the bad cert is skipped while the rest are buffered and the sync
completes. Adds an internal test-only GCPCASClient constructor to inject the
fake client, and a GCPCAS.Tests/README.md describing every test.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).
@spbsoluble
spbsoluble force-pushed the fix/issue-30-subject-guard-backslash branch from acab53a to a9cbb36 Compare July 23, 2026 18:57
…guard-backslash

# Conflicts:
#	CHANGELOG.md
#	GCPCAS/Client/GCPCASClient.cs
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.

2 participants