-
Notifications
You must be signed in to change notification settings - Fork 22
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
TLS (Transport Layer Security) #100
Comments
I made an informal proposal at today's WASI meeting today: https://docs.google.com/presentation/d/1C55ph_fSTRhb4A4Nlpwvp9JGy8HBL6A1MvgY2jrapyQ/edit?usp=sharing In a nutshell: I'd propose we translate the API of Rust's native-tls library to WIT as a starting point. As @badeend pointed out, we could start even simpler than that and add an e.g. |
If taking the native-tls API, the initial WIT version should aim to fill some of its current gaps:
PQC support in TLS is a hot topic at the moment and ensuring that the wasi-tls design allows the selection of TLSv1.3 and specific ciphersuites is important to ensuring that the design is flexible enough to support PQC related features that are coming. |
I drafted up an interface at: #104 I don't think a distinct let ip = resolve_addresses("example.com").await?[0];
let tcp_client = TcpSocket::new();
let (tcp_input, tcp_output) = tcp_client.connect(ip, 443).await;
let tls_client = TlsClient::new("example.com", SuspensionPoints::none()); /* A */
let tls_streams = tls_client.streams()?;
forward(tcp_input, tls_streams.public_output);
forward(tls_streams.public_input, tcp_output);
tls_client.resume(); /* B */
tls_streams.private_output.blocking_write_and_flush("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n");
let response = tls_streams.private_input.blocking_read();
println!(response);
/// Pump all data from `src` to `dest` on a background task
fn forward(src: InputStream, dest: OutputStream) -> JoinHandle {
spawn_blocking(|| {
loop {
dest.blocking_splice(src).await?;
}
})
} If you're wondering what the let id1 = PrivateIdentity::parse(
fs::read("private1.key"),
fs::read("public1.crt"),
)?;
let id2 = PrivateIdentity::parse(
fs::read("private2.key"),
fs::read("public2.crt"),
)?;
let tcp_server = TcpSocket::new();
tcp_server.bind(443);
tcp_server.listen();
loop {
let (tcp_client, tcp_input, tcp_output) = tcp_server.accept().await;
let tls_server = TlsServer::new(SuspensionPoints::ClientHello | SuspensionPoints::Accepted);
let tls_streams = tls_server.streams()?;
{
tls_client.configure_alpn_ids(["h2"]);
forward(tcp_input, tls_streams.public_output);
forward(tls_streams.public_input, tcp_output);
tls_server.resume(); // Accept initiate handshake
}
{
let suspension = wait_suspend(tls_server).await; // Wait for client hello
assert!(suspension.at() == SuspensionPoints::ClientHello);
// Select certificate based on SNI:
match suspension.requested_server_name()? {
Some("example.com") => {
tls_server.configure_identities([id1]);
}
_ => tls_server.configure_identities([id2]);
}
tls_server.resume(); // Continue handshake
}
{
let suspension = wait_suspend(tls_server).await; // Wait for handshake to complete
assert!(suspension.at() == SuspensionPoints::Accepted);
println!("Fully connected!");
tls_server.resume();
}
{
let request = tls_streams.private_input.blocking_read();
println!(request);
}
}
async fn wait_suspend(tls: TlsServer) {
loop {
let result = tls.suspend();
if result == Err(NotReady) {
tls.subscribe().block();
} else {
return result;
}
}
} |
Here is SslStream Platform Abstraction Layer (PAL) for dotnet running on Android (consuming Java API). I guess this is closest to what we need to do for WASI TLS on dotnet. TLSv1.3 only I think. |
The other important thing to notice about .NET's If I'm reading @badeend's draft interface correctly, it looks like we could do that by piping the |
I guess WASI stream will be |
Right, I was assuming we'd only support e.g. |
For reference, here are the thin wrappers I built around https://github.com/dicej/spin-dotnet-sdk/blob/main/src/InputStream.cs |
Pretty much, yes. 👍 The
Thanks for the links. Good to know what the dotnet team has already encountered and how they solved the various differences. Looking at the source for the Android backend and similarly for the OpenSSL backend; there's a lot of "intricate" code. Don't know if this is what you were suggesting, but; I don't we should attempt to emulate one of these existing backend interfaces with all its warts. Rather, I think we should start at the user-facing interface and work our way back from there.
Interesting, why's that? Can't you use |
Perhaps he meant "we can implement them, but using them means no concurrency" (which might be fine for simple use cases). |
I did some exploratory investigation on how much of the .NET interface is theoretically supported by the draft. The results are now included in the PR. Overall; not bad. What sticks out is that about half of the "Not supported"s are to do with lower-level primitives (cipher suites, hashing algorithms, their parameters, etc) i.e. the potential footguns. So we'll need to carefully consider if/how to expose them. |
Yes, we can implement it, but we would not do that for ST build, because
I think we are not "simple use case" with dotnet, but it may make sense for others.
Agreed, we don't want/need to implement full set of those features. I only shared it to broaden our design perspective. After we enable the initial experience, we will learn more. About the use cases which are not possible without those missing features. We can add more incrementally, hopefully without too many breaking changes. |
This is great, thanks! |
cc @ManickaP @karelz @wfurt could you guys please provide feedback about the proposed design of WASI interface definition for TLS stream And proposed scope for C# SslStream ? What would be major existing use-cases which would not work ? |
Adding @rzikm |
And it now also includes the same thing for Node.JS. |
Sorry for longer text, the topics/ideas kept accumulating as I read the two linked files. Re SslStream membersmost of the "Not supported" members are informative only and
Ssl(Client/Server)AuthenticationOptionsI assume "not supported" stands for lack of configuration support, not for lack of feature in general. lack of customizability of some features should not be a problem as long as the behavior is sane.
Re (Client/Server)CertificateContext and private-identityI see that the WIT file has
The 'private-identity' is more or less equivalent to the SslStreamCertificateContext, it is a certificate + intermediates + some extra info, so you can consider it supported. While on the topic of certificates, there is an important point to consider when designing APIs. Windows is very specific in a way how it works with certificates, basically, the sensitive operations with private keys are performed by a separate process (lsass) and application communicates with lsass over IPC. Applications refer to a certificate using a handle. This becomes somewhat problematic when attempting to send certificate chains when intermediates are not stored in the OS certificate store. The relevant SChannel API takes only a single certificate handle parameter, and attempts to build the certificate chain internally. Since the certificate chain is bulit by separate process and the intermediates are not in a store, lsass/Schannel can't find the intermediates, which can result in only the leaf certificate being sent over the wire, which in the end means connection errors because the remote peer may not be able to verify the certificate. In .NET, we workaround this fairly common case by inserting the intermediates to the cert stores when building the SslStreamCertificateContext. There is some discussion about the topic at dotnet/runtime#26323 The other reason I am bringing this up is that on Windows, Having an access to certificate handle does not mean you have access to a certificate private key. You can lookup certs in a store by Thumbprint and get handle back, but by configuration the application may not be able to export private key to be able to pass it to your API, so consider adding more options of creating Also, note that there are multiple binary formats for X509 certificates (DER, PKCS12, ...) so you probably want to reflect that in the suggested additionsI suggest adding following
otherwise the proposed API seems reasonable to be able to cover most of the use cases. Questions/other
cc @wfurt in case I forgot something. |
I've taken a subset of @badeend's draft WIT file and created .NET guest implementation providing a corresponding subset of the Next, @jsturtevant and I will lightly modify |
Quick update on the above: @jsturtevant and I were able to get a modified We didn't need anything fancy -- just this minimal subset of @badeend's proposed draft. I'm sure additional knobs would be needed for more advanced cases (e.g. client certificates), but we've demonstrated that the minimal subset is sufficient for a real-world scenario like this. |
Related dotnet/runtime#109569 |
TODO
https://github.com/Mbed-TLS/mbedtls
https://github.com/enarx-archive/tlssock
The text was updated successfully, but these errors were encountered: