try_init_openssl_env_vars() breaks certificate validation (on FreeBSD)

Open
#37 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

  • #39 by @michael-o — closed without merging
  • #43 by @michael-o — closed without merging

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
18/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
rust

Research direction

The bug sits in the candidate directory list and environment setup in src/lib.rs, where try_init_openssl_env_vars() calls probe() and then sets SSL_CERT_DIR and SSL_CERT_FILE. Start by reading that probe logic and reproduce the FreeBSD case by checking which candidate directories contain a certs subdirectory. Done means the variables are only set to paths OpenSSL can actually use, verified by the sample program succeeding.

Written by the indexing model from the issue text.

Description

try_init_openssl_env_vars() invokes probe() and then manipulates the process environment with SSL_CERT_DIR/SSL_CERT_FILE. This may happen on any system, but for me at least on FreeBSD, when the following condition is met:
https://github.com/alexcrichton/openssl-probe/blob/4221247cfad3e77b758bf9b6e4c3d91a557c429e/src/lib.rs#L31-L50
None of these directories contain a CAfile, but contain a dir CANDIDATE/certs which is not CApath. That path is being used to set SSL_CERT_DIR, OpenSSL picks up this empty directory and fails all validations.
Here on the example of FreeBSD:
For many years FreeBSD contains certctl(8) to manage the system truststore which is assembled from various sources into a CApath in /etc/ssl/certs. If one relies on OpenSSL's SSL_CTX_set_default_verify_paths() all is good.
certctl(8) includes by default these two paths with CA certificates:

  • /usr/share/certs/trusted: comes with the base system and contains all NSS CA certificate from Mozilla
  • /usr/local/share/certs: is initially empty and allows an admin to drop off custom/enterprise CAs (which a do at work).

certcrtl rehash scans all of them and puts symlinks into /etc/ssl/certs, but since candidate_cert_dirs[] has ""/usr/local/share" before "/etc/ssl" an invalid value is set and all fails.

A sample main which fails:

use curl::easy::Easy;

fn main() {
 openssl_probe::init_ssl_cert_env_vars();
 let mut data = Vec::new();
 let mut handle = Easy::new();
 handle.url("https://www.rust-lang.org/").unwrap();
 {
     let mut transfer = handle.transfer();
     transfer.write_function(|new_data| {
         data.extend_from_slice(new_data);
         Ok(new_data.len())
     }).unwrap();
     transfer.perform().unwrap();
 }
 }

Remove the first line in the main and you are good to go.

This causes problems with downstream consumers like git2-rs and then cargo. I will report the issue also downstream.

Dominant language
Rust
Stars
61
Forks
23
Avg merge
43m
Merged PRs (30d)
2

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from rustls/openssl-probe

All issues in rustls/openssl-probe

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.