Home > Blockchain >  Use async-native-tls with a custom CA
Use async-native-tls with a custom CA

Time:01-27

I'm attempting to connect to a transparent Burp proxy using async-native-tls. The way the transparent Burp proxy works is that it generates a new TLS cert based on the SNI parameter of incoming TLS connections on the fly. These TLS certs it generates are all signed by a Burp CA.

When I run my code, I get an error from OpenSSL complaining about a self-signed certificate in the chain. That's totally expected. In fact, all TLS certificate chains have a self-signed certificate in the path -- the CA! I believe I've correctly configured the Burp CA certificate as an alternative to the system CA.

Below are the relevant snippets.

use async_native_tls::{Certificate, TlsConnector};
use http_client::hyper::HyperClient;
use http_client::{hyper, Config, HttpClient, Request};
use std::error::Error;
use std::sync::Arc;

let mut tls_builder = native_tls::TlsConnector::builder();
tls_builder
  // This is important, as it's how Burp knows which certificate to present
  .use_sni(true)
  // This is important, as it indicates that Burp's CA should be trusted
  .add_root_certificate(Certificate::from_pem(
    std::fs::read("/tmp/ca.pem")?.as_slice(),
  )?)
  // These should not be required, but I've turned them on in despairation
  .danger_accept_invalid_hostnames(true)
  .danger_accept_invalid_certs(true)
  .disable_built_in_roots(true)
  .max_protocol_version(None)
  .min_protocol_version(None);

let burp_proxy_tls = TlsConnector::from(tls_builder);
let burp_proxy_config = Config::default().set_tls_config(Some(Arc::new(burp_proxy_tls)));
let mut http_client = HyperClient::new();
http_client.set_config(burp_proxy_config)?;
let mut request = Request::get("https://127.0.0.1:8000/...");
request.append_header("Cookie", "...");
// Not strictly needed since it's also in SNI
request.append_header("Host", "...");
let mut response = http_client.send(request).await?;

When I connect via s_client, everything verifies OK:

$ openssl s_client -connect 127.0.0.1:8000 \
 -servername www......com \
 -CAfile /tmp/ca.pem \
 </dev/null
CONNECTED(00000003)
depth=1 C = PortSwigger, ST = PortSwigger, L = PortSwigger, O = PortSwigger, OU = PortSwigger CA, CN = PortSwigger CA
verify return:1
depth=0 C = PortSwigger, O = PortSwigger, OU = PortSwigger CA, CN = www......com
verify return:1
---
Certificate chain
 0 s:C = PortSwigger, O = PortSwigger, OU = PortSwigger CA, CN = www........com
   i:C = PortSwigger, ST = PortSwigger, L = PortSwigger, O = PortSwigger, OU = PortSwigger CA, CN = PortSwigger CA
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Jan 10 02:29:14 2023 GMT; NotAfter: Jan 10 02:29:14 2024 GMT
 1 s:C = PortSwigger, ST = PortSwigger, L = PortSwigger, O = PortSwigger, OU = PortSwigger CA, CN = PortSwigger CA
   i:C = PortSwigger, ST = PortSwigger, L = PortSwigger, O = PortSwigger, OU = PortSwigger CA, CN = PortSwigger CA
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Jan 24 00:53:54 2014 GMT; NotAfter: Jan 24 00:53:54 2033 GMT
...
subject=C = PortSwigger, O = PortSwigger, OU = PortSwigger CA, CN = www.......com
issuer=C = PortSwigger, ST = PortSwigger, L = PortSwigger, O = PortSwigger, OU = PortSwigger CA, CN = PortSwigger CA
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 2521 bytes and written 403 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
DONE

But then the program fails:

$ cargo run
    Finished dev [unoptimized   debuginfo] target(s) in 0.15s
     Running `target/debug/xxxxxx`

Error: error trying to connect: error:0A000086:SSL routines:tls_post_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1889: (self-signed certificate in certificate chain)

Caused by:
    0: error:0A000086:SSL routines:tls_post_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1889: (self-signed certificate in certificate chain)
    1: error:0A000086:SSL routines:tls_post_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1889:

CodePudding user response:

Well, I never did figure out if this was possible with the async-native-tls library. I wasn't tied to that library so I switched to isahc since it was backed by CURL and I know I can get that to do what I want.

I did have to switch my burp proxy to port 443 because isahc doesn't support --connect-to yet, but I can work with that.

let http_client = HttpClient::builder()
        .dns_resolve(ResolveMap::new().add("www.......com", 443, [127, 0, 0, 1]))
        .ssl_ca_certificate(CaCertificate::file("/tmp/ca.pem"))
        .ssl_options(SslOption::DANGER_ACCEPT_INVALID_CERTS)
        .automatic_decompression(true)
        .build()?;

    let request = Request::get("https://www.......com/....")
        .header("Cookie", cookies)
        .body(())?;
    let mut response = http_client.send(request)?;
  • Related