fix(dgw): correct CredSSP credential injection for RDCleanPath#1668
Merged
Benoît Cortier (CBenoit) merged 2 commits intomasterfrom Feb 3, 2026
Merged
Conversation
Fixes several issues in the RDCleanPath credential injection flow: - Used wrong public key for client-side CredSSP: was using target server's public key instead of gateway's own public key. When performing credential injection, the client performs CredSSP authentication against the gateway. - Hardcoded HYBRID_EX security protocol regardless of client support: now properly negotiates based on what the client actually advertises. - Global cache for gateway public key only stored one entry: if multiple TLS acceptors with different certificates existed, wrong key could be returned. Now uses per-acceptor caching keyed by config pointer. - Missing `intercept_connect_confirm` call: the Connect Initial PDU wasn't being intercepted to update the server_selected_protocol field, causing protocol mismatch issues. - Token mismatch not verified: credential entry token wasn't compared against the received cleanpath PDU token. - Redundant authorization: `handle_with_credential_injection` was re-authorizing the token when `process_cleanpath` already does it. Now reuses claims from `process_cleanpath`. - Unused `_credential_store` parameter in `process_cleanpath`. - TLS utilities (`extract_tls_server_public_key`, `GetPeerCert`, `get_cached_gateway_public_key`) moved from rdp_proxy.rs to tls.rs. - Unnecessary `Sync + 'static` bounds on async stream types reduced to just `Send`. - Replaced `#[allow(...)]` with `#[expect(...)]` for suppressions. - Simplified `NetworkClient` struct into `send_network_request` function. - Various error handling improvements using `.context()` instead of `anyhow::anyhow!()`. - Updated sspi-rs with important fixes. Changelog: ignore
7db00b2 to
de909e4
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes several critical issues in the RDCleanPath credential injection flow for CredSSP authentication. The main problem was that the gateway was using the wrong public key (target server's instead of its own) when performing client-side CredSSP, along with other protocol negotiation and caching issues.
Changes:
- Fixed client-side CredSSP to use gateway's public key instead of target server's public key
- Implemented proper security protocol negotiation based on client capabilities (HYBRID vs HYBRID_EX)
- Refactored TLS certificate caching to use per-acceptor storage instead of a global single-entry cache
- Added missing
intercept_connect_confirmcall and token mismatch verification - Refactored code organization by moving TLS utilities to tls.rs and simplifying network client handling
- Updated sspi-rs dependency from 0.18.5 to 0.18.7 with important fixes
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| devolutions-gateway/src/tls.rs | Added per-acceptor certificate chain caching function and utility traits for extracting public keys from TLS streams |
| devolutions-gateway/src/rdp_proxy.rs | Removed TLS utilities (moved to tls.rs), simplified NetworkClient to a function, removed unnecessary trait bounds, updated to use new caching |
| devolutions-gateway/src/rd_clean_path.rs | Fixed credential injection to use gateway cert chain, added proper protocol negotiation, token verification, and intercept_connect_confirm call |
| Cargo.lock | Updated sspi-rs to 0.18.7 with related transitive dependency changes |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Vladyslav Nikonov (vnikonov-devolutions)
approved these changes
Feb 3, 2026
Contributor
Vladyslav Nikonov (vnikonov-devolutions)
left a comment
There was a problem hiding this comment.
LGTM!
disabled auto-merge in order to fix copilot comment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes several issues in the RDCleanPath credential injection flow:
Used wrong public key for client-side CredSSP: was using target server's public key instead of gateway's own public key. When performing credential injection, the client performs CredSSP authentication against the gateway.
Hardcoded HYBRID_EX security protocol regardless of client support: now properly negotiates based on what the client actually advertises.
Global cache for gateway public key only stored one entry: if multiple TLS acceptors with different certificates existed, wrong key could be returned. Now uses per-acceptor caching keyed by config pointer.
Missing
intercept_connect_confirmcall: the Connect Initial PDU wasn't being intercepted to update the server_selected_protocol field, causing protocol mismatch issues.Token mismatch not verified: credential entry token wasn't compared against the received cleanpath PDU token.
Redundant authorization:
handle_with_credential_injectionwas re-authorizing the token whenprocess_cleanpathalready does it. Now reuses claims fromprocess_cleanpath.Unused
_credential_storeparameter inprocess_cleanpath.TLS utilities (
extract_tls_server_public_key,GetPeerCert,get_cached_gateway_public_key) moved from rdp_proxy.rs to tls.rs.Unnecessary
Sync + 'staticbounds on async stream types reduced to justSend.Replaced
#[allow(...)]with#[expect(...)]for suppressions.Simplified
NetworkClientstruct intosend_network_requestfunction.Various error handling improvements using
.context()instead ofanyhow::anyhow!().Updated sspi-rs with important fixes.
Changelog: ignore