Files
natsdotnet/gaps/tls-security.md
Joseph Doherty c30e67a69d Fix E2E test gaps and add comprehensive E2E + parity test suites
- Fix pull consumer fetch: send original stream subject in HMSG (not inbox)
  so NATS client distinguishes data messages from control messages
- Fix MaxAge expiry: add background timer in StreamManager for periodic pruning
- Fix JetStream wire format: Go-compatible anonymous objects with string enums,
  proper offset-based pagination for stream/consumer list APIs
- Add 42 E2E black-box tests (core messaging, auth, TLS, accounts, JetStream)
- Add ~1000 parity tests across all subsystems (gaps closure)
- Update gap inventory docs to reflect implementation status
2026-03-12 14:09:23 -04:00

31 KiB

TLS / Security — Gap Analysis

This file tracks what has and hasn't been ported from Go to .NET for the TLS / Security module. See stillmissing.md for the full LOC comparison across all modules.

LLM Instructions: How to Analyze This Category

Step 1: Read the Go Reference Files

Read each Go source file listed below. For every file:

  1. Extract all exported types (structs, interfaces, type aliases)
  2. Extract all exported methods on those types (receiver functions)
  3. Extract all exported standalone functions
  4. Note key constants, enums, and protocol states
  5. Note important unexported helpers that implement core logic (functions >20 lines)
  6. Pay attention to concurrency patterns (goroutines, mutexes, channels) — these map to different .NET patterns

Step 2: Read the .NET Implementation Files

Read all .cs files in the .NET directories listed below. For each Go symbol found in Step 1:

  1. Search for a matching type, method, or function in .NET
  2. If found, compare the behavior: does it handle the same edge cases? Same error paths?
  3. If partially implemented, note what's missing
  4. If not found, note it as MISSING

Step 3: Cross-Reference Tests

Compare Go test functions against .NET test methods:

  1. For each Go Test* function, check if a corresponding .NET [Fact] or [Theory] exists
  2. Note which test scenarios are covered and which are missing
  3. Check the parity DB (docs/test_parity.db) for existing mappings:
    sqlite3 docs/test_parity.db "SELECT go_test, dotnet_test, confidence FROM test_mappings tm JOIN go_tests gt ON tm.go_test_id=gt.rowid JOIN dotnet_tests dt ON tm.dotnet_test_id=dt.rowid WHERE gt.go_file LIKE '%PATTERN%'"
    

Step 4: Classify Each Item

Use these status values:

Status Meaning
PORTED Equivalent exists in .NET with matching behavior
PARTIAL .NET implementation exists but is incomplete (missing edge cases, error handling, or features)
MISSING No .NET equivalent found — needs to be ported
NOT_APPLICABLE Go-specific pattern that doesn't apply to .NET (build tags, platform-specific goroutine tricks, etc.)
DEFERRED Intentionally skipped for now (document why)

Step 5: Fill In the Gap Inventory

Add rows to the Gap Inventory table below. Group by Go source file. Include the Go file and line number so a porting LLM can jump directly to the reference implementation.

Key Porting Notes for TLS / Security

  • This category is at 12% LOC parity — one of the largest gaps.
  • OCSP stapling and peer validation are critical for mutual TLS deployments.
  • Cipher suite filtering allows operators to restrict which TLS ciphers are accepted.
  • PROXY protocol support enables running NATS behind HAProxy/nginx with real client IPs.
  • certstore provides OS certificate store access (Windows-specific parts may be NOT_APPLICABLE).
  • certidp implements certificate identity validation via OCSP responders.

Go Reference Files (Source)

  • golang/nats-server/server/ocsp.go — OCSP stapling configuration
  • golang/nats-server/server/ocsp_peer.go — OCSP peer certificate validation
  • golang/nats-server/server/ocsp_responsecache.go — OCSP response caching
  • golang/nats-server/server/ciphersuites.go — TLS cipher suite management and filtering
  • golang/nats-server/server/client_proxyproto.go — PROXY protocol v1/v2 support (HAProxy)
  • golang/nats-server/server/certidp/certidp.go — Certificate identity provider
  • golang/nats-server/server/certidp/messages.go — CertIDP message types
  • golang/nats-server/server/certidp/ocsp_responder.go — OCSP responder client
  • golang/nats-server/server/certstore/certstore.go — OS certificate store access
  • golang/nats-server/server/certstore/certstore_other.go — Non-Windows cert store
  • golang/nats-server/server/certstore/certstore_windows.go — Windows cert store
  • golang/nats-server/server/certstore/errors.go — Cert store errors

Go Reference Files (Tests)

  • golang/nats-server/test/ocsp_test.go (integration)
  • golang/nats-server/test/ocsp_peer_test.go (integration)
  • golang/nats-server/test/tls_test.go (integration)
  • golang/nats-server/server/certstore/certstore_windows_test.go
  • golang/nats-server/server/certidp/*_test.go

.NET Implementation Files (Source)

  • src/NATS.Server/Tls/TlsHelper.cs
  • src/NATS.Server/Tls/TlsCertificateProvider.cs
  • src/NATS.Server/Tls/TlsConnectionState.cs
  • src/NATS.Server/Tls/TlsConnectionWrapper.cs
  • src/NATS.Server/Tls/TlsRateLimiter.cs
  • src/NATS.Server/Tls/PeekableStream.cs
  • src/NATS.Server/Tls/OcspConfig.cs

.NET Implementation Files (Tests)

  • tests/NATS.Server.Tests/ (TLS-related test files in root)

Gap Inventory

ocsp.go — OCSP stapling configuration

Go Symbol Go File:Line Status .NET Equivalent Notes
OCSPMode (type) golang/nats-server/server/ocsp.go:46 PORTED src/NATS.Server/Tls/OcspConfig.cs:8 Mapped to OcspMode enum with matching values
OCSPModeAuto golang/nats-server/server/ocsp.go:49 PORTED src/NATS.Server/Tls/OcspConfig.cs:10 OcspMode.Auto = 0
OCSPModeAlways golang/nats-server/server/ocsp.go:52 PORTED src/NATS.Server/Tls/OcspConfig.cs:11 OcspMode.Always = 1
OCSPModeNever golang/nats-server/server/ocsp.go:55 PORTED src/NATS.Server/Tls/OcspConfig.cs:13 OcspMode.Never = 3
OCSPModeMust golang/nats-server/server/ocsp.go:60 PORTED src/NATS.Server/Tls/OcspConfig.cs:12 OcspMode.Must = 2
OCSPMonitor (struct) golang/nats-server/server/ocsp.go:65 MISSING No dedicated OCSP monitor struct; .NET delegates to SslStreamCertificateContext for stapling
OCSPMonitor.getNextRun golang/nats-server/server/ocsp.go:80 MISSING No periodic OCSP refresh loop
OCSPMonitor.getStatus golang/nats-server/server/ocsp.go:102 MISSING No cache/local/remote OCSP status retrieval
OCSPMonitor.getCacheStatus golang/nats-server/server/ocsp.go:119 MISSING No in-memory OCSP response caching
OCSPMonitor.getLocalStatus golang/nats-server/server/ocsp.go:125 MISSING No file-based OCSP status persistence
OCSPMonitor.getRemoteStatus golang/nats-server/server/ocsp.go:160 MISSING No manual OCSP responder HTTP callout; .NET relies on runtime OCSP
OCSPMonitor.run golang/nats-server/server/ocsp.go:272 MISSING No background goroutine for OCSP staple renewal
OCSPMonitor.stop golang/nats-server/server/ocsp.go:348 MISSING No explicit stop channel for OCSP monitor
Server.NewOCSPMonitor golang/nats-server/server/ocsp.go:357 PARTIAL src/NATS.Server/Tls/TlsHelper.cs:75 BuildCertificateContext delegates stapling to .NET runtime; missing per-kind config, VerifyConnection callbacks, shutdown-on-revoke
Server.setupOCSPStapleStoreDir golang/nats-server/server/ocsp.go:560 MISSING No OCSP store directory setup
tlsConfigKind (struct) golang/nats-server/server/ocsp.go:577 MISSING No per-listener TLS config kind abstraction
Server.configureOCSP golang/nats-server/server/ocsp.go:585 MISSING No multi-listener OCSP configuration loop
Server.enableOCSP golang/nats-server/server/ocsp.go:680 MISSING No server-level OCSP enablement orchestrator
Server.startOCSPMonitoring golang/nats-server/server/ocsp.go:717 MISSING No OCSP monitor goroutine dispatcher
Server.reloadOCSP golang/nats-server/server/ocsp.go:734 MISSING No OCSP hot-reload support
hasOCSPStatusRequest golang/nats-server/server/ocsp.go:804 MISSING No MustStaple TLS extension detection
OCSPMonitor.writeOCSPStatus golang/nats-server/server/ocsp.go:840 MISSING No atomic file write for OCSP status persistence
parseCertPEM golang/nats-server/server/ocsp.go:867 PORTED src/NATS.Server/Tls/TlsHelper.cs:33 Added ParseCertPem(string) with explicit PEM block scanning/validation (CERTIFICATE only), multi-cert bundle parsing, and typed failures on unexpected block types. LoadCaCertificates now uses this parser.
getOCSPIssuerLocally golang/nats-server/server/ocsp.go:892 MISSING No local issuer resolution from cert bundle
getOCSPIssuer golang/nats-server/server/ocsp.go:932 MISSING No issuer resolution logic
ocspStatusString golang/nats-server/server/ocsp.go:968 PORTED src/NATS.Server/Events/EventTypes.cs:647 OcspEventBuilder.ParseStatus and OcspStatus enum
validOCSPResponse golang/nats-server/server/ocsp.go:979 MISSING No manual OCSP response time validation

ocsp_peer.go — OCSP peer certificate validation

Go Symbol Go File:Line Status .NET Equivalent Notes
parseOCSPPeer golang/nats-server/server/ocsp_peer.go:29 PORTED src/NATS.Server/Configuration/ConfigProcessor.cs:1101 ParseOcspPeer supports short-form bool and long-form map parsing with Go-matching field names and conversion behavior
peerFromVerifiedChains golang/nats-server/server/ocsp_peer.go:130 MISSING No peer extraction from verified chains
Server.plugTLSOCSPPeer golang/nats-server/server/ocsp_peer.go:138 PARTIAL src/NATS.Server/Tls/TlsHelper.cs:36 .NET uses X509RevocationMode.Online when OcspPeerVerify set; missing full OCSP peer plugin pattern with per-chain validation
Server.plugClientTLSOCSPPeer golang/nats-server/server/ocsp_peer.go:163 PARTIAL src/NATS.Server/Tls/TlsHelper.cs:41 RemoteCertificateValidationCallback with revocation check, but no OCSP-specific chain walking or event publishing
Server.plugServerTLSOCSPPeer golang/nats-server/server/ocsp_peer.go:183 MISSING No leaf-spoke server-side OCSP peer plug
Server.tlsServerOCSPValid golang/nats-server/server/ocsp_peer.go:209 MISSING No server-side verified-chain OCSP evaluation
Server.tlsClientOCSPValid golang/nats-server/server/ocsp_peer.go:220 MISSING No client-side verified-chain OCSP evaluation
Server.peerOCSPValid golang/nats-server/server/ocsp_peer.go:225 MISSING No multi-chain OCSP eligibility walker
Server.certOCSPGood golang/nats-server/server/ocsp_peer.go:286 MISSING No per-link OCSP response fetch, cache check, delegation validation, and policy overrides (WarnOnly, AllowWhenCAUnreachable)
sendOCSPPeerRejectEvent golang/nats-server/server/ocsp_peer.go (ref) PARTIAL src/NATS.Server/Events/EventTypes.cs:612 OcspEventBuilder.BuildPeerReject exists as data builder but no actual event publishing to system account
sendOCSPPeerChainlinkInvalidEvent golang/nats-server/server/ocsp_peer.go (ref) PARTIAL src/NATS.Server/Events/EventTypes.cs:628 OcspEventBuilder.BuildChainValidation exists as data builder but no actual event publishing

ocsp_responsecache.go — OCSP response caching

Go Symbol Go File:Line Status .NET Equivalent Notes
OCSPResponseCacheType (type) golang/nats-server/server/ocsp_responsecache.go:44 MISSING No cache type enum (NONE/LOCAL)
OCSPResponseCacheConfig golang/nats-server/server/ocsp_responsecache.go:56 MISSING No OCSP cache configuration struct
NewOCSPResponseCacheConfig golang/nats-server/server/ocsp_responsecache.go:63 MISSING No cache config factory
OCSPResponseCacheStats golang/nats-server/server/ocsp_responsecache.go:72 MISSING No cache statistics tracking
OCSPResponseCacheItem golang/nats-server/server/ocsp_responsecache.go:81 MISSING No cache item model
OCSPResponseCache (interface) golang/nats-server/server/ocsp_responsecache.go:89 MISSING No cache interface (Put/Get/Delete/Start/Stop)
NoOpCache (struct) golang/nats-server/server/ocsp_responsecache.go:102 MISSING No no-op cache implementation
LocalCache (struct) golang/nats-server/server/ocsp_responsecache.go:155 MISSING No local file-backed OCSP response cache
LocalCache.Put golang/nats-server/server/ocsp_responsecache.go:167 MISSING No cache insert with S2 compression
LocalCache.Get golang/nats-server/server/ocsp_responsecache.go:201 MISSING No cache lookup with decompression
LocalCache.Delete golang/nats-server/server/ocsp_responsecache.go:245 MISSING No cache delete with preserve-revoked policy
LocalCache.Start golang/nats-server/server/ocsp_responsecache.go:272 MISSING No cache initialization from disk
LocalCache.Stop golang/nats-server/server/ocsp_responsecache.go:281 MISSING No cache shutdown and save
LocalCache.Compress / Decompress golang/nats-server/server/ocsp_responsecache.go:344 MISSING No S2 compression for OCSP responses
LocalCache.loadCache / saveCache golang/nats-server/server/ocsp_responsecache.go:371 MISSING No JSON-based disk persistence
Server.initOCSPResponseCache golang/nats-server/server/ocsp_responsecache.go:508 MISSING No cache initialization on server startup
Server.startOCSPResponseCache golang/nats-server/server/ocsp_responsecache.go:546 MISSING No cache start on server startup
Server.stopOCSPResponseCache golang/nats-server/server/ocsp_responsecache.go:564 MISSING No cache stop on server shutdown
parseOCSPResponseCache golang/nats-server/server/ocsp_responsecache.go:574 MISSING No config-file parsing for OCSP cache options

ciphersuites.go — TLS cipher suite management and filtering

Go Symbol Go File:Line Status .NET Equivalent Notes
cipherMap (var) golang/nats-server/server/ciphersuites.go:32 MISSING No cipher name-to-suite mapping; .NET handles cipher suites via SslServerAuthenticationOptions
cipherMapByID (var) golang/nats-server/server/ciphersuites.go:33 MISSING No cipher ID-to-suite mapping
defaultCipherSuites golang/nats-server/server/ciphersuites.go:35 NOT_APPLICABLE .NET TLS stack manages default cipher suites internally; no explicit enumeration needed
curvePreferenceMap (var) golang/nats-server/server/ciphersuites.go:45 NOT_APPLICABLE .NET does not expose curve preference ordering at application level
defaultCurvePreferences golang/nats-server/server/ciphersuites.go:55 NOT_APPLICABLE .NET runtime handles curve negotiation; FIPS mode handled by OS/.NET runtime config
init() cipher registration golang/nats-server/server/ciphersuites.go:21 NOT_APPLICABLE Go-specific init pattern; .NET populates cipher lists differently

client_proxyproto.go — PROXY protocol v1/v2 support

Go Symbol Go File:Line Status .NET Equivalent Notes
proxyProtoV2 constants golang/nats-server/server/client_proxyproto.go:28 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:54 All v2 constants mirrored
proxyProtoV1 constants golang/nats-server/server/client_proxyproto.go:63 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:82 All v1 constants mirrored
proxyProtoAddr (struct) golang/nats-server/server/client_proxyproto.go:81 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:11 ProxyAddress class with SrcIp, SrcPort, DstIp, DstPort
proxyProtoAddr.String golang/nats-server/server/client_proxyproto.go:89 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:20 ProxyAddress.ToString() with IPv6 bracket formatting
proxyProtoAddr.Network golang/nats-server/server/client_proxyproto.go:94 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:18 ProxyAddress.Network property
proxyConn (struct) golang/nats-server/server/client_proxyproto.go:102 MISSING No connection wrapper; .NET parser is pure buffer-based, integration with accept loop not yet wired
proxyConn.RemoteAddr golang/nats-server/server/client_proxyproto.go:109 MISSING Part of proxyConn; accept loop integration needed
detectProxyProtoVersion golang/nats-server/server/client_proxyproto.go:116 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:91 ProxyProtocolParser.Parse auto-detects v1/v2 from first 6 bytes
readProxyProtoV1Header golang/nats-server/server/client_proxyproto.go:134 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:117 ProxyProtocolParser.ParseV1 — buffer-based, all edge cases handled
readProxyProtoHeader golang/nats-server/server/client_proxyproto.go:226 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:91 ProxyProtocolParser.Parse covers both versions
readProxyProtoV2Header golang/nats-server/server/client_proxyproto.go:274 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:190 ProxyProtocolParser.ParseV2
parseProxyProtoV2Header golang/nats-server/server/client_proxyproto.go:301 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:208 ProxyProtocolParser.ParseV2AfterSig
parseIPv4Addr golang/nats-server/server/client_proxyproto.go:365 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:250 ParseIPv4 private method
parseIPv6Addr golang/nats-server/server/client_proxyproto.go:383 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:269 ParseIPv6 private method
error variables golang/nats-server/server/client_proxyproto.go:73 PORTED src/NATS.Server/Protocol/ProxyProtocol.cs:353 ProxyProtocolException and ProxyProtocolUnsupportedException

certidp/certidp.go — Certificate identity provider

Go Symbol Go File:Line Status .NET Equivalent Notes
DefaultAllowedClockSkew golang/nats-server/server/certidp/certidp.go:30 PORTED src/NATS.Server/Tls/OcspPeerConfig.cs:105 OCSPPeerConfig.DefaultAllowedClockSkew set to 30 seconds
DefaultOCSPResponderTimeout golang/nats-server/server/certidp/certidp.go:31 PORTED src/NATS.Server/Tls/OcspPeerConfig.cs:106 OCSPPeerConfig.DefaultOCSPResponderTimeout set to 2 seconds
DefaultTTLUnsetNextUpdate golang/nats-server/server/certidp/certidp.go:32 PORTED src/NATS.Server/Tls/OcspPeerConfig.cs:107 OCSPPeerConfig.DefaultTTLUnsetNextUpdate set to 1 hour
StatusAssertion (type) golang/nats-server/server/certidp/certidp.go:35 PORTED src/NATS.Server/Tls/OcspPeerConfig.cs:9 Added StatusAssertion enum with JSON converter and bidirectional string/int maps
GetStatusAssertionStr golang/nats-server/server/certidp/certidp.go:56 PORTED src/NATS.Server/Tls/OcspPeerConfig.cs:40 StatusAssertionMaps.GetStatusAssertionStr(int) with unknown fallback
ChainLink (struct) golang/nats-server/server/certidp/certidp.go:93 PORTED src/NATS.Server/Tls/OcspPeerConfig.cs:81 Added ChainLink type with Leaf, Issuer, and OCSPWebEndpoints
OCSPPeerConfig (struct) golang/nats-server/server/certidp/certidp.go:100 PORTED src/NATS.Server/Tls/OcspPeerConfig.cs:103 Added OCSPPeerConfig with matching fields and defaults
NewOCSPPeerConfig golang/nats-server/server/certidp/certidp.go:110 PORTED src/NATS.Server/Tls/OcspPeerConfig.cs:117 Added OCSPPeerConfig.NewOCSPPeerConfig() factory
Log (struct) golang/nats-server/server/certidp/certidp.go:123 NOT_APPLICABLE .NET uses ILogger injection; no need for function-pointer log struct
CertInfo (struct) golang/nats-server/server/certidp/certidp.go:131 PORTED src/NATS.Server/Tls/OcspPeerConfig.cs:88 Added CertInfo DTO with subject, issuer, fingerprint, and raw fields
GenerateFingerprint golang/nats-server/server/certidp/certidp.go:179 PORTED src/NATS.Server/Tls/TlsHelper.cs:95 Added GenerateFingerprint using SHA-256 of raw certificate bytes and base64 encoding
getWebEndpoints golang/nats-server/server/certidp/certidp.go:184 PORTED src/NATS.Server/Tls/TlsHelper.cs:101 Added GetWebEndpoints filtering to valid absolute HTTP/HTTPS URIs
GetSubjectDNForm golang/nats-server/server/certidp/certidp.go:203 PORTED src/NATS.Server/Tls/TlsHelper.cs:117 Added subject DN helper returning empty string for null cert
GetIssuerDNForm golang/nats-server/server/certidp/certidp.go:212 PORTED src/NATS.Server/Tls/TlsHelper.cs:122 Added issuer DN helper returning empty string for null cert
CertOCSPEligible golang/nats-server/server/certidp/certidp.go:221 PORTED src/NATS.Server/Tls/TlsHelper.cs:142 Added AIA OCSP responder extraction + HTTP(S) endpoint filtering, and populates ChainLink.OCSPWebEndpoints on success
GetLeafIssuerCert golang/nats-server/server/certidp/certidp.go:237 PORTED src/NATS.Server/Tls/TlsHelper.cs:165 Added positional issuer extraction helper (leafPos + 1) with bounds/self-signed guards
OCSPResponseCurrent golang/nats-server/server/certidp/certidp.go:250 PORTED src/NATS.Server/Tls/TlsHelper.cs:193 Added OCSP response currency window checks with configurable clock-skew and fallback TTL when NextUpdate is unset
ValidDelegationCheck golang/nats-server/server/certidp/certidp.go:288 PORTED src/NATS.Server/Tls/TlsHelper.cs:224 Added delegation validation: direct issuer response accepted, delegated responder requires OCSPSigning EKU

certidp/messages.go — CertIDP message types

Go Symbol Go File:Line Status .NET Equivalent Notes
Error message constants golang/nats-server/server/certidp/messages.go:17 PORTED src/NATS.Server/Tls/OcspPeerMessages.cs:6 Ported certidp error string constants (returned and directly-logged variants) into OcspPeerMessages
Debug message constants golang/nats-server/server/certidp/messages.go:47 PORTED src/NATS.Server/Tls/OcspPeerMessages.cs:36 Ported certidp debug-format constants used by OCSP peer/cache workflows
MsgTLSClientRejectConnection golang/nats-server/server/certidp/messages.go:81 PORTED src/NATS.Server/Tls/OcspPeerMessages.cs:5 Added literal reject reason constant for client OCSP validation failures
MsgTLSServerRejectConnection golang/nats-server/server/certidp/messages.go:82 PORTED src/NATS.Server/Tls/OcspPeerMessages.cs:6 Added literal reject reason constant for server OCSP validation failures
MsgCacheOnline / MsgCacheOffline golang/nats-server/server/certidp/messages.go:96 PORTED src/NATS.Server/Tls/OcspPeerMessages.cs:7 Added cache online/offline informational message templates

certidp/ocsp_responder.go — OCSP responder client

Go Symbol Go File:Line Status .NET Equivalent Notes
FetchOCSPResponse golang/nats-server/server/certidp/ocsp_responder.go:29 MISSING No HTTP-based OCSP response fetcher (GET with base64 encoding); .NET relies on X509Chain revocation
encodeOCSPRequest golang/nats-server/server/certidp/ocsp_responder.go:89 MISSING No DER-to-base64-to-URL encoding for OCSP requests

certstore/certstore.go — OS certificate store access

Go Symbol Go File:Line Status .NET Equivalent Notes
StoreType (type) golang/nats-server/server/certstore/certstore.go:24 NOT_APPLICABLE .NET has native X509Store; no need for Windows-specific store type enum
StoreMap / StoreOSMap golang/nats-server/server/certstore/certstore.go:34 NOT_APPLICABLE .NET handles store locations via X509StoreLocation enum
MatchByType (type) golang/nats-server/server/certstore/certstore.go:44 NOT_APPLICABLE .NET can use X509FindType enum for similar functionality
MatchByMap golang/nats-server/server/certstore/certstore.go:52 NOT_APPLICABLE .NET equivalent: X509FindType
ParseCertStore golang/nats-server/server/certstore/certstore.go:68 NOT_APPLICABLE .NET has built-in X509Store with StoreLocation
ParseCertMatchBy golang/nats-server/server/certstore/certstore.go:80 NOT_APPLICABLE .NET has X509FindType
GetLeafIssuer golang/nats-server/server/certstore/certstore.go:88 PORTED src/NATS.Server/Tls/TlsHelper.cs:176 Added verified-chain issuer resolver using custom-root trust and returning chain element issuer
credential (interface) golang/nats-server/server/certstore/certstore.go:99 NOT_APPLICABLE .NET uses X509Certificate2 with private key; no separate credential interface needed

certstore/certstore_other.go — Non-Windows cert store stub

Go Symbol Go File:Line Status .NET Equivalent Notes
otherKey (struct) golang/nats-server/server/certstore/certstore_other.go:27 NOT_APPLICABLE Go build-tag stub for non-Windows; .NET X509Store is cross-platform
TLSConfig (stub) golang/nats-server/server/certstore/certstore_other.go:29 NOT_APPLICABLE Build-tag stub; not needed in .NET

certstore/certstore_windows.go — Windows cert store

Go Symbol Go File:Line Status .NET Equivalent Notes
Windows CNG/NCrypt constants golang/nats-server/server/certstore/certstore_windows.go:42 NOT_APPLICABLE .NET X509Store abstracts away Windows CNG; no P/Invoke needed
winCertStore (struct) golang/nats-server/server/certstore/certstore_windows.go:352 NOT_APPLICABLE .NET X509Store handles store access natively
TLSConfig (Windows) golang/nats-server/server/certstore/certstore_windows.go:202 NOT_APPLICABLE .NET can use X509Store + X509Certificate2 directly; no syscall-level TLS config needed
winKey (struct) golang/nats-server/server/certstore/certstore_windows.go:528 NOT_APPLICABLE .NET X509Certificate2.GetRSAPrivateKey/GetECDsaPrivateKey handles this
winSignECDSA / winSignRSA* golang/nats-server/server/certstore/certstore_windows.go:562 NOT_APPLICABLE .NET runtime handles signing through X509Certificate2 private key
createCACertsPool golang/nats-server/server/certstore/certstore_windows.go:173 NOT_APPLICABLE .NET uses X509Certificate2Collection / X509Chain for CA pool
certByIssuer / certBySubject / certByThumbprint golang/nats-server/server/certstore/certstore_windows.go:390 NOT_APPLICABLE .NET uses X509Store.Certificates.Find() with X509FindType
unmarshalECC / winUnmarshalRSA golang/nats-server/server/certstore/certstore_windows.go:844 NOT_APPLICABLE .NET BCL handles key deserialization

certstore/errors.go — Cert store errors

Go Symbol Go File:Line Status .NET Equivalent Notes
ErrBadCryptoStoreProvider golang/nats-server/server/certstore/errors.go:9 NOT_APPLICABLE .NET X509Store throws its own exceptions
ErrBadRSAHashAlgorithm golang/nats-server/server/certstore/errors.go:12 NOT_APPLICABLE .NET runtime handles hash algorithm validation
ErrBadSigningAlgorithm golang/nats-server/server/certstore/errors.go:15 NOT_APPLICABLE .NET runtime handles signing
ErrStoreRSASigningError golang/nats-server/server/certstore/errors.go:18 NOT_APPLICABLE .NET CryptographicException covers this
ErrStoreECDSASigningError golang/nats-server/server/certstore/errors.go:21 NOT_APPLICABLE .NET CryptographicException covers this
ErrNoPrivateKeyStoreRef golang/nats-server/server/certstore/errors.go:24 NOT_APPLICABLE .NET checks HasPrivateKey
ErrExtractingPrivateKeyMetadata golang/nats-server/server/certstore/errors.go:27 NOT_APPLICABLE .NET handles internally
ErrExtractingECCPublicKey golang/nats-server/server/certstore/errors.go:30 NOT_APPLICABLE .NET handles internally
ErrExtractingRSAPublicKey golang/nats-server/server/certstore/errors.go:33 NOT_APPLICABLE .NET handles internally
ErrExtractingPublicKey golang/nats-server/server/certstore/errors.go:36 NOT_APPLICABLE .NET handles internally
ErrBadPublicKeyAlgorithm golang/nats-server/server/certstore/errors.go:39 NOT_APPLICABLE .NET handles internally
ErrExtractPropertyFromKey golang/nats-server/server/certstore/errors.go:42 NOT_APPLICABLE .NET handles internally
ErrBadECCCurveName golang/nats-server/server/certstore/errors.go:45 NOT_APPLICABLE .NET handles internally
ErrFailedCertSearch golang/nats-server/server/certstore/errors.go:48 NOT_APPLICABLE .NET X509Store.Find returns empty collection
ErrFailedX509Extract golang/nats-server/server/certstore/errors.go:51 NOT_APPLICABLE .NET handles internally
ErrBadMatchByType golang/nats-server/server/certstore/errors.go:54 NOT_APPLICABLE .NET uses enum
ErrBadCertStore golang/nats-server/server/certstore/errors.go:57 NOT_APPLICABLE .NET uses enum
ErrConflictCertFileAndStore golang/nats-server/server/certstore/errors.go:60 MISSING Config validation for conflicting cert_file + cert_store not ported
ErrBadCertStoreField golang/nats-server/server/certstore/errors.go:63 NOT_APPLICABLE Config validation
ErrBadCertMatchByField golang/nats-server/server/certstore/errors.go:66 NOT_APPLICABLE Config validation
ErrBadCertMatchField golang/nats-server/server/certstore/errors.go:69 NOT_APPLICABLE Config validation
ErrBadCaCertMatchField golang/nats-server/server/certstore/errors.go:72 NOT_APPLICABLE Config validation
ErrBadCertMatchSkipInvalidField golang/nats-server/server/certstore/errors.go:75 NOT_APPLICABLE Config validation
ErrOSNotCompatCertStore golang/nats-server/server/certstore/errors.go:78 NOT_APPLICABLE .NET X509Store is cross-platform

Keeping This File Updated

After porting work is completed:

  1. Update status: Change MISSING → PORTED or PARTIAL → PORTED for each item completed
  2. Add .NET path: Fill in the ".NET Equivalent" column with the actual file:line
  3. Re-count LOC: Update the LOC numbers in stillmissing.md:
    # Re-count .NET source LOC for this module
    find src/NATS.Server/Tls/ -name '*.cs' -type f -exec cat {} + | wc -l
    # Re-count .NET test LOC for this module
    # TLS tests are in root test directory — filter manually
    
  4. Add a changelog entry below with date and summary of what was ported
  5. Update the parity DB if new test mappings were created:
    sqlite3 docs/test_parity.db "INSERT INTO test_mappings (go_test_id, dotnet_test_id, confidence, notes) VALUES (?, ?, 'manual', 'ported in YYYY-MM-DD session')"
    

Change Log

Date Change By
2026-02-26 Ported parseCertPEM parity by adding strict PEM certificate parser (CERTIFICATE blocks only), wiring LoadCaCertificates through it, and adding focused TLS helper tests for invalid block rejection and multi-cert bundles. codex
2026-02-25 File created with LLM analysis instructions auto
2026-02-25 Completed full gap inventory: 12 Go source files analyzed, 144 symbols classified (20 PORTED, 9 PARTIAL, 70 MISSING, 45 NOT_APPLICABLE, 0 DEFERRED) claude-opus
2026-02-25 Ported OCSP eligibility/issuer/currentness/delegation helpers, certstore leaf issuer resolution, and certidp error/debug message constants with targeted TLS/Ocsp parity tests codex