Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access rustls::Session from hyper::Service #2463

Closed
ipetr0v opened this issue Mar 11, 2021 · 5 comments
Closed

Access rustls::Session from hyper::Service #2463

ipetr0v opened this issue Mar 11, 2021 · 5 comments

Comments

@ipetr0v
Copy link

ipetr0v commented Mar 11, 2021

Currently the parameters of hyper::Service::call only include a Request. And I'm curious if it's possible to access TCP/TLS connection internals somewhere from the Service. For example access rustls::Session .

Accessing TLS session could be useful for multiple reasons, for example for implementing applications that rely on the TLS Keying Material (provided by rustls::Session::export_keying_material).

Originally posted in rustls/hyper-rustls#146

cc @tiziano88

@seanmonstar
Copy link
Member

If it's connection related data, you could collect that and make it part of your impl Service, such that on each request you can just access self.tls_session or what-not.

For example:

// probably in a while loop?
let socket = listener.accept().await?;

// probably spawn the TLS handshake into a new task to not block the accept loop?
let tls = rustls_accept(socket, config).await?;

let session = tls.session().clone();
let svc = MyAppSvc { session };
hyper::server::conn::Http::new().serve_connection(tls, svc).await?

@ipetr0v
Copy link
Author

ipetr0v commented Apr 24, 2021

Is it possible to do a similar thing on the client side?

IIUC there is an HttpsConnector::call that can return a TlsStream, from which TLS session can be accessed.

But the problem is that there is no way to use this session afterwards with hyper::Client, because it will try to create a new session, since it has already been called.

@sfackler
Copy link
Contributor

You can make a wrapper around the HttpsConnector that adds whatever data you need via the Connected::extras method, which will end up in the extensions field in the response.

@ipetr0v
Copy link
Author

ipetr0v commented Apr 24, 2021

The question is more about how to extract a TlsSession (and corresponding KeyingMaterial), while still being able to use hyper::Client to connect to the server.

@ipetr0v
Copy link
Author

ipetr0v commented Apr 28, 2021

If I understand correctly, the only way to access TlsStream is to do HttpsConnector::call

let mut https_connector = hyper_rustls::HttpsConnector::from((http_connector, tls_config));
let mut https_stream = https_connector.call(dst).await.unwrap();
let keying_material = match https_stream {
    MaybeHttpsStream::Https(ref mut tls_stream) => {
        let (tcp_stream, session) = tls_stream.get_mut();
        KeyingMaterial::export(session).expect("Couldn't generate keying material")

But the problem is that I cannot use this https_connector in the Client after this, since it already created a connection, and the Client will just create a new TLS connection.

In order to force Client to use the same connection for consecutive requests I also tried to create a custom HttpsConnector and do all the keying material negotiation inside the call function:

impl<T> Service<Uri> for CustomConnector<T>
...
    fn call(&mut self, dst: Uri) -> Self::Future {
        let http_connector = self.http_connector.clone();
        let tls_config = self.tls_config.clone();
        let result = async move {
            let mut https_connector = hyper_rustls::HttpsConnector::from((http_connector, tls_config));
            let mut https_stream = https_connector.call(dst).await.unwrap();
            match https_stream {
                MaybeHttpsStream::Https(ref mut tls_stream) => {
                    let keying_material = {
                        let (tcp_stream, session) = tls_stream.get_mut();
                        KeyingMaterial::export(session).expect("Couldn't generate keying material")
                    };
                    // Send keying material in a separate HTTP request.
                    ...
                }
            }
            Ok(https_stream)
        };
        Box::pin(result)
    }

But the problem is similar: once I get tls_stream, I cannot use hyper::Client and have to send and receive raw HTTP requests through tokio_rustls::client::TlsStream.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants