[Devolutions Gateway] Validate the TLS certificate at service startup, not at first handshake
1 vote
Summary
When the Gateway cannot use its configured TLS certificate, it currently starts anyway, opens the listener, reports itself as healthy to the operating system, and only surfaces the problem once per incoming connection — deep in the log. Everything visible from the outside says the service is fine.
We would like the Gateway to validate its certificate at load time and fail loudly there.
What we saw
Our Gateway was configured to load its certificate from the Windows certificate store. The service account had no read permission on the private key. From the outside, the service looked perfectly healthy:
PS> Get-Service DevolutionsGateway Status Name DisplayName ------ ---- ----------- Running DevolutionsGateway Devolutions Gateway Service PS> Get-NetTCPConnection -LocalPort 7171 -State Listen LocalAddress LocalPort State ------------ --------- ----- :: 7171 Listen 0.0.0.0 7171 Listen
The startup sequence in the log was equally clean:
INFO devolutions_gateway::listener: Listening on https://[::]:7171 INFO devolutions_gateway::listener: Listening on https://0.0.0.0:7171 INFO devolutions_gateway: devolutions-gateway service started
The actual problem only appeared when a client connected, and then repeated for every single connection thereafter:
ERROR devolutions_gateway::tls::windows: Failed to resolve TLS certificate error="no usable certificate found in the system store; key acquisition failures: cert[0]: failed to acquire key: Error code 80090016" ERROR devolutions_gateway::listener: handle_https_peer failed error="TLS handshake failed: unexpected error: no server certificate chain resolved"
`0x80090016` is `NTE_BAD_KEYSET`. The message itself is excellent — it named the exact cause and we fixed it within a minute of finding it. The problem is where and when it appeared.
The request
Resolve the certificate once at service startup. If it cannot be loaded or its private key cannot be acquired, log that at startup with:
For example:
ERROR Cannot use configured TLS certificate.
Subject: CN=gateway.example.com
Store: LocalMachine\My
Service account: NT AUTHORITY\NetworkService
failed to acquire key: 0x80090016 (NTE_BAD_KEYSET)
-> Verify that the service account has read permission
on the certificate's private key.
Whether the service should then refuse to start, or start and report unhealthy, is a design decision we do not have a strong opinion on. What matters is that the condition is visible before a user tries to connect, rather than being inferred from a listener that accepts connections and drops every one of them.
Why this matters
The installer has performed certificate checks since 2026.2.x, which is a good addition — but it only covers configuration made through the installer. Any change afterwards is unchecked:
In all of those cases the installer's validation has long since run, and the next indication that something is wrong is a user reporting that they cannot connect.
There is already a `doctor` diagnostic that performs exactly the checks needed here — SAN presence, EKU `serverAuth`, missing intermediates. Running an equivalent check at service start would close the gap between "the installer said it was fine" and "it is fine right now".
---
Related request for Devolutions Server: surface the actual reason behind "Certificate could not be verified", which is the dialog users see when this condition occurs.