# 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](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: ```bash 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`: ```bash # 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: ```bash 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 |