Comments (21)
Reader
and ClientHelloPayload
are only public (AFAICT) via internals
:
Internal classes that are used in integration tests. The contents of this section DO NOT form part of the stable interface.
These are not intended to be used by downstream applications and are not bound by semver constraints.
from rustls.
👋 Hi there,
In our application we would like to make a decision based on contents of SNI in ClientHelloPayload
Have you looked at using the Acceptor
API? The Accepted::client_hello() fn's return type offers a server_name() fn for accesing the SNI value to make a decision.
If you look in the issue tracker I believe there have been previous discussions about exporting internal message types and this hasn't been something the project has been keen to support. In this case I'm not sure it's necessary at all given the Acceptor
API.
from rustls.
Thanks for a quick response. I think our use case is slightly different.
I would like to check if the incoming TCP stream is TLS. If it is TLS then I can pass the stream to rustls for proper processing. If the stream is not then we would like to process it as TCP.
The main problem with using the Acceptor (I am actually using LazyConfigAcceptor ) is that we can't get back the consumed bytes.
That's why I resolved to peeking bytes from TCP stream and then deserializing ClientHelloPayload
myself. In this respect if I can successfully deserialize ClientHelloPayload and get SNI, I can pass the stream to rustls acceptor and if I can't then I can treat it as a TCP stream.
Having ClientHelloPayload public as building block is a great simplification since I don't have to do my own parsing. Being able to retrieve extensions would simplify it even further.
from rustls.
@dawid-nowak have a look at rustls/tokio-rustls#54.
from rustls.
I also just submitted #1916, maybe it could help?
from rustls.
Super, i will need to dig deeper into it.
The use case here is similar to Envoy's TLS inspector .
My code looks pretty much as this snippet in rustls/tokio-rustls#54. We use something like below to figure out if the incoming stream is TCP/TLS.
So really, we are using public APIs anyway. The missing bit is to be able to get the extensions cleanly without having to re-writing/hacking at stuff that rustls is doing anyway :)
let mut reader = rustls::internal::msgs::codec::Reader::init(client_hello_buf);
let chp = ClientHelloPayload::read(&mut reader);
if let Ok(chp) = chp {
for ext in chp.extensions {
if let rustls::internal::msgs::handshake::ClientExtension::ServerName(ref req) = ext
{
for s in req {
let encoded_server_name = s.get_encoding();
if let Ok(Some(name)) = Self::parse_rustls_sever_name(encoded_server_name) {
return Self {
server_name: Some(name),
};
}
}
}
}
}
Self { server_name: None }
}
fn parse_rustls_sever_name(server_name: Vec<u8>) -> Result<Option<String>> {
// first skipped byte is rutls type server name type
// first two bytes is the encoded length;
let buf: [u8; 2] = server_name[1..3].try_into()?;
let len = u16::from_be_bytes(buf) as usize;
let range = &server_name[3..(3 + len)];
let dns = DnsName::try_from(range);
if let Ok(server_name) = dns {
Ok(Some(server_name.as_ref().to_ascii_lowercase()))
} else {
Ok(None)
}
}
I don't like the parse_rustls_sever_name
, the code is brittle since we need to guess rustls formats etc. it would be neater if there was an API available.
from rustls.
Perhaps we could also add an into_bytes()
method on Acceptor
that takes out the receive buffer, if that helps.
from rustls.
If I understand it correctly with into_bytes()
, I would still need to deserialize ClientHelloPayload
?
I get that my use case is pretty awkward :) but if you wanted to make changes to Acceptor
then I think you would need to expose some extra methods on the Acceptor
to allow the application to peek at client hello before calling accept
and/or to get back the full tcp stream if the information in the client hello doesn't match the needs.
from rustls.
Okay, I see how that doesn't work.
So maybe we should move the deframer_buffer.buf
into AcceptedAlert
, to allow you to recover the received bytes from there? Then if it fails to parse a ClientHello
you can get the bytes and turn them into a plaintext connection?
from rustls.
That could work... Still think that making impl ClientHelloPayload
would be easier and less error prone. Could you help me understand the rationale here ?
from rustls.
Why do you think it would be easier and less error prone?
from rustls.
Sure :) just for the conversations sake
I look at it from perspective of a user who is outside of the normal path and is happy to use low level building blocks provided to create something different.
ClientHelloPayload
is public and also Reader
is public so these two basic blocks are already available to the end user to start tinkering. The methods to find extensions are there but hidden. And since these methods are used internally, they are tested and verified. Exposing those methods is probably not a problem.
Yes, the application has a dependency on rustls low level building blocks which could change but at the same time it can trust that these blocks are sound.
Additionally, the normal flow of rustls is not affected. There are no changes to the APIs so the existing applications will work as normal.
That would be my thinking but I am happy to go with whichever way.
from rustls.
I left a comment with a WIP branch on #1916 but I think it makes more sense to discuss here.
Using the acceptor API and the fns on an accepted rustls::server::ClientHello
seems like it meets the need of the TLS side (mainly, dispatch by SNI/ALPN) without any new API surface/exports or cumbersome external deserialization.
I think what's lacking is a way to accept a plaintext connection in some cases. To solve that, what if instead of exposing the deframer buffer and having the caller need to figure out if its TLS we do the reverse and have the acceptor return the buffer when it has already decided it isn't TLS as part of a returned error?
I think that strikes a good balance. Existing TLS focused users can continue exactly as they do now, treating accept errors of any kind as fatal, sending an alert and closing. Users that want to dispatch non-TLS data can match on the new error type and unpack the data that Rustls couldn't deframe as the expected first TLS message. Does that seem workable?
from rustls.
Your WIP branch makes sense to me, though I'm not sure I understand the need for OtherError(Arc::new(..))
wrapping the internal error. Could it just be a boxed Error
? I think we could stick the buffer in AcceptedAlert
instead of in Error
, which seems simpler if a little bit weird. Also we should maybe file an issue for a simplifying revision the next time we decide to release a semver-incompatible API.
from rustls.
I think what's lacking is a way to accept a plaintext connection in some cases. To solve that, what if instead of exposing the deframer buffer and having the caller need to figure out if its TLS we do the reverse and have the acceptor return the buffer when it has already decided it isn't TLS as part of a returned error?
My feeling on this is: it is very clear within the first few bytes whether the conversation is TLS or not. It seems quite reasonable to have downstream code that wants to do plaintext and TLS on the same stream port to read the bytes and do the demultiplexing up-front?
from rustls.
Could it just be a boxed Error?
Yup! That's a better idea, not sure why I didn't think of that initially. I will change it out.
I think we could stick the buffer in AcceptedAlert instead of in Error, which seems simpler if a little bit weird.
I thought about this approach but it felt fairly unnatural. I'm not sure I understand what makes it simpler, except that it avoids adding a new variant to the Error
enum that's specific to the Acceptor
and not used elsewhere.
Also we should maybe file an issue for a simplifying revision the next time we decide to release a semver-incompatible API.
Yeah, that sounds like a good idea 👍
It seems quite reasonable to have downstream code that wants to do plaintext and TLS on the same stream port
@ctz Sorry, I'm having trouble mapping your response to an indicator of support/dissent for the proposal I have in mind. Are you thinking the demultiplexing shouldn't be done in Rustls and we should continue to expect it to be done donwstream ala the approach used in rustls/tokio-rustls#54 (comment) ?
from rustls.
Are you thinking the demultiplexing shouldn't be done in Rustls and we should continue to expect it to be done donwstream ala the approach used in rustls/tokio-rustls#54 (comment) ?
Yeah that's the sort of thing I had in mind.
from rustls.
wrong butan
from rustls.
Yeah that's the sort of thing I had in mind.
OK, I won't pursue turning the WIP branch into a PR in that case 👍
Should this issue be closed?
from rustls.
I am happy to close this for time being.
There seem to be two radically different approaches here and we can't get a consensus :
- Let rustls try to figure out if the stream is the TLS stream and if it is not then return back the consumed data (or stream) so the user can re-store the stream.
- Let the user try to figure out if the stream is TLS and then either use rustls or not.
I think Option 2 makes sense if for example the basic blocks to parse ClientHello are available as a public API. That would save people from having to re-invent the logic here and since those blocks are part of rustls then there is trust that the logic is good.
Option 1 is tightly integrated into rustls. Thing to consider here is that the new API would need to be exposed via higher level adapters such as tokio-rustls.
from rustls.
There seem to be two radically different approaches here and we can't get a consensus
From my read I think Option 3, the status quo, is where maintainer consensus is today.
Solutions outside of the crate are possible without change here (as demonstrated in the tokio-rustls issue). I think the parts required to do it reliably are already exposed under the internals
API namespace. Option 2 feels like elevating those parts out of that namespace in order to offer explicit support & semver consideration. That's a fair request, but I don't think its likely at this time. I liked Option 1, but since that wasn't unanimous and it isn't a use case myself or the folks funding my work feel strongly about I was swayed towards inaction :-)
from rustls.
Related Issues (20)
- Suggest registering for OpenSSF Best Practices badge HOT 9
- Pass ClientHello by reference to ResolvesServerCert HOT 2
- GHSA-6g7w-8wpp-frhj and CVE-2024-32650 don't make it clear that async rustls servers aren't susceptible HOT 2
- AWS LC fails against golang TLS server while ring works fine HOT 6
- Rustls w/ aws-lc-rs on Windows requires NASM HOT 33
- Question. Does rustls have something to hide cert (as it is sensitive data ) in binary and memory HOT 3
- Verify that SigningKey matches public key within certificate HOT 6
- Ensuring that a provider based on the one built-in is used HOT 8
- Compile error when target is watchos HOT 6
- Expose ability to customize ClientHello message HOT 4
- How I use CryptoProvider::install_default() ? HOT 3
- Illegal instruction on arm-a72 HOT 3
- Add RustCrypto cryptographic backend HOT 5
- Build rustls v0.23.5 with musl HOT 2
- UnbufferedConnectionState HOT 2
- Unbuffered process_tls_records does not mach usage scenario HOT 2
- Clean up crate feature naming
- build failure due to aws-lc-sys v0.16.0 HOT 1
- `UnknownIssuer` with self-signed certificate HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rustls.