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

FreeBSD certs not found #28

Open
LukeMauldin opened this issue Sep 14, 2021 · 14 comments · May be fixed by #109
Open

FreeBSD certs not found #28

LukeMauldin opened this issue Sep 14, 2021 · 14 comments · May be fixed by #109

Comments

@LukeMauldin
Copy link

I have a FreeBSD 13 system and I have uploaded my custom certs into /usr/local/share/certs/ca-root-nss.crt which allows OOTB curl to work. However, Rust programs (ex: rustup-init) built using rustls-native-certs do not check that location. I can work around the issue by setting the env variable SSL_CERT_FILE=/usr/local/share/certs/ca-root-nss.crt but I would like for that location to be searched by this crate.

@LukeMauldin
Copy link
Author

As an update to this issue, it looks like the file /usr/local/share/certs/ca-root-nss.crt isn't searched because /usr/local/openssl/cert.pem also exists and is higher in the priority search order.

@Ralith
Copy link

Ralith commented Sep 14, 2021

Should all possible locations be searched and aggregated?

@LukeMauldin
Copy link
Author

LukeMauldin commented Sep 15, 2021 via email

@djc
Copy link
Member

djc commented Oct 11, 2021

Would you mind submitting a PR for aggregating? It seems reasonable to me.

@charlespierce
Copy link

I'm interested in this (as I believe it's ultimately something that is affecting one of the users of my project), and willing to submit a PR, however it looks like the precedence searching is actually internal to openssl-probe and they don't currently expose an API of the files that are searched—They provide an API for the directories, but not the files within those directories that are searched as part of probe.

I'm a bit out of my depth with the internals here, but it looks like openssl-probe is intentionally only providing a single file and single directory as the results of probe—Does anyone know if it even makes sense to search all of the possible locations? Or would that be behavior that is wildly different from what OpenSSL actually does to detect certificates?

@pgerber
Copy link

pgerber commented May 8, 2024

I just ran into the same simalar issue on FreeBSD 14. Looking at openssl-probe, I believe the /etc/ssh/certs/ is what openssl-probe is supposed to find. Openssl-probe can return a file and a directory:

pub struct ProbeResult {
    pub cert_file: [Option](https://doc.rust-lang.org/nightly/core/option/enum.Option.html)<[PathBuf](https://doc.rust-lang.org/nightly/std/path/struct.PathBuf.html)>,
    pub cert_dir: [Option](https://doc.rust-lang.org/nightly/core/option/enum.Option.html)<[PathBuf](https://doc.rust-lang.org/nightly/std/path/struct.PathBuf.html)>,
}

But this crate only checks for ProbeResult::cert_file:

pub fn load_native_certs() -> Result<Vec<CertificateDer<'static>>, Error> {
    let likely_locations = openssl_probe::probe();

    match likely_locations.cert_file {
        Some(cert_file) => load_pem_certs(&cert_file),
        None => Ok(Vec::new()),
    }
}

I suspect other tools that use probe() use both and that's why this works elsewhere. Still it seems odd to stop on the first file and directory.

pgerber added a commit to pgerber/rustls-native-certs that referenced this issue May 9, 2024
pgerber added a commit to pgerber/rustls-native-certs that referenced this issue May 9, 2024
pgerber added a commit to pgerber/rustls-native-certs that referenced this issue May 9, 2024
pgerber added a commit to pgerber/rustls-native-certs that referenced this issue May 9, 2024
@pgerber
Copy link

pgerber commented May 9, 2024

Okay, reading certs from ProbeResult::cert_dir seems indeed to fix the issue on FreeBSD 14. See my draft commit. Tests now pass on FreeBSD 14.

I'm not sure this solves the issue originally described here but it appears fix the issue I had where no cert would be found at all on the system because there is only a /etc/ssl/certs/ here.

@djc
Copy link
Member

djc commented May 9, 2024

In rustup, this seemed to get fixed by running pkg install -y ca_root_nss. How does that interact with this?

It generally seems sensible to me to work through both cert_file and cert_dir. @ctz any thoughts?

@ctz
Copy link
Member

ctz commented May 9, 2024

Yeah we probably should. That would involve reading in files named in the openssl rehash or certctl rehash style (hopefully the same -- needs a little research).

Working through both cert_file and cert_dir is likely to end up with every root twice. We could look at cert_dir only if cert_file does not exist, or perhaps deduplicate as we go?

@djc
Copy link
Member

djc commented May 12, 2024

@pgerber want to submit a PR for this?

@pgerber
Copy link

pgerber commented May 12, 2024

Can I assume the goal here is that rustls-native-certs is designed to be a OpenSSL drop-in replacement? In that case, we should probably try to be closer to what OpenSSL does, or at least what the openssl Crate does.

Reading through (SSL_CTX_load_verify_locations), there is some differences:

(Env. vars. are documented in openssl-env.)

Certs are looked up based on hash and only when needed:

If CApath is not NULL, it points to a directory containing CA certificates in PEM format. The files each contain one CA certificate. The files are looked up by the CA subject name hash value, which must hence be available. If more than one CA certificate with the same name hash value exist, the extension must be different (e.g. 9d66eef0.0, 9d66eef0.1 etc). The search is performed in the ordering of the extension number, regardless of other properties of the certificates. Use the c_rehash utility to create the necessary links.

The certificates in CApath are only looked up when required, e.g. when building the certificate chain or when actually performing the verification of a peer certificate.

See also See also c_rehash.

CAfile is searched first:

When looking up CA certificates, the OpenSSL library will first search the certificates in CAfile, then those in CApath.

I also looked at openssl-probe a bit closer:

SSL_CERT_FILE/SSL_CERT_DIR are already consulted when calling probe():

fn probe_from_env() -> ProbeResult {
    let var = |name| {
        env::var_os(name)
            .map(PathBuf::from)
            .filter(|p| p.exists())
    };
    ProbeResult {
        cert_file: var(ENV_CERT_FILE),
        cert_dir: var(ENV_CERT_DIR),
    }
}

pub fn probe() -> ProbeResult {
    let mut result = probe_from_env();
    for certs_dir in cert_dirs_iter() {
    …
}

This implementation differs from the implementation (in my draft) in two ways:
a) SSL_CERT_FILE/SSL_CERT_DIR is ignored if the target doesn't exist.
b) If only one of SSL_CERT_FILE and SSL_CERT_DIR is set and the path exists, the other one is still looked up at the default location.

If we want to be compatible with OpenSSL, we should probably use this implementation.

According Compilation and Installation:

One is supposed to select default directory / file at build time:

OpenSSL 1.1.0 and above

OpenSSL 1.1.0 changed the behavior of install rules. You should specify both --prefix and --openssldir to ensure make install works as expected.

The takeaway is /usr/local/ssl is used by default, and it can be overridden with both --prefix and --openssldir. The rule of thumb applies for path overrides: specify both --prefix and --openssldir. So, it would appear that there is usually no more than one file and one directory. So, this would match openssl-probe.

So there is but one directory and one file searched and their paths are platform/OS/distribution-dependent. So, probe() only returning one location for the file and one for the directory appears to match the behavior of OpenSSL.

@ctz
Copy link
Member

ctz commented May 13, 2024

Can I assume the goal here is that rustls-native-certs is designed to be a OpenSSL drop-in replacement?

No, merely enough to obtain certificates for a variety of operating systems. That is why the current implementation is good enough for linux (because update-ca-certificates is pretty ubiquitous, and maintains a the single-file version, albeit nobody can agree where a file lives).

Your attached commit looks like an excellent start to me.

@pgerber
Copy link

pgerber commented May 13, 2024

Okay, having given this some though, I'll open a pull request with the following changes (as compared to my draft commit):

  • Remove parsing for SSL_CERT_FILE and have openssl_probe::probe() handling SSL_CERT_FILE and SSL_CERT_DIR. This way, openssl and rustls have better compatibility. (Main difference is that openssl-probe does not err if the file doesn't exist.)
  • Parse files that have a file name which appears to be a valid hash in CAdir.
  • Deduplicate certificates.

For the openssl-probe Crate:

  • Create a pull request documenting probe(), particularly, document how it handles SSL_CERT_FILE/SSL_CERT_DIR.
  • Create a pull request to handle an empty SSL_CERT_FILE/SSL_CERT_DIR differently. Currently, this is interpreted as path "." but OpenSSL itself uses it to disable the CAfile/CAdir. That way, SSL_CERT_FILE=/a/path/to/a/cert SSL_CERT_DIR= command can be used to ignore the native trust store. (This is how the openssl command appears to handle the env. vars.)

Let me know if you disagree with this plan.

pgerber added a commit to pgerber/rustls-native-certs that referenced this issue Jun 3, 2024
pgerber added a commit to pgerber/rustls-native-certs that referenced this issue Jun 7, 2024
@pgerber pgerber linked a pull request Jun 7, 2024 that will close this issue
pgerber added a commit to pgerber/rustls-native-certs that referenced this issue Jun 7, 2024
@pgerber
Copy link

pgerber commented Jun 7, 2024

I'm afraid it took me a bit longer than hoped but I just opened a pull request. I kind of gave up on trying to stick as close to OpenSSL as possible. OpenSSL, Curl, OpenSSL-rust, etc. all do things a bit different. I tried to add documentation/comments/tests to indicate behavior which some may feel is unexpected.

pgerber added a commit to pgerber/rustls-native-certs that referenced this issue Jun 7, 2024
pgerber added a commit to pgerber/rustls-native-certs that referenced this issue Jun 7, 2024
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

Successfully merging a pull request may close this issue.

6 participants