0

I have a web server built using hyper and tokio-rustls. When using the self-signed certificate, I have confirmed that the https request is successfully processed by a web browser such as Chrome.

However, when I try to make a hyper client for the test and try to make a request, the following error is output.

hyper::Error(Connect, Custom { kind: Other, error: Custom { kind: InvalidData, error: InvalidCertificateData("invalid peer certificate: UnknownIssuer") } })', tests/server.rs:80:42

Even when I check with curl request for self signed certificate, I am getting 200 response. Don't clients using hyper-rustls accept self-signed certificates? Or is there a reason the browser and test client show different results?

Is there a separate option not to check the server's certificate on the client (insecure)?

I used hyper_rustls to make https requests.

let url = ("https://localhost:5582").parse().unwrap();
let https = hyper_rustls::HttpsConnectorBuilder::new()
    .with_native_roots()
    .https_only()
    .enable_http1()
    .build();

let client: Client<_, hyper::Body> = Client::builder().build(https);

let response = client.get(url).await.unwrap();
yjlee
  • 363
  • 1
  • 14

2 Answers2

1

All environments should reject the self-signed certificate until explicitly instructed to accept it. For example, with curl you can use -k or --insecure to tell curl not to validate the certificate. Likewise, your browser displayed a scary "certificate error" page that you bypassed, instructing the browser to accept the certificate.

If an environment doesn't reject such certificates by default, it is susceptible to man-in-the-middle attacks, which would be a security vulnerability.

You can disable certificate verification by adding an invocation of .with_tls_config() when building your hyper_rustls connector. You need to access the dangerous part of the ClientConfig and set the certificate verifier to a one that performs no checks at all.

Alternatively, you can install the certificate as a trusted host certificate in your system's certificate store, which is probably both simpler and safer.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
1

To build on the answer by cdhowie, here is a more complete example:

use std::{sync::Arc, fs::File, io::Read};

use anyhow::Error;
use hyper::client::HttpConnector;
use hyper_rustls::HttpsConnector;
use rustls::ClientConfig;

// customization for "reqwest" requests
pub fn get_reqwest_client_with_k8s_certs() -> Result<reqwest::Client, Error> {
    // if you just want to add custom certificates, use this
    /*let mut buf = Vec::new();
    File::open("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")?
        .read_to_end(&mut buf)?;
    let cert = reqwest::Certificate::from_pem(&buf)?;
    Ok(reqwest::ClientBuilder::new()
        .add_root_certificate(cert).build()?)*/

    Ok(reqwest::ClientBuilder::new()

        // if you want to completely disable cert-verification, use this
        .danger_accept_invalid_certs(true)

        .build()?)
}

// customization for "hyper" requests
pub fn get_hyper_client_with_k8s_certs() -> Result<hyper::Client<HttpsConnector<HttpConnector>>, Error> {
    let https = hyper_rustls::HttpsConnectorBuilder::new()
        .with_tls_config(get_rustls_config_dangerous()?)
        .https_only()
        .enable_http1()
        .build();

    let client: hyper::Client<_, hyper::Body> = hyper::Client::builder().build(https);
    Ok(client)
}

pub fn get_rustls_config_dangerous() -> Result<ClientConfig, Error> {
    let mut store = rustls::RootCertStore::empty();

    // if you just want to add custom certificates, use this
    /*let mut buf = Vec::new();
    File::open("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")?
        .read_to_end(&mut buf)?;
    //let cert = reqwest::Certificate::from_pem(&buf)?;
    store.add_parsable_certificates(&[buf]);*/
    
    let mut config = ClientConfig::builder()
        .with_safe_defaults()
        .with_root_certificates(store)
        .with_no_client_auth();

    // if you want to completely disable cert-verification, use this
    let mut dangerous_config = ClientConfig::dangerous(&mut config);
    dangerous_config.set_certificate_verifier(Arc::new(NoCertificateVerification {}));

    Ok(config)
}
pub struct NoCertificateVerification {}
impl rustls::client::ServerCertVerifier for NoCertificateVerification {
    fn verify_server_cert(
        &self,
        _end_entity: &rustls::Certificate,
        _intermediates: &[rustls::Certificate],
        _server_name: &rustls::ServerName,
        _scts: &mut dyn Iterator<Item = &[u8]>,
        _ocsp: &[u8],
        _now: std::time::SystemTime,
    ) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
        Ok(rustls::client::ServerCertVerified::assertion())
    }
}
Venryx
  • 15,624
  • 10
  • 70
  • 96