SNI compatibility
jeromegn opened this issue · 2 comments
We've started using this crate to pre-parse the SNI and do some async work before handing it off to the synchronous rustls handshake.
We've stumbled on some issues parsing SNI in some scenarios. I'm not sure if it's just a question of different clients sending different TLS extension formats.
Here's an error we get:
Error(([170, 170, 0, 0, 0, 0, 0, 23, 0, 21, 0, 0, 18, 119, 119, 119, 46, 97, 109, 105, 114, 97, 104, 122, 97, 107, 121, 46, 99, 111, 109, 0, 23, 0, 0, 255, 1, 0, 1, 0, 0, 10, 0, 10, 0, 8, 218, 218, 0, 29, 0, 23, 0, 24, 0, 11, 0, 2, 1, 0, 0, 35, 0, 0, 0, 16, 0, 14, 0, 12, 2, 104, 50, 8, 104, 116, 116, 112, 47, 49, 46, 49, 0, 5, 0, 5, 1, 0, 0, 0, 0, 0, 13, 0, 20, 0, 18, 4, 3, 8, 4, 4, 1, 5, 3, 8, 5, 5, 1, 8, 6, 6, 1, 2, 1, 0, 18, 0, 0, 0, 27, 0, 3, 2, 0, 2, 122, 122, 0, 1, 0], Tag))
If I decode to UTF8 lossy, I get:
��www.amirahzaky.com�
���#h2http/1.1
zz
It looks like the data is in there? The error doesn't say this is incomplete, so I assume this is a parser issue?
Thanks for creating this, it's a huge time save for us.
This is how I'm parsing it btw:
let acceptor = store.get(&svc, &metrics, should_h2).await?;
let mut bytes = [0; 1024];
let n = io.peek(&mut bytes).await?;
log::trace!("read {} bytes from tls handshake", n);
let res = tls_parser::parse_tls_plaintext(&bytes);
match res {
Ok((_rem, record)) => {
// rem is the remaining data (not parsed)
// record is an object of type TlsRecord
log::trace!("record: {:?}", record);
match record.msg.get(0) {
Some(tls_parser::tls::TlsMessage::Handshake(
tls_parser::tls::TlsMessageHandshake::ClientHello(hello_contents),
)) => match hello_contents.ext {
Some(exts) => match tls_parser::tls_extensions::parse_tls_extension_sni(exts) {
Ok((_rem, tls_parser::tls_extensions::TlsExtension::SNI(sni))) => {
match sni.get(0) {
Some((tls_parser::tls_extensions::SNIType::HostName, hostname)) => {
let hostname = std::str::from_utf8(hostname)?;
log::debug!("got hostname: {}", hostname);
store.ensure_cert(svc, should_h2, hostname).await;
}
_ => log::warn!("unhandled SNI Type!"),
};
}
Err(e) => {
log::debug!("error decoding sni: {:?}", e);
}
_ => {
log::warn!("did not find SNI");
}
},
_ => {
log::warn!("could not get client hello contents");
}
},
_ => log::warn!("didn't care about message type..."),
};
}
Err(nom::Err::Incomplete(needed)) => {
log::error!(
"Defragmentation required (TLS record), needed: {:?}",
needed
);
}
Err(e) => {
log::debug!("parse_tls_plaintext failed: {:?}", e);
}
};
(I get the error at error decoding sni
line)
Here is the full record with debug formatting (for a different request):
TlsPlaintext { hdr: TlsRecordHeader { type: Handshake, version: Tls10, len: 211 }, msg: [Handshake(ClientHello(TlsClientHelloContents { version: Tls12, rand_time: 1273706538, rand_data: [c5 6a a5 92 f9 67 90 76 b6 b0 e4 fc 39 ee bb aa ea 27 4b 5e 78 ee e0 01 b7 45 2e d1], session_id: None, ciphers: [0xc02b(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), 0xc02f(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), 0xcca9(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), 0xcca8(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), 0xcc14(Unknown cipher), 0xcc13(Unknown cipher), 0xc00a(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA), 0xc014(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA), 0xc009(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA), 0xc013(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA), 0x009c(TLS_RSA_WITH_AES_128_GCM_SHA256), 0x0035(TLS_RSA_WITH_AES_256_CBC_SHA), 0x002f(TLS_RSA_WITH_AES_128_CBC_SHA), 0x000a(TLS_RSA_WITH_3DES_EDE_CBC_SHA)], comp: [Null], ext: Some([ff 01 00 01 00 00 00 00 23 00 21 00 00 1e 6d 65 64 69 61 2e 75 70 77 6f 72 74 68 79 2e 6d 61 74 74 65 72 73 6d 65 64 69 61 2e 69 6f 00 17 00 00 00 23 00 00 00 0d 00 16 00 14 06 01 06 03 05 01 05 03 04 01 04 03 03 01 03 03 02 01 02 03 00 05 00 05 01 00 00 00 00 33 74 00 00 00 12 00 00 00 10 00 17 00 15 02 68 32 08 73 70 64 79 2f 33 2e 31 08 68 74 74 70 2f 31 2e 31 00 0b 00 02 01 00 00 0a 00 06 00 04 00 17 00 18]) }))] }
My bad, I should've been parsing all extensions and iterating to find the SNI one.