-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: clarify features exposed by ironrdp-tls (#325)
- ironrdp-v0.7.4
- ironrdp-v0.7.3
- ironrdp-v0.7.2
- ironrdp-v0.7.1
- ironrdp-v0.7.0
- ironrdp-v0.6.0
- ironrdp-v0.5.0
- ironrdp-tokio-v0.2.2
- ironrdp-tokio-v0.2.1
- ironrdp-tokio-v0.2.0
- ironrdp-tls-v0.1.2
- ironrdp-tls-v0.1.1
- ironrdp-tls-v0.1.0
- ironrdp-svc-v0.1.3
- ironrdp-svc-v0.1.2
- ironrdp-svc-v0.1.1
- ironrdp-session-v0.2.2
- ironrdp-session-v0.2.1
- ironrdp-session-v0.2.0
- ironrdp-server-v0.4.1
- ironrdp-server-v0.4.0
- ironrdp-server-v0.3.1
- ironrdp-server-v0.3.0
- ironrdp-rdpsnd-v0.3.0
- ironrdp-rdpsnd-v0.2.0
- ironrdp-rdpsnd-v0.1.1
- ironrdp-rdpsnd-v0.1.0
- ironrdp-rdpsnd-native-v0.1.3
- ironrdp-rdpsnd-native-v0.1.2
- ironrdp-rdpsnd-native-v0.1.1
- ironrdp-rdpsnd-native-v0.1.0
- ironrdp-rdpdr-v0.1.2
- ironrdp-rdpdr-v0.1.1
- ironrdp-rdpdr-v0.1.0
- ironrdp-rdpdr-native-v0.1.1
- ironrdp-rdpdr-native-v0.1.0
- ironrdp-rdcleanpath-v0.1.2
- ironrdp-rdcleanpath-v0.1.1
- ironrdp-rdcleanpath-v0.1.0
- ironrdp-pdu-v0.2.0
- ironrdp-pdu-v0.1.2
- ironrdp-pdu-v0.1.1
- ironrdp-input-v0.1.2
- ironrdp-input-v0.1.1
- ironrdp-input-v0.1.0
- ironrdp-graphics-v0.1.2
- ironrdp-graphics-v0.1.1
- ironrdp-graphics-v0.1.0
- ironrdp-futures-v0.1.2
- ironrdp-futures-v0.1.1
- ironrdp-futures-v0.1.0
- ironrdp-error-v0.1.2
- ironrdp-error-v0.1.1
- ironrdp-error-v0.1.0
- ironrdp-dvc-v0.1.2
- ironrdp-dvc-v0.1.1
- ironrdp-dvc-v0.1.0
- ironrdp-displaycontrol-v0.1.2
- ironrdp-displaycontrol-v0.1.1
- ironrdp-displaycontrol-v0.1.0
- ironrdp-core-v0.1.3
- ironrdp-core-v0.1.2
- ironrdp-core-v0.1.1
- ironrdp-connector-v0.3.1
- ironrdp-connector-v0.3.0
- ironrdp-connector-v0.2.2
- ironrdp-connector-v0.2.1
- ironrdp-cliprdr-v0.1.2
- ironrdp-cliprdr-v0.1.1
- ironrdp-cliprdr-v0.1.0
- ironrdp-cliprdr-native-v0.1.3
- ironrdp-cliprdr-native-v0.1.2
- ironrdp-cliprdr-native-v0.1.1
- ironrdp-cliprdr-native-v0.1.0
- ironrdp-cliprdr-format-v0.1.2
- ironrdp-cliprdr-format-v0.1.1
- ironrdp-cliprdr-format-v0.1.0
- ironrdp-blocking-v0.2.1
- ironrdp-blocking-v0.2.0
- ironrdp-async-v0.3.0
- ironrdp-async-v0.2.1
- ironrdp-async-v0.2.0
- ironrdp-ainput-v0.1.2
- ironrdp-ainput-v0.1.1
- ironrdp-ainput-v0.1.0
- ironrdp-acceptor-v0.3.0
- ironrdp-acceptor-v0.2.1
- ironrdp-acceptor-v0.2.0
Showing
6 changed files
with
233 additions
and
104 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,59 @@ | ||
# IronRDP TLS | ||
|
||
TLS boilerplate common with most IronRDP clients. | ||
|
||
This crate exposes three features for selecting the TLS backend: | ||
|
||
- `rustls`: use the rustls crate. | ||
- `native-tls`: use the native-tls crate. | ||
- `stub`: use a stubbed backend which fail at runtime when used. | ||
|
||
These features are mutually exclusive and only one may be enabled at a time. | ||
When more than one backend is enabled, a compile-time error is emitted. | ||
For this reason, no feature is enabled by default. | ||
|
||
The rationale is two-fold: | ||
|
||
- It makes deliberate the choice of the TLS backend. | ||
- It eliminates the risk of mistakenly enabling multiple backends at once. | ||
|
||
With this approach, it’s obvious which backend is enabled when looking at the dependency declaration: | ||
|
||
```toml | ||
# This: | ||
ironrdp-tls = { version = "x.y.z", features = ["rustls"] } | ||
|
||
# Instead of: | ||
ironrdp-tls = "x.y.z" | ||
``` | ||
|
||
There is also no default feature to disable: | ||
|
||
```toml | ||
# This: | ||
ironrdp-tls = { version = "x.y.z", features = ["native-tls"] } | ||
|
||
# Instead of: | ||
ironrdp-tls = { version = "x.y.z", default-features = false, features = ["native-tls"] } | ||
``` | ||
|
||
This is typically more convenient and less error-prone when re-exposing the features from another crate. | ||
|
||
```toml | ||
[features] | ||
rustls = ["ironrdp-tls/rustls"] | ||
native-tls = ["ironrdp-tls/native-tls"] | ||
stub-tls = ["ironrdp-tls/stub"] | ||
|
||
# This: | ||
[dependencies] | ||
ironrdp-tls = "x.y.z" | ||
|
||
# Instead of: | ||
[dependencies] | ||
ironrdp-tls = { version = "x.y.z", default-features = false } | ||
``` | ||
|
||
(This is worse when the crate is exposing other default features which are typically not disabled by default.) | ||
|
||
The stubbed backend is provided as an easy way to make the code compiles with minimal dependencies if required. |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
use std::io; | ||
|
||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt as _}; | ||
|
||
pub type TlsStream<S> = tokio_native_tls::TlsStream<S>; | ||
|
||
pub async fn upgrade<S>(stream: S, server_name: &str) -> io::Result<(TlsStream<S>, Vec<u8>)> | ||
where | ||
S: Unpin + AsyncRead + AsyncWrite, | ||
{ | ||
let mut tls_stream = { | ||
let connector = tokio_native_tls::native_tls::TlsConnector::builder() | ||
.danger_accept_invalid_certs(true) | ||
.use_sni(false) | ||
.build() | ||
.map(tokio_native_tls::TlsConnector::from) | ||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; | ||
|
||
connector | ||
.connect(server_name, stream) | ||
.await | ||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))? | ||
}; | ||
|
||
tls_stream.flush().await?; | ||
|
||
let server_public_key = { | ||
let cert = tls_stream | ||
.get_ref() | ||
.peer_certificate() | ||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))? | ||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "peer certificate is missing"))?; | ||
let cert = cert.to_der().map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; | ||
crate::extract_tls_server_public_key(&cert)? | ||
}; | ||
|
||
Ok((tls_stream, server_public_key)) | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
use std::io; | ||
|
||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt as _}; | ||
|
||
pub type TlsStream<S> = tokio_rustls::client::TlsStream<S>; | ||
|
||
pub async fn upgrade<S>(stream: S, server_name: &str) -> io::Result<(TlsStream<S>, Vec<u8>)> | ||
where | ||
S: Unpin + AsyncRead + AsyncWrite, | ||
{ | ||
let mut tls_stream = { | ||
let mut config = tokio_rustls::rustls::client::ClientConfig::builder() | ||
.with_safe_defaults() | ||
.with_custom_certificate_verifier(std::sync::Arc::new(danger::NoCertificateVerification)) | ||
.with_no_client_auth(); | ||
|
||
// This adds support for the SSLKEYLOGFILE env variable (https://wiki.wireshark.org/TLS#using-the-pre-master-secret) | ||
config.key_log = std::sync::Arc::new(tokio_rustls::rustls::KeyLogFile::new()); | ||
|
||
// Disable TLS resumption because it’s not supported by some services such as CredSSP. | ||
// | ||
// > The CredSSP Protocol does not extend the TLS wire protocol. TLS session resumption is not supported. | ||
// | ||
// source: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cssp/385a7489-d46b-464c-b224-f7340e308a5c | ||
config.resumption = tokio_rustls::rustls::client::Resumption::disabled(); | ||
|
||
let config = std::sync::Arc::new(config); | ||
|
||
let server_name = server_name.try_into().unwrap(); | ||
|
||
tokio_rustls::TlsConnector::from(config) | ||
.connect(server_name, stream) | ||
.await? | ||
}; | ||
|
||
tls_stream.flush().await?; | ||
|
||
let server_public_key = { | ||
let cert = tls_stream | ||
.get_ref() | ||
.1 | ||
.peer_certificates() | ||
.and_then(|certificates| certificates.first()) | ||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "peer certificate is missing"))?; | ||
crate::extract_tls_server_public_key(&cert.0)? | ||
}; | ||
|
||
Ok((tls_stream, server_public_key)) | ||
} | ||
|
||
mod danger { | ||
use std::time::SystemTime; | ||
|
||
use tokio_rustls::rustls::client::ServerCertVerified; | ||
use tokio_rustls::rustls::{Certificate, Error, ServerName}; | ||
|
||
pub(super) struct NoCertificateVerification; | ||
|
||
impl tokio_rustls::rustls::client::ServerCertVerifier for NoCertificateVerification { | ||
fn verify_server_cert( | ||
&self, | ||
_end_entity: &Certificate, | ||
_intermediates: &[Certificate], | ||
_server_name: &ServerName, | ||
_scts: &mut dyn Iterator<Item = &[u8]>, | ||
_ocsp_response: &[u8], | ||
_now: SystemTime, | ||
) -> Result<ServerCertVerified, Error> { | ||
Ok(tokio_rustls::rustls::client::ServerCertVerified::assertion()) | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
use std::io; | ||
use std::marker::PhantomData; | ||
use std::task::{Context, Poll}; | ||
|
||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; | ||
|
||
#[derive(Debug)] | ||
pub struct TlsStream<S> { | ||
_marker: PhantomData<S>, | ||
} | ||
|
||
impl<S> AsyncRead for TlsStream<S> { | ||
fn poll_read(self: std::pin::Pin<&mut Self>, _: &mut Context<'_>, _: &mut ReadBuf<'_>) -> Poll<io::Result<()>> { | ||
Poll::Ready(Ok(())) | ||
} | ||
} | ||
|
||
impl<S> AsyncWrite for TlsStream<S> { | ||
fn poll_write(self: std::pin::Pin<&mut Self>, _: &mut Context<'_>, _: &[u8]) -> Poll<Result<usize, io::Error>> { | ||
Poll::Ready(Ok(0)) | ||
} | ||
|
||
fn poll_flush(self: std::pin::Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), io::Error>> { | ||
Poll::Ready(Ok(())) | ||
} | ||
|
||
fn poll_shutdown(self: std::pin::Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), io::Error>> { | ||
Poll::Ready(Ok(())) | ||
} | ||
} | ||
|
||
pub async fn upgrade<S>(stream: S, server_name: &str) -> io::Result<(TlsStream<S>, Vec<u8>)> | ||
where | ||
S: Unpin + AsyncRead + AsyncWrite, | ||
{ | ||
// Do nothing and fail | ||
let _ = (stream, server_name); | ||
Err(io::Error::other("no TLS backend enabled for this build")) | ||
} |