Skip to content
Snippets Groups Projects
Commit 8def5a0d authored by Nick Mathewson's avatar Nick Mathewson :game_die:
Browse files

tor-rtcompat: Add support for rustls.

This is based on @janimo's approach in !74, but diverges in a few
important ways.

1. It assumes that something like !251 will merge, so that we can
   have separate implementations for native_tls and rustls compiled
   at the same time.

2. It assumes that we can implement this for the futures::io traits
   only with no real penalty.

3. It uses the `x509-signature` crate to work around the pickiness of
   the `webpki` crate.  If webpki eventually solves their
   [bug 219](https://github.com/briansmith/webpki/issues/219), we
   can remove a lot of that workaround.

Closes #86.
parent 979cfb46
No related branches found
No related tags found
1 merge request!260tor-rtcompat: Add support for a rustls backend
......@@ -292,6 +292,17 @@ dependencies = [
"winapi",
]
[[package]]
name = "async-rustls"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c86f33abd5a4f3e2d6d9251a9e0c6a7e52eb1113caf893dae8429bf4a53f378"
dependencies = [
"futures-lite",
"rustls",
"webpki",
]
[[package]]
name = "async-std"
version = "1.10.0"
......@@ -2092,6 +2103,21 @@ dependencies = [
"anyhow",
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rlimit"
version = "0.6.2"
......@@ -2146,6 +2172,19 @@ dependencies = [
"semver",
]
[[package]]
name = "rustls"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7"
dependencies = [
"base64",
"log",
"ring",
"sct",
"webpki",
]
[[package]]
name = "ryu"
version = "1.0.9"
......@@ -2178,6 +2217,16 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "sct"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.4.2"
......@@ -2984,15 +3033,18 @@ version = "0.0.3"
dependencies = [
"async-io",
"async-native-tls",
"async-rustls",
"async-std",
"async-trait",
"async_executors",
"futures",
"native-tls",
"pin-project",
"rustls",
"tokio",
"tokio-native-tls",
"tokio-util",
"x509-signature",
]
[[package]]
......@@ -3179,6 +3231,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.2.2"
......@@ -3329,6 +3387,16 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "webpki"
version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "wepoll-ffi"
version = "0.1.2"
......@@ -3371,6 +3439,16 @@ dependencies = [
"zeroize",
]
[[package]]
name = "x509-signature"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb2bc2a902d992cd5f471ee3ab0ffd6603047a4207384562755b9d6de977518"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "xz2"
version = "0.1.6"
......
......@@ -16,6 +16,7 @@ default = [ ]
async-std = [ "async-std-crate", "async-io", "async-native-tls" , "async_executors/async_std" ]
tokio = [ "tokio-crate", "tokio-util", "tokio-native-tls", "async_executors/tokio_tp" ]
static = [ "native-tls/vendored" ]
rustls = [ "rustls-crate", "async-rustls", "x509-signature" ]
[dependencies]
......@@ -24,6 +25,7 @@ async-trait = "0.1.2"
futures = "0.3"
pin-project = "1"
native-tls = "0.2"
rustls-crate = { package = "rustls", version = "0.19", optional = true, features = [ "dangerous_configuration" ] }
async-std-crate = { package = "async-std", version = "1.7.0", optional = true }
async-io = { version = "1.4.1", optional = true }
......@@ -33,3 +35,5 @@ tokio-crate = { package = "tokio", version = "1.4", optional = true, features =
tokio-util = { version = "0.6", features = ["compat"], optional = true }
tokio-native-tls = { version = "0.3.0", optional = true }
async-rustls = { version = "0.2.0", optional = true }
x509-signature = { version = "0.5.0", optional = true }
......@@ -4,20 +4,42 @@ use crate::{compound::CompoundRuntime, SpawnBlocking};
use crate::impls::async_std::NativeTlsAsyncStd;
#[cfg(feature = "rustls")]
use crate::impls::rustls::RustlsProvider;
#[cfg(feature = "rustls")]
use async_std_crate::net::TcpStream;
use async_executors::AsyncStd;
/// A [`Runtime`](crate::Runtime) powered by `async_std` and `native_tls`.
#[derive(Clone)]
pub struct AsyncStdRuntime {
/// The actual runtime object.
inner: Inner,
inner: NativeTlsInner,
}
/// Implementation type for AsyncStdRuntime.
type Inner = CompoundRuntime<AsyncStd, AsyncStd, AsyncStd, NativeTlsAsyncStd>;
type NativeTlsInner = CompoundRuntime<AsyncStd, AsyncStd, AsyncStd, NativeTlsAsyncStd>;
crate::opaque::implement_opaque_runtime! {
AsyncStdRuntime { inner : NativeTlsInner }
}
#[cfg(feature = "rustls")]
/// A [`Runtime`](crate::Runtime) powered by `async_std` and `rustls`.
#[derive(Clone)]
pub struct AsyncStdRustlsRuntime {
/// The actual runtime object.
inner: RustlsInner,
}
/// Implementation type for AsyncStdRustlsRuntime.
#[cfg(feature = "rustls")]
type RustlsInner = CompoundRuntime<AsyncStd, AsyncStd, AsyncStd, RustlsProvider<TcpStream>>;
#[cfg(feature = "rustls")]
crate::opaque::implement_opaque_runtime! {
AsyncStdRuntime { inner : Inner }
AsyncStdRustlsRuntime { inner: RustlsInner }
}
/// Return a new async-std-based [`Runtime`](crate::Runtime).
......@@ -25,7 +47,6 @@ crate::opaque::implement_opaque_runtime! {
/// Generally you should call this function only once, and then use
/// [`Clone::clone()`] to create additional references to that
/// runtime.
pub fn create_runtime() -> std::io::Result<AsyncStdRuntime> {
let rt = create_runtime_impl();
Ok(AsyncStdRuntime {
......@@ -33,6 +54,15 @@ pub fn create_runtime() -> std::io::Result<AsyncStdRuntime> {
})
}
/// Return a new [`Runtime`](crate::Runtime) based on `async_std` and `rustls`.
#[cfg(feature = "rustls")]
pub fn create_rustls_runtime() -> std::io::Result<AsyncStdRustlsRuntime> {
let rt = create_runtime_impl();
Ok(AsyncStdRustlsRuntime {
inner: CompoundRuntime::new(rt, rt, rt, RustlsProvider::default()),
})
}
/// Try to return an instance of the currently running async_std
/// [`Runtime`](crate::Runtime).
pub fn current_runtime() -> std::io::Result<AsyncStdRuntime> {
......
......@@ -7,3 +7,6 @@ pub(crate) mod async_std;
#[cfg(all(feature = "tokio"))]
pub(crate) mod tokio;
#[cfg(all(feature = "rustls"))]
pub(crate) mod rustls;
//! Implementation for using Rustls with a runtime.
use crate::traits::{CertifiedConn, TlsConnector, TlsProvider};
use async_rustls::webpki::{DNSNameRef, Error as WebpkiError};
use async_trait::async_trait;
use futures::{AsyncRead, AsyncWrite};
use rustls::{Session, TLSError};
use rustls_crate as rustls;
use std::{
io::{self, Error as IoError, Result as IoResult},
sync::Arc,
};
/// A [`TlsProvider`] that uses `rustls`.
///
/// It supports wrapping any reasonable stream type that implements `AsyncRead` + `AsyncWrite`.
#[non_exhaustive]
pub struct RustlsProvider<S> {
/// Inner `ClientConfig` logic used to create connectors.
config: Arc<async_rustls::rustls::ClientConfig>,
/// Phantom data to ensure proper variance.
_phantom: std::marker::PhantomData<fn(S) -> S>,
}
impl<S> CertifiedConn for async_rustls::client::TlsStream<S> {
fn peer_certificate(&self) -> IoResult<Option<Vec<u8>>> {
let (_, session) = self.get_ref();
Ok(session
.get_peer_certificates()
.and_then(|certs| certs.get(0).map(|c| Vec::from(c.as_ref()))))
}
}
/// An implementation of [`TlsConnector`] built with `rustls`.
pub struct RustlsConnector<S> {
/// The inner connector object.
connector: async_rustls::TlsConnector,
/// Phantom data to ensure proper variance.
_phantom: std::marker::PhantomData<fn(S) -> S>,
}
#[async_trait]
impl<S> TlsConnector<S> for RustlsConnector<S>
where
S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
type Conn = async_rustls::client::TlsStream<S>;
async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn> {
let name = get_dns_name(sni_hostname)?;
self.connector.connect(name, stream).await
}
}
impl<S> TlsProvider<S> for RustlsProvider<S>
where
S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
type Connector = RustlsConnector<S>;
type TlsStream = async_rustls::client::TlsStream<S>;
fn tls_connector(&self) -> Self::Connector {
let connector = async_rustls::TlsConnector::from(Arc::clone(&self.config));
RustlsConnector {
connector,
_phantom: std::marker::PhantomData,
}
}
}
impl<S> RustlsProvider<S> {
/// Construct a new [`RustlsProvider`.]
pub(crate) fn new() -> Self {
let mut config = async_rustls::rustls::ClientConfig::new();
// Be afraid: we are overriding the default certificate verification and
// TLS signature checking code! See notes on `Verifier` below for
// details.
//
// Note that the `set_certificate_verifier` function is somewhat
// misnamed: it overrides not only how certificates are verified, but
// also how certificates are used to check the signatures in a TLS
// handshake.
config
.dangerous()
.set_certificate_verifier(std::sync::Arc::new(Verifier {}));
RustlsProvider {
config: Arc::new(config),
_phantom: std::marker::PhantomData,
}
}
}
impl<S> Default for RustlsProvider<S> {
fn default() -> Self {
Self::new()
}
}
// We have to provide this ourselves, since derive(Clone) wrongly infers a
// `where S: Clone` bound (from the generic argument).
impl<S> Clone for RustlsProvider<S> {
fn clone(&self) -> Self {
Self {
config: Arc::clone(&self.config),
_phantom: std::marker::PhantomData,
}
}
}
// We have to provide this ourselves, since derive(Clone) wrongly infers a
// `where S: Clone` bound (from the generic argument).
impl<S> Clone for RustlsConnector<S> {
fn clone(&self) -> Self {
Self {
connector: self.connector.clone(),
_phantom: std::marker::PhantomData,
}
}
}
/// A [`rustls::ServerCertVerifier`] based on the [`x509_signature`] crate.
///
/// This verifier is necessary since Tor relays doesn't participate in the web
/// browser PKI, and as such their certificates won't check out as valid ones.
///
/// What's more, the `webpki` crate rejects most of Tor's certificates as
/// unparsable because they do not contain any extensions: That means we need to
/// replace the TLS-handshake signature checking functions too, since otherwise
/// `rustls` would think all the certificates were invalid.
///
/// Fortunately, the p2p people have provided `x509_signature` for this
/// purpose.
#[derive(Clone, Debug)]
struct Verifier {}
impl rustls::ServerCertVerifier for Verifier {
fn verify_server_cert(
&self,
_roots: &rustls::RootCertStore,
presented_certs: &[rustls::Certificate],
_dns_name: async_rustls::webpki::DNSNameRef,
_ocsp_response: &[u8],
) -> Result<rustls::ServerCertVerified, TLSError> {
// We don't check anything about the certificate at this point other
// than making sure it is well-formed.
//
// When we make a channel, we'll check that it's authenticated by the
// other party's real identity key, inside the Tor handshake.
//
// In theory, we shouldn't have to do even this much: rustls should not
// allow a handshake without a certificate, and the certificate's
// well-formedness should get checked below in one of the
// verify_*_signature functions. But this check is cheap, so let's
// leave it in.
let cert0 = presented_certs
.get(0)
.ok_or(TLSError::NoCertificatesPresented)?;
let _cert = get_cert(cert0)?;
// Note that we don't even check timeliness: Tor uses the presented
// relay certificate just as a container for the relay's public link
// key. Actual timeliness checks will happen later, on the certificates
// that authenticate this one, when we process the relay's CERTS cell in
// `tor_proto::channel::handshake`.
Ok(rustls::ServerCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
message: &[u8],
cert: &rustls::Certificate,
dss: &rustls::internal::msgs::handshake::DigitallySignedStruct,
) -> Result<rustls::HandshakeSignatureValid, rustls::TLSError> {
let cert = get_cert(cert)?;
let scheme = convert_scheme(dss.scheme)?;
let signature = dss.sig.0.as_ref();
// NOTE:
//
// We call `check_signature` here rather than `check_tls12_signature`.
// That means that we're allowing the other side to use signature
// algorithms that aren't actually supported by TLS 1.2.
//
// It turns out, apparently, unless my experiments are wrong, that
// OpenSSL will happily use PSS with TLS 1.2. At least, it seems to do
// so when invoked via native_tls in the test code for this crate.
cert.check_signature(scheme, message, signature)
.map(|_| rustls::HandshakeSignatureValid::assertion())
.map_err(|_| TLSError::WebPKIError(WebpkiError::InvalidSignatureForPublicKey))
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &rustls::Certificate,
dss: &rustls::internal::msgs::handshake::DigitallySignedStruct,
) -> Result<rustls::HandshakeSignatureValid, rustls::TLSError> {
let cert = get_cert(cert)?;
let scheme = convert_scheme(dss.scheme)?;
let signature = dss.sig.0.as_ref();
cert.check_tls13_signature(scheme, message, signature)
.map(|_| rustls::HandshakeSignatureValid::assertion())
.map_err(|_| TLSError::WebPKIError(WebpkiError::InvalidSignatureForPublicKey))
}
}
/// Convert a string into a `DnsNameRef`, if possible.
fn get_dns_name(s: &str) -> IoResult<DNSNameRef> {
DNSNameRef::try_from_ascii_str(s).map_err(|e| IoError::new(io::ErrorKind::InvalidInput, e))
}
/// Parse a `rustls::Certificate` as an `x509_signature::X509Certificate`, if possible.
fn get_cert(c: &rustls::Certificate) -> Result<x509_signature::X509Certificate, TLSError> {
x509_signature::parse_certificate(c.as_ref())
.map_err(|_| TLSError::WebPKIError(async_rustls::webpki::Error::BadDER))
}
/// Convert from the signature scheme type used in `rustls` to the one used in
/// `x509_signature`.
///
/// (We can't just use the x509_signature crate's "rustls" feature to have it
/// use the same enum from `rustls`, because it seems to be on a different
/// version from the rustls we want.)
fn convert_scheme(
scheme: rustls::internal::msgs::enums::SignatureScheme,
) -> Result<x509_signature::SignatureScheme, TLSError> {
use rustls::internal::msgs::enums::SignatureScheme as R;
use x509_signature::SignatureScheme as X;
Ok(match scheme {
R::RSA_PKCS1_SHA256 => X::RSA_PKCS1_SHA256,
R::ECDSA_NISTP256_SHA256 => X::ECDSA_NISTP256_SHA256,
R::RSA_PKCS1_SHA384 => X::RSA_PKCS1_SHA384,
R::ECDSA_NISTP384_SHA384 => X::ECDSA_NISTP384_SHA384,
R::RSA_PKCS1_SHA512 => X::RSA_PKCS1_SHA512,
R::RSA_PSS_SHA256 => X::RSA_PSS_SHA256,
R::RSA_PSS_SHA384 => X::RSA_PSS_SHA384,
R::RSA_PSS_SHA512 => X::RSA_PSS_SHA512,
R::ED25519 => X::ED25519,
R::ED448 => X::ED448,
R::RSA_PKCS1_SHA1 | R::ECDSA_SHA1_Legacy | R::ECDSA_NISTP521_SHA512 => {
// The `x509-signature` crate doesn't support these, nor should it really.
return Err(TLSError::PeerIncompatibleError(format!(
"Unsupported signature scheme {:?}",
scheme
)));
}
R::Unknown(_) => {
return Err(TLSError::PeerIncompatibleError(format!(
"Unrecognized signature scheme {:?}",
scheme
)))
}
})
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_cvt_scheme() {
use rustls::internal::msgs::enums::SignatureScheme as R;
use x509_signature::SignatureScheme as X;
macro_rules! check_cvt {
{ $id:ident } =>
{ assert_eq!(convert_scheme(R::$id).unwrap(), X::$id); }
}
check_cvt!(RSA_PKCS1_SHA256);
check_cvt!(RSA_PKCS1_SHA384);
check_cvt!(RSA_PKCS1_SHA512);
check_cvt!(ECDSA_NISTP256_SHA256);
check_cvt!(ECDSA_NISTP384_SHA384);
check_cvt!(RSA_PSS_SHA256);
check_cvt!(RSA_PSS_SHA384);
check_cvt!(ED25519);
check_cvt!(ED448);
assert!(convert_scheme(R::RSA_PKCS1_SHA1).is_err());
assert!(convert_scheme(R::Unknown(0x1337)).is_err());
}
}
......@@ -6,7 +6,7 @@
use std::convert::TryInto;
/// Types used for networking (tokio implementation)
mod net {
pub(crate) mod net {
use crate::traits;
use async_trait::async_trait;
......
No preview for this file type
......@@ -161,12 +161,12 @@ fn simple_tls<R: Runtime>(runtime: &R) -> IoResult<()> {
/*
A simple expired self-signed rsa-2048 certificate.
Generated using OpenSSL 1.1.1k with:
Generated by running the make-cert.c program in tor-rtcompat/test-data-helper,
and then making a PFX file using
openssl genpkey -algorithm RSA > test.key
openssl req -new -out - -key test.key > test.csr
openssl x509 -in test.csr -out test.crt -req -signkey test.key -days 0
openssl pkcs12 -export -certpbe PBE-SHA1-3DES -out test.pfx -inkey test.key -in test.crt
The password is "abc".
*/
static PFX_ID: &[u8] = include_bytes!("test.pfx");
// Note that we need to set a password on the pkcs12 file, since apparently
......@@ -242,6 +242,53 @@ macro_rules! runtime_tests {
}
}
macro_rules! tls_runtime_tests {
{ $($id:ident),* $(,)? } => {
#[cfg(feature="tokio")]
mod tokio_native_tls_tests {
use std::io::Result as IoResult;
$(
#[test]
fn $id() -> IoResult<()> {
super::$id(&crate::tokio::create_runtime()?)
}
)*
}
#[cfg(feature="async-std")]
mod async_std_native_tls_tests {
use std::io::Result as IoResult;
$(
#[test]
fn $id() -> IoResult<()> {
super::$id(&crate::async_std::create_runtime()?)
}
)*
}
#[cfg(all(feature="tokio", feature="rustls"))]
mod tokio_rusttls_tests {
use std::io::Result as IoResult;
$(
#[test]
fn $id() -> IoResult<()> {
super::$id(&crate::tokio::create_rustls_runtime()?)
}
)*
}
#[cfg(all(feature="async-std", feature="rustls"))]
mod async_std_rusttls_tests {
use std::io::Result as IoResult;
$(
#[test]
fn $id() -> IoResult<()> {
super::$id(&crate::async_std::create_rustls_runtime()?)
}
)*
}
}
}
runtime_tests! {
small_delay,
small_timeout_ok,
......@@ -249,5 +296,8 @@ runtime_tests! {
tiny_wallclock,
self_connect,
listener_stream,
}
tls_runtime_tests! {
simple_tls,
}
......@@ -5,6 +5,11 @@ use async_executors::TokioTp;
use crate::{CompoundRuntime, Runtime, SpawnBlocking};
use std::io::{Error as IoError, ErrorKind, Result as IoResult};
#[cfg(feature = "rustls")]
use crate::impls::rustls::RustlsProvider;
#[cfg(feature = "rustls")]
use crate::impls::tokio::net::TcpStream;
/// A [`Runtime`] built around a Handle to a tokio runtime, and `native_tls`.
///
/// # Limitations
......@@ -21,6 +26,18 @@ pub struct TokioRuntimeHandle {
/// Implementation type for a TokioRuntimeHandle.
type HandleInner = CompoundRuntime<Handle, Handle, Handle, NativeTlsTokio>;
/// A [`Runtime`] built around a Handle to a tokio runtime, and `rustls`.
#[derive(Clone)]
#[cfg(feature = "rustls")]
pub struct TokioRustlsRuntimeHandle {
/// The actual [`CompoundRuntime`] that implements this.
inner: RustlsHandleInner,
}
/// Implementation for a TokioRuntimeRustlsHandle
#[cfg(feature = "rustls")]
type RustlsHandleInner = CompoundRuntime<Handle, Handle, Handle, RustlsProvider<TcpStream>>;
/// A [`Runtime`] built around an owned `TokioTp` executor, and `native_tls`.
#[derive(Clone)]
pub struct TokioRuntime {
......@@ -28,9 +45,22 @@ pub struct TokioRuntime {
inner: TokioRuntimeInner,
}
/// A [`Runtime`] built around an owned `TokioTp` executor, and `rustls`.
#[derive(Clone)]
#[cfg(feature = "rustls")]
pub struct TokioRustlsRuntime {
/// The actual [`CompoundRuntime`] that implements this.
inner: TokioRustlsRuntimeInner,
}
/// Implementation type for TokioRuntime.
type TokioRuntimeInner = CompoundRuntime<TokioTp, TokioTp, TokioTp, NativeTlsTokio>;
/// Implementation type for TokioRustlsRuntime.
#[cfg(feature = "rustls")]
type TokioRustlsRuntimeInner =
CompoundRuntime<TokioTp, TokioTp, TokioTp, RustlsProvider<TcpStream>>;
crate::opaque::implement_opaque_runtime! {
TokioRuntimeHandle { inner : HandleInner }
}
......@@ -39,6 +69,16 @@ crate::opaque::implement_opaque_runtime! {
TokioRuntime { inner : TokioRuntimeInner }
}
#[cfg(feature = "rustls")]
crate::opaque::implement_opaque_runtime! {
TokioRustlsRuntimeHandle { inner : RustlsHandleInner }
}
#[cfg(feature = "rustls")]
crate::opaque::implement_opaque_runtime! {
TokioRustlsRuntime { inner : TokioRustlsRuntimeInner }
}
impl From<tokio_crate::runtime::Handle> for TokioRuntimeHandle {
fn from(h: tokio_crate::runtime::Handle) -> Self {
let h = Handle::new(h);
......@@ -55,6 +95,14 @@ fn create_tokio_runtime() -> IoResult<TokioRuntime> {
})
}
/// Create and return a new Tokio multithreaded runtime configured to use `rustls`.
#[cfg(feature = "rustls")]
fn create_tokio_rustls_runtime() -> IoResult<TokioRustlsRuntime> {
crate::impls::tokio::create_runtime().map(|r| TokioRustlsRuntime {
inner: CompoundRuntime::new(r.clone(), r.clone(), r, RustlsProvider::default()),
})
}
/// Create a new Tokio-based [`Runtime`].
///
/// Generally you should call this function only once, and then use
......@@ -69,6 +117,21 @@ pub fn create_runtime() -> std::io::Result<impl Runtime> {
create_tokio_runtime()
}
/// Create a new Tokio-based [`Runtime`] with `rustls`.
///
/// Generally you should call this function only once, and then use
/// [`Clone::clone()`] to create additional references to that
/// runtime.
///
/// Tokio users may want to avoid this function and instead make a
/// runtime using [`current_runtime()`]: this function always _builds_ a
/// runtime, and if you already have a runtime, that isn't what you
/// want with Tokio.
#[cfg(feature = "rustls")]
pub fn create_rustls_runtime() -> std::io::Result<impl Runtime> {
create_tokio_rustls_runtime()
}
/// Try to return an instance of the currently running tokio [`Runtime`].
///
/// # Usage note
......@@ -90,6 +153,18 @@ pub fn current_runtime() -> std::io::Result<TokioRuntimeHandle> {
})
}
/// Return an instance of the currently running tokio [`Runtime`], wrapped to
/// use `rustls`.
#[cfg(feature = "rustls")]
pub fn current_runtime_rustls() -> std::io::Result<TokioRustlsRuntimeHandle> {
let handle = tokio_crate::runtime::Handle::try_current()
.map_err(|e| IoError::new(ErrorKind::Other, e))?;
let h = Handle::new(handle);
Ok(TokioRustlsRuntimeHandle {
inner: CompoundRuntime::new(h.clone(), h.clone(), h, RustlsProvider::default()),
})
}
/// Run a test function using a freshly created tokio runtime.
///
/// # Panics
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment