How to avoid calling potentially dangerous function

Guys, the code below works. But... Only if I have the call to "danger_accept_invalid_hostnames(true)"
The moment I don't have that call I'm getting error:
"called Result::unwrap() on an Err value: Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 167773202, library: "SSL routines", function: "ssl3_read_bytes", reason: "sslv3 alert bad certificate", file: "ssl/record/rec_layer_s3.c", line: 1586, data: "SSL alert number 42" }]))) }, X509VerifyResult { code: 0, error: "ok" })
"
I do "understand" what the error msg is saying, but what I don't understand is why is it saying it. I do provide certificate, so what's the issue?
Thanks in advance for help with that issue.

//Cargo.toml
[dependencies]
rcgen = "0.13.1"
tokio = { version = "1.41.1", features = ["full"] }
tokio-native-tls = "0.3.1"
//main.rs
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio_native_tls::native_tls::Identity;
use tokio_native_tls::{native_tls, TlsAcceptor, TlsConnector};

#[tokio::main]
async fn main() {
    let cert = rcgen::generate_simple_self_signed([]).unwrap();
    let listener = TcpListener::bind("127.0.0.1:8001").await.unwrap();

    let trusted = native_tls::Certificate::from_pem(cert.cert.pem().as_bytes()).unwrap();
    tokio::spawn(async move {
        let connector = TlsConnector::from(
            native_tls::TlsConnector::builder()
                .disable_built_in_roots(true)
                .add_root_certificate(trusted)
                .danger_accept_invalid_hostnames(true)
                .use_sni(false)
                .build()
                .unwrap(),
        );
        let tcp = TcpStream::connect("0.0.0.0:8001").await.unwrap();
        let mut tls = connector.connect("N/A", tcp).await.unwrap();
        tls.write_all(b"hello!").await.unwrap();
        tls.shutdown().await.unwrap();
    });

    let acceptor = TlsAcceptor::from(
        native_tls::TlsAcceptor::new(
            Identity::from_pkcs8(
                cert.cert.pem().as_bytes(),
                cert.key_pair.serialize_pem().as_bytes(),
            )
                .unwrap(),
        )
            .unwrap(),
    );

    let (tcp, _) = listener.accept().await.unwrap();
    let mut tls = acceptor.accept(tcp).await.unwrap();
    let mut buf = String::new();
    tls.read_to_string(&mut buf).await.unwrap();
    println!("read: {buf}");
}

The certificate you created is not valid for any domain name as you passed an empty list of domain names to rcgen::generate_simple_self_signed(). At the same time on the client side you are filling in a domain name N/A. N/A is not a valid domain name for the certificate and thus the client returns an error. You will have to add a domain name to the certificate and pass this domain name to connector.connect().

By the way connecting to 0.0.0.0 is not portable. Listening 0.0.0.0 is defined as listening on all ip addresses the system has, but connecting to 0.0.0.0 may connect to localhost or it may just plain error.

3 Likes

Thank you