Skip to content
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

add_root_certificate does not work when SSL_CERT_FILE env var is not set #175

Closed
davidMcneil opened this issue Jun 30, 2020 · 3 comments
Closed

Comments

@davidMcneil
Copy link

add_root_certificate does not seem to add a certificate when SSL_CERT_FILE is not set or points to an invalid path. Consider the example program below using reqwest.

[dependencies]
reqwest = { version = "*", features = ["blocking", "native-tls", "native-tls-vendored"] }
use reqwest::{blocking::ClientBuilder, Certificate};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cert = "/usr/lib/ssl/certs/ca-certificates.crt";
    let cert = std::fs::read(cert)?;
    let cert = Certificate::from_pem(&cert)?;
    let client = ClientBuilder::new().add_root_certificate(cert).build()?;

    println!("SSL_CERT_FILE {:?}", std::env::var("SSL_CERT_FILE"));
    println!("SSL_CERT_DIR {:?}", std::env::var("SSL_CERT_DIR"));

    let url = "https://www.rust-lang.org/";
    let response = client.get(url).send()?;
    println!("Status {}", response.status());
    Ok(())
}

This works fine when running cargo run. However, running env SSL_CERT_FILE=/a/bad/path cargo run produces the error unable to get local issuer certificate. Switching to use rustls instead of the native-tls backend works.

[dependencies]
reqwest = { version = "*", default-features = false, features = ["blocking", "rustls-tls"] }

This is obviously a very contrived example, but this situation does arise when vendoring openssl with the vendored feature and running on a system without openssl installed. In this case, openssl-probe is unable to set the SSL_CERT_FILE env var leading to the same behavior as when it is set to an invalid path.

@sfackler
Copy link
Owner

That code is only parsing the first certificate out of the ca-certificates.crt file. Is www.rust-lang.org's root the first entry in that file?

@davidMcneil
Copy link
Author

davidMcneil commented Jun 30, 2020

Aha! That explains it. Thank you! ... For those interested the working code that uses the pem crate can be found below. Would you be interested in a PR that adds the ability to make a Vec of Certificates from a buffer? I would essentially copy the functionality from rustls here.

Thanks again! I really apreciate your time.

use reqwest::{blocking::ClientBuilder, Certificate};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = ClientBuilder::new();

    let certs = "/usr/lib/ssl/certs/ca-certificates.crt";
    let certs = std::fs::read(certs)?;
    let certs = pem::parse_many(certs);
    for cert in certs.iter() {
        let cert = Certificate::from_der(&cert.contents)?;
        client = client.add_root_certificate(cert);
    }

    let client = client.build()?;

    println!("SSL_CERT_FILE {:?}", std::env::var("SSL_CERT_FILE"));
    println!("SSL_CERT_DIR {:?}", std::env::var("SSL_CERT_DIR"));

    let url = "https://www.rust-lang.org/";
    let response = client.get(url).send()?;
    println!("Status {}", response.status());
    Ok(())
}

@davidMcneil
Copy link
Author

Looks like someone beat me to it in #168.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants