chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1 @@
{"files":{".cargo_vcs_info.json":"69ea0a52e742c0ed241be95a7b82f7fb095359f07f19f70208900a401872d7e9",".github/dependabot.yml":"5fd25138a412fc3baccb14afd8ceb4b85e9293c758415065d8dd573a8c20e98b",".github/workflows/rust.yml":"467b941d8067301dd16ee94e37f02c3dbee80847d227e31b8c839be325849de3",".github/workflows/smoke-tests.yaml":"a6a2ae251ed6044482fb10a21cceb7a95b2cbe76c2613c77e7d26eff1ad783fb","CONTRIBUTING.md":"fa2b78fb5291cf522ef3b749c7cb662b6e6c101445dc1ea92155876589bc65e0","Cargo.lock":"14429684bfd32d74c53a319493c99e3d62a2efe141491b78162b6b98ca8851aa","Cargo.toml":"e8796c4912a8e9eebb3810a05e31be3debc3d309fe0a227594bbc35f851a7fd0","Cargo.toml.orig":"48316e02a970ccf9646184bca1ce262a47e35ea6d18c5d86820da9f5dd7d94de","LICENSE":"d75967ce788187f83c3bd3328210974acfc443d4dc44909f1d7e34f21623a0c6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-ISC":"7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4","LICENSE-MIT":"709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c","README.md":"afe8eecb0d329891e3d2004ba12839d9eb295a031ca9c2050b5322ea39a4fab6","RELEASING.md":"736984cde0639c5e5f96ad10fd5c419b1147e76e499bade5007a4b2d856964e1","examples/google.rs":"d56785b4a8499a653a6e02b857e58fdd4d6f27fd24406595d412bf3ea04d193b","examples/print-trust-anchors.rs":"527ec56bc114a10e26d0316f10453ec28a62a9f2a8981ec3f6cae83b250058a0","integration-tests/macos.sh":"300c40d501dd40c5b134d0f420ba3e32755eae4ee1105695012ad1ca413f8a99","integration-tests/one-existing-ca.pem":"6bdc59f897631af7811e3201cbc58e5999de2600ae8667454a34514eecfd8381","rustfmt.toml":"079483fb72cf5e4d45fcf021e6fdab3c30a88b941b139f7df3a552f84e5e0455","src/lib.rs":"e96b60d226d77599e68fdbb180335866d1f2a99301cfdfb12ed3f6e207a46af0","src/macos.rs":"9d54600f7dc289dda4ae233d5af8da3fbf79d64cd516c14d2aa4e722b00c9f26","src/unix.rs":"81249d335b14e6fdff360146627a9c5d37635e738492e004a967df12df5d5163","src/windows.rs":"ed6eae47fb2f8d4a81bdb68885dca220d0a682f9dbd5c4ad5205231d4af19b37","tests/badssl-com-chain.pem":"a3f77e30bf85cb3a6589c48a4d62da843655b1b82658677ccf6a339698040528","tests/common/mod.rs":"37b794dea004c54f0aa83e165261e877b1829439645c92a8cdc8907e1b1f3140","tests/compare_mozilla.rs":"17b18351b92c7e8af85cf592dee39b939065f9f325b3a29fd1d54e105909eff8","tests/smoketests.rs":"f787fb7db93e1ba07299558cf28e87da67608e83775e878b7c16a23605966631"},"package":"612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"}

View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "71e4dd82ad584ac93c41a5ec694f255530da97d3"
},
"path_in_vcs": ""
}

View File

@@ -0,0 +1,15 @@
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
groups:
crates-io:
patterns:
- "*"
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly

View File

@@ -0,0 +1,188 @@
name: rustls
permissions:
contents: read
on:
push:
branches: ['main', 'ci/*']
pull_request:
merge_group:
schedule:
- cron: '0 18 * * *'
workflow_dispatch:
jobs:
build:
name: Build+test
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
# test a bunch of toolchains on ubuntu
rust:
- stable
- beta
- nightly
os: [ubuntu-latest]
# but only stable on macos/windows (slower platforms)
include:
- os: macos-latest
rust: stable
- os: windows-latest
rust: stable
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install ${{ matrix.rust }} toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- name: Install NASM for aws-lc-rs on Windows
if: runner.os == 'Windows'
uses: ilammy/setup-nasm@v1
- name: cargo build (debug; default features)
run: cargo build --locked
- name: cargo test (debug; default features)
run: cargo test --locked
env:
RUST_BACKTRACE: 1
- name: cargo test (debug; all features)
run: cargo test --locked --all-features
env:
RUST_BACKTRACE: 1
- name: cargo build (debug; no default features)
run: cargo build --locked --no-default-features
- name: cargo test (debug; no default features; no run)
run: cargo test --locked --no-default-features --no-run
- name: cargo test (release; no run)
run: cargo test --locked --release --no-run
# https://github.com/rustls/rustls-native-certs/issues/179
# - name: run macOS integration test
# if: matrix.os == 'macos-latest'
# run: sudo bash integration-tests/macos.sh
msrv:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install MSRV toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: "1.71"
- run: cargo check --locked --lib --all-features
minimal-versions:
name: Check minimum versions of direct dependencies
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install rust toolchain
uses: dtolnay/rust-toolchain@nightly
- name: Install cargo-minimal-versions
uses: taiki-e/install-action@cargo-minimal-versions
# cargo-minimal-versions requires cargo-hack
- name: Install cargo-hack
uses: taiki-e/install-action@cargo-hack
- name: Check direct-minimal-versions
run: cargo minimal-versions --direct --ignore-private check
semver:
name: Check semver compatibility
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Check semver
uses: obi1kenobi/cargo-semver-checks-action@v2
docs:
name: Check for documentation errors
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install rust toolchain
uses: dtolnay/rust-toolchain@nightly
- name: cargo doc (rustls; all features)
run: cargo doc --locked --all-features --no-deps --document-private-items
env:
RUSTDOCFLAGS: -Dwarnings
format:
name: Format
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- run: cargo clippy --locked --all-features --all-targets -- --deny warnings
clippy-nightly:
name: Clippy (Nightly)
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install rust toolchain
uses: dtolnay/rust-toolchain@nightly
with:
components: clippy
- run: cargo clippy --locked --all-features --all-targets -- --deny warnings

View File

@@ -0,0 +1,53 @@
name: smoke-tests
permissions:
contents: read
on:
workflow_dispatch:
schedule:
# We run these tests on a daily basis (at a time slightly offset from the
# top of the hour), because they rely on external 3rd party services that
# can be flaky.
- cron: '15 18 * * *'
jobs:
smoke-tests:
name: Smoke Tests
runs-on: ${{ matrix.os }}
strategy:
matrix:
# test a bunch of toolchains on ubuntu
rust:
- stable
- beta
- nightly
os: [ ubuntu-latest ]
# but only stable on macos/windows (slower platforms)
include:
- os: macos-latest
rust: stable
- os: windows-latest
rust: stable
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install ${{ matrix.rust }} toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- name: Install NASM for aws-lc-rs on Windows
if: runner.os == 'Windows'
uses: ilammy/setup-nasm@v1
- name: Build main crate
run: cargo build --locked
- name: Run smoke tests
run: cargo test --locked -- --ignored
env:
RUST_BACKTRACE: 1

View File

@@ -0,0 +1,51 @@
# Contributing
Thanks for considering helping this project. There are many
ways you can help: using the library and reporting bugs,
reporting usability issues, making additions and improvements
to the library, documentation and finding security bugs.
## Reporting bugs
Please file a github issue. Include as much information as
possible. Suspected protocol bugs are easier debugged with
a pcap or reproduction steps.
Feel free to file github issues to get help, or ask a question.
## Code changes
Some ideas and guidelines for contributions:
- For large features, file an issue prior to starting work.
This means everyone can see what is in progress prior to a PR.
- Feel free to submit a PR even if the work is not totally finished,
for feedback or to hand-over.
- Prefer not to reference github issue or PR numbers in commits.
- Try to keep code formatting commits separate from functional commits.
- I run `cargo outdated` prior to major releases; but PRs to update specific
dependencies are welcome.
## Security bugs
Please report security bugs by filing a github issue, or by
email to jbp@jbp.io if you want to disclose privately. I'll then:
- Prepare a fix and regression tests.
- Backport the fix and make a patch release for most recent release.
- Submit an advisory to [rustsec/advisory-db](https://github.com/RustSec/advisory-db).
- Refer to the advisory on the main README.md and release notes.
## Testing
- Features involving additions to the public API should have (at least)
API-level tests (see [`tests/api.rs`](tests/api.rs)).
- Protocol additions should have some coverage -- consider enabling
corresponding tests in the bogo suite, or writing some adhoc tests.
PRs which cause test failures or a significant coverage decrease
are unlikely to be accepted.
## Licensing
Contributions are made under [rustls-native-certs's licenses](LICENSE).

953
vendor/rustls-native-certs/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,953 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "asn1-rs"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60"
dependencies = [
"asn1-rs-derive",
"asn1-rs-impl",
"displaydoc",
"nom",
"num-traits",
"rusticata-macros",
"thiserror",
"time",
]
[[package]]
name = "asn1-rs-derive"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "asn1-rs-impl"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "aws-lc-rs"
version = "1.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288"
dependencies = [
"aws-lc-sys",
"zeroize",
]
[[package]]
name = "aws-lc-sys"
version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1"
dependencies = [
"cc",
"cmake",
"dunce",
"fs_extra",
]
[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "cc"
version = "1.2.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
dependencies = [
"find-msvc-tools",
"jobserver",
"libc",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cmake"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
dependencies = [
"cc",
]
[[package]]
name = "core-foundation"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "data-encoding"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
[[package]]
name = "der-parser"
version = "10.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6"
dependencies = [
"asn1-rs",
"displaydoc",
"nom",
"num-bigint",
"num-traits",
"rusticata-macros",
]
[[package]]
name = "deranged"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
dependencies = [
"powerfmt",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "dunce"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "find-msvc-tools"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
[[package]]
name = "fs_extra"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-sink"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "futures-task"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "getrandom"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "getrandom"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasip2",
]
[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "jobserver"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [
"getrandom 0.3.4",
"libc",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "oid-registry"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7"
dependencies = [
"asn1-rs",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "openssl-probe"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391"
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "proc-macro2"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "ring"
version = "0.17.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
dependencies = [
"cc",
"cfg-if",
"getrandom 0.2.16",
"libc",
"untrusted",
"windows-sys 0.52.0",
]
[[package]]
name = "rusticata-macros"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
dependencies = [
"nom",
]
[[package]]
name = "rustix"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.61.2",
]
[[package]]
name = "rustls"
version = "0.23.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
dependencies = [
"aws-lc-rs",
"log",
"once_cell",
"rustls-pki-types",
"rustls-webpki",
"subtle",
"zeroize",
]
[[package]]
name = "rustls-native-certs"
version = "0.8.3"
dependencies = [
"openssl-probe",
"ring",
"rustls",
"rustls-pki-types",
"rustls-webpki",
"schannel",
"security-framework",
"serial_test",
"tempfile",
"untrusted",
"webpki-roots",
"x509-parser",
]
[[package]]
name = "rustls-pki-types"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
dependencies = [
"zeroize",
]
[[package]]
name = "rustls-webpki"
version = "0.103.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
dependencies = [
"aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
]
[[package]]
name = "scc"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc"
dependencies = [
"sdd",
]
[[package]]
name = "schannel"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sdd"
version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca"
[[package]]
name = "security-framework"
version = "3.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serial_test"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9"
dependencies = [
"futures",
"log",
"once_cell",
"parking_lot",
"scc",
"serial_test_derive",
]
[[package]]
name = "serial_test_derive"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "slab"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tempfile"
version = "3.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
dependencies = [
"fastrand",
"getrandom 0.3.4",
"once_cell",
"rustix",
"windows-sys 0.61.2",
]
[[package]]
name = "thiserror"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
[[package]]
name = "time-macros"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasip2"
version = "1.0.1+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
dependencies = [
"wit-bindgen",
]
[[package]]
name = "webpki-roots"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "wit-bindgen"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
[[package]]
name = "x509-parser"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3e137310115a65136898d2079f003ce33331a6c4b0d51f1531d1be082b6425"
dependencies = [
"asn1-rs",
"data-encoding",
"der-parser",
"lazy_static",
"nom",
"oid-registry",
"rusticata-macros",
"thiserror",
"time",
]
[[package]]
name = "zeroize"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"

89
vendor/rustls-native-certs/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,89 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.71"
name = "rustls-native-certs"
version = "0.8.3"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "rustls-native-certs allows rustls to use the platform native certificate store"
homepage = "https://github.com/rustls/rustls-native-certs"
readme = "README.md"
categories = [
"network-programming",
"cryptography",
]
license = "Apache-2.0 OR ISC OR MIT"
repository = "https://github.com/rustls/rustls-native-certs"
[lib]
name = "rustls_native_certs"
path = "src/lib.rs"
[[example]]
name = "google"
path = "examples/google.rs"
[[example]]
name = "print-trust-anchors"
path = "examples/print-trust-anchors.rs"
[[test]]
name = "compare_mozilla"
path = "tests/compare_mozilla.rs"
[[test]]
name = "smoketests"
path = "tests/smoketests.rs"
[dependencies.pki-types]
version = "1.10"
features = ["std"]
package = "rustls-pki-types"
[dev-dependencies.ring]
version = "0.17"
[dev-dependencies.rustls]
version = "0.23"
[dev-dependencies.rustls-webpki]
version = "0.103"
[dev-dependencies.serial_test]
version = "3"
[dev-dependencies.tempfile]
version = "3.5"
[dev-dependencies.untrusted]
version = "0.9"
[dev-dependencies.webpki-roots]
version = "1"
[dev-dependencies.x509-parser]
version = "0.18"
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies.openssl-probe]
version = "0.2"
[target.'cfg(target_os = "macos")'.dependencies.security-framework]
version = "3"
[target."cfg(windows)".dependencies.schannel]
version = "0.1"

10
vendor/rustls-native-certs/LICENSE vendored Normal file
View File

@@ -0,0 +1,10 @@
Rustls is distributed under the following three licenses:
- Apache License version 2.0.
- MIT license.
- ISC license.
These are included as LICENSE-APACHE, LICENSE-MIT and LICENSE-ISC
respectively. You may use this software under the terms of any
of these licenses, at your option.

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

15
vendor/rustls-native-certs/LICENSE-ISC vendored Normal file
View File

@@ -0,0 +1,15 @@
ISC License (ISC)
Copyright (c) 2016, Joseph Birr-Pixton <jpixton@gmail.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

25
vendor/rustls-native-certs/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,25 @@
Copyright (c) 2016 Joseph Birr-Pixton <jpixton@gmail.com>
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

72
vendor/rustls-native-certs/README.md vendored Normal file
View File

@@ -0,0 +1,72 @@
![Logo](https://raw.githubusercontent.com/rustls/rustls/main/admin/rustls-logo-web.png)
**rustls-native-certs** allows [rustls](https://github.com/rustls/rustls) to use the
platform's native certificate store when operating as a TLS client.
> [!IMPORTANT]
> Instead of this crate, we suggest using [rustls-platform-verifier](https://github.com/rustls/rustls-platform-verifier),
> which provides a more robust solution with a simpler API. This crate is still maintained,
> but mostly for use inside the platform verifier on platforms where no other
> solution is available. For more context, see
> [deployment considerations](https://github.com/rustls/rustls-platform-verifier?tab=readme-ov-file#deployment-considerations).
# Status
rustls-native-certs is mature and widely used.
If you'd like to help out, please see [CONTRIBUTING.md](CONTRIBUTING.md).
[![rustls](https://github.com/rustls/rustls-native-certs/actions/workflows/rust.yml/badge.svg)](https://github.com/rustls/rustls-native-certs/actions/workflows/rust.yml)
[![Documentation](https://docs.rs/rustls-native-certs/badge.svg)](https://docs.rs/rustls-native-certs)
Release notes can be found [on GitHub](https://github.com/rustls/rustls-native-certs/releases).
# API
This library exposes a single function with this signature:
```rust
pub fn load_native_certs() -> Result<Vec<pki_types::CertificateDer<'static>>, std::io::Error>
```
On success, this returns a `Vec<pki_types::CertificateDer<'static>>` loaded with a
snapshot of the root certificates found on this platform. This
function fails in a platform-specific way, expressed in a `std::io::Error`.
This function can be expensive: on some platforms it involves loading
and parsing a ~300KB disk file. It's therefore prudent to call
this sparingly.
# Platform support
This is supported on Windows, macOS and Linux:
- On all platforms, the `SSL_CERT_FILE` environment variable is checked first.
If that's set, certificates are loaded from the path specified by that variable,
or an error is returned if certificates cannot be loaded from the given path.
If it's not set, then the platform-specific certificate source is used.
- On Windows, certificates are loaded from the system certificate store.
The [`schannel`](https://github.com/steffengy/schannel-rs) crate is used to access
the Windows certificate store APIs.
- On macOS, certificates are loaded from the keychain.
The user, admin and system trust settings are merged together as documented
by Apple. The [`security-framework`](https://github.com/kornelski/rust-security-framework)
crate is used to access the keystore APIs.
- On Linux and other UNIX-like operating systems, the
[`openssl-probe`](https://github.com/alexcrichton/openssl-probe) crate is used to discover
the filename of the system CA bundle.
# Worked example
See [`examples/google.rs`](examples/google.rs).
# License
rustls-native-certs is distributed under the following three licenses:
- Apache License version 2.0.
- MIT license.
- ISC license.
These are included as LICENSE-APACHE, LICENSE-MIT and LICENSE-ISC
respectively. You may use this software under the terms of any
of these licenses, at your option.

26
vendor/rustls-native-certs/RELEASING.md vendored Normal file
View File

@@ -0,0 +1,26 @@
# Making a rustls-native-certs release
This is a checklist for steps to make before/after making a rustls release.
1. Attend to the README.md: this appears on crates.io for the release, and can't be edited after
the fact.
- Ensure the version has a good set of release notes. Move old release notes to OLDCHANGES.md
if this is getting excessively long.
- Write the version and date of the release.
2. Run `cargo update` followed by `cargo outdated`, to check if we have any
dependency updates which are not already automatically taken by their semver specs.
- If we do, take them if possible with separate commits (but there should've been
dependabot PRs submitted for these already.)
3. Now run `cargo test --all-features` to ensure our tests continue to pass with the
updated dependencies.
4. Update `Cargo.toml` to set the correct version.
5. Make a commit with the above changes, something like 'Prepare $VERSION'. This
should not contain functional changes: just versions numbers, and markdown changes.
6. Do a dry run: check `cargo publish --dry-run`
7. Push the above commit. Wait for CI to confirm it as green.
- Any red _should_ naturally block the release.
- If rustc nightly is broken, this _may_ be acceptable if the reason is understood
and does not point to a defect.
8. Tag the released version: `git tag -m '0.20.0' v/0.20.0`
9. Push the tag: `git push --tags`
10. Do the release: `cargo publish`.

View File

@@ -0,0 +1,43 @@
use std::io::{stdout, Read, Write};
use std::net::TcpStream;
use std::sync::Arc;
fn main() {
let mut roots = rustls::RootCertStore::empty();
for cert in rustls_native_certs::load_native_certs().expect("could not load platform certs") {
roots.add(cert).unwrap();
}
let config = rustls::ClientConfig::builder()
.with_root_certificates(roots)
.with_no_client_auth();
let mut conn =
rustls::ClientConnection::new(Arc::new(config), "google.com".try_into().unwrap()).unwrap();
let mut sock = TcpStream::connect("google.com:443").expect("cannot connect");
let mut tls = rustls::Stream::new(&mut conn, &mut sock);
tls.write_all(
concat!(
"GET / HTTP/1.1\r\n",
"Host: google.com\r\n",
"Connection: close\r\n",
"Accept-Encoding: identity\r\n",
"\r\n"
)
.as_bytes(),
)
.expect("write failed");
let ciphersuite = tls
.conn
.negotiated_cipher_suite()
.expect("tls handshake failed");
writeln!(
&mut std::io::stderr(),
"Current ciphersuite: {:?}",
ciphersuite.suite()
)
.unwrap();
let mut plaintext = Vec::new();
tls.read_to_end(&mut plaintext).unwrap();
stdout().write_all(&plaintext).unwrap();
}

View File

@@ -0,0 +1,14 @@
//! Print the Subject of all extracted trust anchors.
use std::error::Error;
use x509_parser::prelude::*;
fn main() -> Result<(), Box<dyn Error>> {
for cert in rustls_native_certs::load_native_certs().expect("could not load platform certs") {
match parse_x509_certificate(cert.as_ref()) {
Ok((_, cert)) => println!("{}", cert.tbs_certificate.subject),
Err(e) => eprintln!("error parsing certificate: {e}"),
};
}
Ok(())
}

View File

@@ -0,0 +1,41 @@
#!/bin/bash
set -ex
ANY_CA_PEM=integration-tests/one-existing-ca.pem
ANY_CA_SUBJECT="OU=GlobalSign Root CA - R3, O=GlobalSign, CN=GlobalSign"
reset() {
security remove-trusted-cert -d $ANY_CA_PEM || true
list | grep "$ANY_CA_SUBJECT"
}
list() {
cargo test util_list_certs -- --nocapture 2>/dev/null
}
assert_missing() {
set +e
list | grep "$1"
ret=$?
set -e
test $ret -eq 1
}
assert_exists() {
list | grep "$1" > /dev/null
}
test_distrust_existing_root() {
assert_exists "$ANY_CA_SUBJECT"
security add-trusted-cert -d -r deny $ANY_CA_PEM
assert_missing "$ANY_CA_SUBJECT"
reset
}
# https://developer.apple.com/forums/thread/671582?answerId=693632022#693632022
security authorizationdb write com.apple.trust-settings.admin allow
reset
test_distrust_existing_root
printf "\n*** All tests passed ***\n"

View File

@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
WD9f
-----END CERTIFICATE-----

View File

@@ -0,0 +1 @@
chain_width=40

515
vendor/rustls-native-certs/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,515 @@
//! rustls-native-certs allows rustls to use the platform's native certificate
//! store when operating as a TLS client.
//!
//! It provides a single function [`load_native_certs()`], which returns a
//! collection of certificates found by reading the platform-native
//! certificate store.
//!
//! If the SSL_CERT_FILE environment variable is set, certificates (in PEM
//! format) are read from that file instead.
//!
//! If you want to load these certificates into a `rustls::RootCertStore`,
//! you'll likely want to do something like this:
//!
//! ```no_run
//! let mut roots = rustls::RootCertStore::empty();
//! for cert in rustls_native_certs::load_native_certs().expect("could not load platform certs") {
//! roots.add(cert).unwrap();
//! }
//! ```
// Enable documentation for all features on docs.rs
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
use std::error::Error as StdError;
use std::path::{Path, PathBuf};
use std::{env, fmt, fs, io};
use pki_types::pem::{self, PemObject};
use pki_types::CertificateDer;
#[cfg(all(unix, not(target_os = "macos")))]
mod unix;
#[cfg(all(unix, not(target_os = "macos")))]
use unix as platform;
#[cfg(windows)]
mod windows;
#[cfg(windows)]
use windows as platform;
#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "macos")]
use macos as platform;
/// Load root certificates found in the platform's native certificate store.
///
/// ## Environment Variables
///
/// | Env. Var. | Description |
/// |---------------|---------------------------------------------------------------------------------------|
/// | SSL_CERT_FILE | File containing an arbitrary number of certificates in PEM format. |
/// | SSL_CERT_DIR | Colon separated list of directories containing certificate files. |
///
/// If **either** (or **both**) are set, certificates are only loaded from
/// the locations specified via environment variables and not the platform-
/// native certificate store.
///
/// ## Certificate Validity
///
/// All certificates are expected to be in PEM format. A file may contain
/// multiple certificates.
///
/// Example:
///
/// ```text
/// -----BEGIN CERTIFICATE-----
/// MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw
/// CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg
/// R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00
/// MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT
/// ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw
/// EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW
/// +1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9
/// ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
/// AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI
/// zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW
/// tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1
/// /q4AaOeMSQ+2b1tbFfLn
/// -----END CERTIFICATE-----
/// -----BEGIN CERTIFICATE-----
/// MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
/// MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
/// Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
/// A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
/// Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
/// ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
/// QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
/// ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
/// BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
/// YyRIHN8wfdVoOw==
/// -----END CERTIFICATE-----
///
/// ```
///
/// For reasons of compatibility, an attempt is made to skip invalid sections
/// of a certificate file but this means it's also possible for a malformed
/// certificate to be skipped.
///
/// If a certificate isn't loaded, and no error is reported, check if:
///
/// 1. the certificate is in PEM format (see example above)
/// 2. *BEGIN CERTIFICATE* line starts with exactly five hyphens (`'-'`)
/// 3. *END CERTIFICATE* line ends with exactly five hyphens (`'-'`)
/// 4. there is a line break after the certificate.
///
/// ## Errors
///
/// This function fails in a platform-specific way, expressed in a `std::io::Error`.
///
/// ## Caveats
///
/// This function can be expensive: on some platforms it involves loading
/// and parsing a ~300KB disk file. It's therefore prudent to call
/// this sparingly.
///
/// [c_rehash]: https://www.openssl.org/docs/manmaster/man1/c_rehash.html
pub fn load_native_certs() -> CertificateResult {
let paths = CertPaths::from_env();
match (&paths.dirs, &paths.file) {
(v, _) if !v.is_empty() => paths.load(),
(_, Some(_)) => paths.load(),
_ => platform::load_native_certs(),
}
}
/// Results from trying to load certificates from the platform's native store.
#[non_exhaustive]
#[derive(Debug, Default)]
pub struct CertificateResult {
/// Any certificates that were successfully loaded.
pub certs: Vec<CertificateDer<'static>>,
/// Any errors encountered while loading certificates.
pub errors: Vec<Error>,
}
impl CertificateResult {
/// Return the found certificates if no error occurred, otherwise panic.
#[track_caller]
pub fn expect(self, msg: &str) -> Vec<CertificateDer<'static>> {
match self.errors.is_empty() {
true => self.certs,
false => panic!("{msg}: {:?}", self.errors),
}
}
/// Return the found certificates if no error occurred, otherwise panic.
#[track_caller]
pub fn unwrap(self) -> Vec<CertificateDer<'static>> {
match self.errors.is_empty() {
true => self.certs,
false => panic!(
"errors occurred while loading certificates: {:?}",
self.errors
),
}
}
fn pem_error(&mut self, err: pem::Error, path: &Path) {
self.errors.push(Error {
context: "failed to read PEM from file",
kind: match err {
pem::Error::Io(err) => ErrorKind::Io {
inner: err,
path: path.to_owned(),
},
_ => ErrorKind::Pem(err),
},
});
}
fn io_error(&mut self, err: io::Error, path: &Path, context: &'static str) {
self.errors.push(Error {
context,
kind: ErrorKind::Io {
inner: err,
path: path.to_owned(),
},
});
}
#[cfg(any(windows, target_os = "macos"))]
fn os_error(&mut self, err: Box<dyn StdError + Send + Sync + 'static>, context: &'static str) {
self.errors.push(Error {
context,
kind: ErrorKind::Os(err),
});
}
}
/// Certificate paths from `SSL_CERT_FILE` and/or `SSL_CERT_DIR`.
struct CertPaths {
file: Option<PathBuf>,
dirs: Vec<PathBuf>,
}
impl CertPaths {
fn from_env() -> Self {
Self {
file: env::var_os(ENV_CERT_FILE).map(PathBuf::from),
// Read `SSL_CERT_DIR`, split it on the platform delimiter (`:` on Unix, `;` on Windows),
// and return the entries as `PathBuf`s.
//
// See <https://docs.openssl.org/3.5/man1/openssl-rehash/#options>
dirs: match env::var_os(ENV_CERT_DIR) {
Some(dirs) => env::split_paths(&dirs).collect(),
None => Vec::new(),
},
}
}
/// Load certificates from the paths.
///
/// See [`load_certs_from_paths()`].
fn load(&self) -> CertificateResult {
load_certs_from_paths_internal(self.file.as_deref(), &self.dirs)
}
}
/// Load certificates from the given paths.
///
/// If both are `None`, returns an empty [`CertificateResult`].
///
/// If `file` is `Some`, it is always used, so it must be a path to an existing,
/// accessible file from which certificates can be loaded successfully. While parsing,
/// the rustls-pki-types PEM parser will ignore parts of the file which are
/// not considered part of a certificate. Certificates which are not in the right
/// format (PEM) or are otherwise corrupted may get ignored silently.
///
/// If `dir` is defined, a directory must exist at this path, and all files
/// contained in it must be loaded successfully, subject to the rules outlined above for `file`.
/// The directory is not scanned recursively and may be empty.
pub fn load_certs_from_paths(file: Option<&Path>, dir: Option<&Path>) -> CertificateResult {
let dir = match dir {
Some(d) => vec![d],
None => Vec::new(),
};
load_certs_from_paths_internal(file, dir.as_ref())
}
fn load_certs_from_paths_internal(
file: Option<&Path>,
dir: &[impl AsRef<Path>],
) -> CertificateResult {
let mut out = CertificateResult::default();
if file.is_none() && dir.is_empty() {
return out;
}
if let Some(cert_file) = file {
load_pem_certs(cert_file, &mut out);
}
for cert_dir in dir.iter() {
load_pem_certs_from_dir(cert_dir.as_ref(), &mut out);
}
out.certs
.sort_unstable_by(|a, b| a.cmp(b));
out.certs.dedup();
out
}
/// Load certificate from certificate directory (what OpenSSL calls CAdir)
fn load_pem_certs_from_dir(dir: &Path, out: &mut CertificateResult) {
let dir_reader = match fs::read_dir(dir) {
Ok(reader) => reader,
Err(err) => {
out.io_error(err, dir, "opening directory");
return;
}
};
for entry in dir_reader {
let entry = match entry {
Ok(entry) => entry,
Err(err) => {
out.io_error(err, dir, "reading directory entries");
continue;
}
};
let path = entry.path();
// `openssl rehash` used to create this directory uses symlinks. So,
// make sure we resolve them.
let metadata = match fs::metadata(&path) {
Ok(metadata) => metadata,
Err(e) if e.kind() == io::ErrorKind::NotFound => {
// Dangling symlink
continue;
}
Err(e) => {
out.io_error(e, &path, "failed to open file");
continue;
}
};
if metadata.is_file() {
load_pem_certs(&path, out);
}
}
}
fn load_pem_certs(path: &Path, out: &mut CertificateResult) {
let iter = match CertificateDer::pem_file_iter(path) {
Ok(iter) => iter,
Err(err) => {
out.pem_error(err, path);
return;
}
};
for result in iter {
match result {
Ok(cert) => out.certs.push(cert),
Err(err) => out.pem_error(err, path),
}
}
}
#[derive(Debug)]
pub struct Error {
pub context: &'static str,
pub kind: ErrorKind,
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(match &self.kind {
ErrorKind::Io { inner, .. } => inner,
ErrorKind::Os(err) => &**err,
ErrorKind::Pem(err) => err,
})
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.context)?;
f.write_str(": ")?;
match &self.kind {
ErrorKind::Io { inner, path } => {
write!(f, "{inner} at '{}'", path.display())
}
ErrorKind::Os(err) => err.fmt(f),
ErrorKind::Pem(err) => err.fmt(f),
}
}
}
#[non_exhaustive]
#[derive(Debug)]
pub enum ErrorKind {
Io { inner: io::Error, path: PathBuf },
Os(Box<dyn StdError + Send + Sync + 'static>),
Pem(pem::Error),
}
const ENV_CERT_FILE: &str = "SSL_CERT_FILE";
const ENV_CERT_DIR: &str = "SSL_CERT_DIR";
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
#[cfg(unix)]
use std::fs::Permissions;
use std::io::Write;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
#[test]
fn deduplication() {
let temp_dir = tempfile::TempDir::new().unwrap();
let cert1 = include_str!("../tests/badssl-com-chain.pem");
let cert2 = include_str!("../integration-tests/one-existing-ca.pem");
let file_path = temp_dir
.path()
.join("ca-certificates.crt");
let dir_path = temp_dir.path().to_path_buf();
{
let mut file = File::create(&file_path).unwrap();
write!(file, "{}", &cert1).unwrap();
write!(file, "{}", &cert2).unwrap();
}
{
// Duplicate (already in `file_path`)
let mut file = File::create(dir_path.join("71f3bb26.0")).unwrap();
write!(file, "{}", &cert1).unwrap();
}
{
// Duplicate (already in `file_path`)
let mut file = File::create(dir_path.join("912e7cd5.0")).unwrap();
write!(file, "{}", &cert2).unwrap();
}
let result = CertPaths {
file: Some(file_path.clone()),
dirs: vec![],
}
.load();
assert_eq!(result.certs.len(), 2);
let result = CertPaths {
file: None,
dirs: vec![dir_path.clone()],
}
.load();
assert_eq!(result.certs.len(), 2);
let result = CertPaths {
file: Some(file_path),
dirs: vec![dir_path],
}
.load();
assert_eq!(result.certs.len(), 2);
}
#[test]
fn malformed_file_from_env() {
// Certificate parser tries to extract certs from file ignoring
// invalid sections.
let mut result = CertificateResult::default();
load_pem_certs(Path::new(file!()), &mut result);
assert_eq!(result.certs.len(), 0);
assert!(result.errors.is_empty());
}
#[test]
fn from_env_missing_file() {
let mut result = CertificateResult::default();
load_pem_certs(Path::new("no/such/file"), &mut result);
match &first_error(&result).kind {
ErrorKind::Io { inner, .. } => assert_eq!(inner.kind(), io::ErrorKind::NotFound),
_ => panic!("unexpected error {:?}", result.errors),
}
}
#[test]
fn from_env_missing_dir() {
let mut result = CertificateResult::default();
load_pem_certs_from_dir(Path::new("no/such/directory"), &mut result);
match &first_error(&result).kind {
ErrorKind::Io { inner, .. } => assert_eq!(inner.kind(), io::ErrorKind::NotFound),
_ => panic!("unexpected error {:?}", result.errors),
}
}
#[test]
#[cfg(unix)]
fn from_env_with_non_regular_and_empty_file() {
let mut result = CertificateResult::default();
load_pem_certs(Path::new("/dev/null"), &mut result);
assert_eq!(result.certs.len(), 0);
assert!(result.errors.is_empty());
}
#[test]
#[cfg(unix)]
fn from_env_bad_dir_perms() {
// Create a temp dir that we can't read from.
let temp_dir = tempfile::TempDir::new().unwrap();
fs::set_permissions(temp_dir.path(), Permissions::from_mode(0o000)).unwrap();
test_cert_paths_bad_perms(CertPaths {
file: None,
dirs: vec![temp_dir.path().into()],
})
}
#[test]
#[cfg(unix)]
fn from_env_bad_file_perms() {
// Create a tmp dir with a file inside that we can't read from.
let temp_dir = tempfile::TempDir::new().unwrap();
let file_path = temp_dir.path().join("unreadable.pem");
let cert_file = File::create(&file_path).unwrap();
cert_file
.set_permissions(Permissions::from_mode(0o000))
.unwrap();
test_cert_paths_bad_perms(CertPaths {
file: Some(file_path.clone()),
dirs: vec![],
});
}
#[cfg(unix)]
fn test_cert_paths_bad_perms(cert_paths: CertPaths) {
let result = cert_paths.load();
if let (None, true) = (cert_paths.file, cert_paths.dirs.is_empty()) {
panic!("only one of file or dir should be set");
};
let error = first_error(&result);
match &error.kind {
ErrorKind::Io { inner, .. } => {
assert_eq!(inner.kind(), io::ErrorKind::PermissionDenied);
inner
}
_ => panic!("unexpected error {:?}", result.errors),
};
}
fn first_error(result: &CertificateResult) -> &Error {
result.errors.first().unwrap()
}
}

72
vendor/rustls-native-certs/src/macos.rs vendored Normal file
View File

@@ -0,0 +1,72 @@
use std::collections::HashMap;
use pki_types::CertificateDer;
use security_framework::trust_settings::{Domain, TrustSettings, TrustSettingsForCertificate};
use super::CertificateResult;
pub fn load_native_certs() -> CertificateResult {
// The various domains are designed to interact like this:
//
// "Per-user Trust Settings override locally administered
// Trust Settings, which in turn override the System Trust
// Settings."
//
// So we collect the certificates in this order; as a map of
// their DER encoding to what we'll do with them. We don't
// overwrite existing elements, which means User settings
// trump Admin trump System, as desired.
let mut result = CertificateResult::default();
let mut all_certs = HashMap::new();
for domain in &[Domain::User, Domain::Admin, Domain::System] {
let ts = TrustSettings::new(*domain);
let iter = match ts.iter() {
Ok(iter) => iter,
Err(err) => {
result.os_error(
err.into(),
match domain {
Domain::User => "failed to load user trust settings",
Domain::Admin => "failed to load admin trust settings",
Domain::System => "failed to load system trust settings",
},
);
continue;
}
};
for cert in iter {
let der = cert.to_der();
// If there are no specific trust settings, the default
// is to trust the certificate as a root cert. Weird API but OK.
// The docs say:
//
// "Note that an empty Trust Settings array means 'always trust this cert,
// with a resulting kSecTrustSettingsResult of kSecTrustSettingsResultTrustRoot'."
let trusted = match ts.tls_trust_settings_for_certificate(&cert) {
Ok(trusted) => trusted.unwrap_or(TrustSettingsForCertificate::TrustRoot),
Err(err) => {
result.os_error(err.into(), "certificate not trusted");
continue;
}
};
all_certs.entry(der).or_insert(trusted);
}
}
// Now we have all the certificates and an idea of whether
// to use them.
for (der, trusted) in all_certs.drain() {
use TrustSettingsForCertificate::*;
if let TrustRoot | TrustAsRoot = trusted {
result
.certs
.push(CertificateDer::from(der));
}
}
result
}

10
vendor/rustls-native-certs/src/unix.rs vendored Normal file
View File

@@ -0,0 +1,10 @@
use crate::{CertPaths, CertificateResult};
pub fn load_native_certs() -> CertificateResult {
let likely_locations = openssl_probe::probe();
CertPaths {
file: likely_locations.cert_file,
dirs: likely_locations.cert_dir,
}
.load()
}

View File

@@ -0,0 +1,37 @@
use pki_types::CertificateDer;
use schannel::cert_context::ValidUses;
use schannel::cert_store::CertStore;
use super::CertificateResult;
pub fn load_native_certs() -> CertificateResult {
let mut result = CertificateResult::default();
let current_user_store = match CertStore::open_current_user("ROOT") {
Ok(store) => store,
Err(err) => {
result.os_error(err.into(), "failed to open current user certificate store");
return result;
}
};
for cert in current_user_store.certs() {
if usable_for_rustls(cert.valid_uses().unwrap()) && cert.is_time_valid().unwrap() {
result
.certs
.push(CertificateDer::from(cert.to_der().to_vec()));
}
}
result
}
fn usable_for_rustls(uses: ValidUses) -> bool {
match uses {
ValidUses::All => true,
ValidUses::Oids(strs) => strs
.iter()
.any(|x| x == PKIX_SERVER_AUTH),
}
}
static PKIX_SERVER_AUTH: &str = "1.3.6.1.5.5.7.3.1";

View File

@@ -0,0 +1 @@
{"name":"rustls-native-certs","vers":"0.8.3","deps":[{"name":"pki-types","req":"^1.10","features":["std"],"optional":false,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":"rustls-pki-types","public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"ring","req":"^0.17","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"rustls","req":"^0.23","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"rustls-webpki","req":"^0.103","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"serial_test","req":"^3","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"tempfile","req":"^3.5","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"untrusted","req":"^0.9","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"webpki-roots","req":"^1","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"x509-parser","req":"^0.18","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"openssl-probe","req":"^0.2","features":[],"optional":false,"default_features":true,"target":"cfg(all(unix, not(target_os = \"macos\")))","kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"security-framework","req":"^3","features":[],"optional":false,"default_features":true,"target":"cfg(target_os = \"macos\")","kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"schannel","req":"^0.1","features":[],"optional":false,"default_features":true,"target":"cfg(windows)","kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false}],"features":{},"features2":null,"cksum":"6b875ab0e15550c7ccd1269b7df350586eadcc8cfb008ddb1f0dc1fdfe22d896","yanked":null,"links":null,"rust_version":null,"v":2}

View File

@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDeTCCAmGgAwIBAgIJAMnA8BB8xT6wMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp
c2NvMQ8wDQYDVQQKDAZCYWRTU0wxFTATBgNVBAMMDCouYmFkc3NsLmNvbTAeFw0y
MTEwMTEyMDAzNTRaFw0yMzEwMTEyMDAzNTRaMGIxCzAJBgNVBAYTAlVTMRMwEQYD
VQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQK
DAZCYWRTU0wxFTATBgNVBAMMDCouYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAMIE7PiM7gTCs9hQ1XBYzJMY61yoaEmwIrX5lZ6xKyx2
PmzAS2BMTOqytMAPgLaw+XLJhgL5XEFdEyt/ccRLvOmULlA3pmccYYz2QULFRtMW
hyefdOsKnRFSJiFzbIRMeVXk0WvoBj1IFVKtsyjbqv9u/2CVSndrOfEk0TG23U3A
xPxTuW1CrbV8/q71FdIzSOciccfCFHpsKOo3St/qbLVytH5aohbcabFXRNsKEqve
ww9HdFxBIuGa+RuT5q0iBikusbpJHAwnnqP7i/dAcgCskgjZjFeEU4EFy+b+a1SY
QCeFxxC7c3DvaRhBB0VVfPlkPz0sw6l865MaTIbRyoUCAwEAAaMyMDAwCQYDVR0T
BAIwADAjBgNVHREEHDAaggwqLmJhZHNzbC5jb22CCmJhZHNzbC5jb20wDQYJKoZI
hvcNAQELBQADggEBAC4DensZ5tCTeCNJbHABYPwwqLUFOMITKOOgF3t8EqOan0CH
ST1NNi4jPslWrVhQ4Y3UbAhRBdqXl5N/NFfMzDosPpOjFgtifh8Z2s3w8vdlEZzf
A4mYTC8APgdpWyNgMsp8cdXQF7QOfdnqOfdnY+pfc8a8joObR7HEaeVxhJs+XL4E
CLByw5FR+svkYgCbQGWIgrM1cRpmXemt6Gf/XgFNP2PdubxqDEcnWlTMk8FCBVb1
nVDSiPjYShwnWsOOshshCRCAiIBPCKPX0QwKDComQlRrgMIvddaSzFFTKPoNZjC+
CUspSNnL7V9IIHvqKlRSmu+zIpm2VJCp1xLulk8=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,17 @@
use std::env;
/// Cargo, at least sometimes, sets SSL_CERT_FILE and SSL_CERT_DIR internally, as
/// it uses OpenSSL. So, always unset both at the beginning of a test even if
/// the test doesn't use either.
///
/// # Safety
///
/// This is only safe if used together with `#[serial]` because calling
/// `[env::remove_var()]` is unsafe if another thread is running.
///
/// Note that `env::remove_var()` is scheduled to become unsafe in Rust
/// Edition 2024.
pub(crate) unsafe fn clear_env() {
env::remove_var("SSL_CERT_FILE");
env::remove_var("SSL_CERT_DIR");
}

View File

@@ -0,0 +1,152 @@
//! This test attempts to verify that the set of 'native'
//! certificates produced by this crate is roughly similar
//! to the set of certificates in the mozilla root program
//! as expressed by the `webpki-roots` crate.
//!
//! This is, obviously, quite a heuristic test.
mod common;
use std::collections::HashMap;
use pki_types::Der;
use ring::io::der;
use serial_test::serial;
use webpki::anchor_from_trusted_cert;
fn stringify_x500name(subject: &Der<'_>) -> String {
let mut parts = vec![];
let mut reader = untrusted::Reader::new(subject.as_ref().into());
while !reader.at_end() {
let (tag, contents) = der::read_tag_and_get_value(&mut reader).unwrap();
assert!(tag == 0x31); // sequence, constructed, context=1
let mut inner = untrusted::Reader::new(contents);
let pair = der::expect_tag_and_get_value(&mut inner, der::Tag::Sequence).unwrap();
let mut pair = untrusted::Reader::new(pair);
let oid = der::expect_tag_and_get_value(&mut pair, der::Tag::OID).unwrap();
let (value_ty, value) = der::read_tag_and_get_value(&mut pair).unwrap();
let name = match oid.as_slice_less_safe() {
[0x55, 0x04, 0x03] => "CN",
[0x55, 0x04, 0x05] => "serialNumber",
[0x55, 0x04, 0x06] => "C",
[0x55, 0x04, 0x07] => "L",
[0x55, 0x04, 0x08] => "ST",
[0x55, 0x04, 0x09] => "STREET",
[0x55, 0x04, 0x0a] => "O",
[0x55, 0x04, 0x0b] => "OU",
[0x55, 0x04, 0x11] => "postalCode",
[0x55, 0x04, 0x61] => "organizationIdentifier",
[0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19] => "domainComponent",
[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01] => "emailAddress",
_ => panic!("unhandled x500 attr {oid:?}"),
};
let str_value = match value_ty {
// PrintableString, UTF8String, TeletexString or IA5String
0x0c | 0x13 | 0x14 | 0x16 => std::str::from_utf8(value.as_slice_less_safe()).unwrap(),
_ => panic!("unhandled x500 value type {value_ty:?}"),
};
parts.push(format!("{name}={str_value}"));
}
parts.join(", ")
}
#[test]
fn test_does_not_have_many_roots_unknown_by_mozilla() {
let native = rustls_native_certs::load_native_certs();
let mozilla = webpki_roots::TLS_SERVER_ROOTS
.iter()
.map(|ta| (ta.subject_public_key_info.as_ref(), ta))
.collect::<HashMap<_, _>>();
let mut missing_in_moz_roots = 0;
for cert in &native.certs {
let cert = anchor_from_trusted_cert(cert).unwrap();
if let Some(moz) = mozilla.get(cert.subject_public_key_info.as_ref()) {
assert_eq!(cert.subject, moz.subject, "subjects differ for public key");
} else {
println!(
"Native anchor {:?} is missing from mozilla set",
stringify_x500name(&cert.subject)
);
missing_in_moz_roots += 1;
}
}
#[cfg(windows)]
let threshold = 2.0; // no more than 160% extra roots; windows CI vm has lots of extra roots
#[cfg(target_os = "macos")]
let threshold = 0.6; // macOS has a bunch of extra roots, too
#[cfg(not(any(windows, target_os = "macos")))]
let threshold = 0.5; // no more than 50% extra roots
let diff = (missing_in_moz_roots as f64) / (mozilla.len() as f64);
println!("mozilla: {:?}", mozilla.len());
println!("native: {:?}", native.certs.len());
println!(
"{missing_in_moz_roots:?} anchors present in native set but not mozilla ({}%)",
diff * 100.
);
assert!(diff < threshold, "too many unknown roots");
}
#[test]
fn test_contains_most_roots_known_by_mozilla() {
let native = rustls_native_certs::load_native_certs();
let mut native_map = HashMap::new();
for anchor in &native.certs {
let cert = anchor_from_trusted_cert(anchor).unwrap();
let spki = cert.subject_public_key_info.as_ref();
native_map.insert(spki.to_owned(), anchor);
}
let mut missing_in_native_roots = 0;
let mozilla = webpki_roots::TLS_SERVER_ROOTS;
for cert in mozilla {
if !native_map.contains_key(cert.subject_public_key_info.as_ref()) {
println!(
"Mozilla anchor {:?} is missing from native set",
stringify_x500name(&cert.subject)
);
missing_in_native_roots += 1;
}
}
#[cfg(windows)]
let threshold = 0.95; // no more than 95% extra roots; windows misses *many* roots
#[cfg(target_os = "macos")]
let threshold = 0.6; // no more than 60% extra roots; macOS has a bunch of extra roots, too
#[cfg(not(any(windows, target_os = "macos")))]
let threshold = 0.5; // no more than 50% extra roots
let diff = (missing_in_native_roots as f64) / (mozilla.len() as f64);
println!("mozilla: {:?}", mozilla.len());
println!("native: {:?}", native.certs.len());
println!(
"{missing_in_native_roots:?} anchors present in mozilla set but not native ({}%)",
diff * 100.
);
assert!(diff < threshold, "too many missing roots");
}
#[test]
#[serial]
fn util_list_certs() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
let native = rustls_native_certs::load_native_certs();
for (i, cert) in native.certs.iter().enumerate() {
let cert = anchor_from_trusted_cert(cert).unwrap();
println!("cert[{i}] = {}", stringify_x500name(&cert.subject));
}
}

View File

@@ -0,0 +1,329 @@
mod common;
use std::io::{ErrorKind, Read, Write};
use std::net::TcpStream;
#[cfg(unix)]
use std::os::unix::fs::symlink;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::{env, panic};
// #[serial] is used on all these tests to run them sequentially. If they're run in parallel,
// the global env var configuration in the env var test interferes with the others.
use serial_test::serial;
/// Check if connection to site works using native roots.
///
/// Yields an Err if and only if there is an issue connecting that
/// appears to be due to a certificate problem.
///
/// # Panics
///
/// Panics on errors unrelated to the TLS connection like errors during
/// certificate loading, or connecting via TCP.
fn check_site(domain: &str) -> Result<(), ()> {
check_site_with_roots(domain, rustls_native_certs::load_native_certs().unwrap())
}
/// Check if connection to site works using the given roots.
///
/// Yields an Err if and only if there is an issue connecting that
/// appears to be due to a certificate problem.
///
/// # Panics
///
/// Panics on errors unrelated to the TLS connection like connecting via TCP.
fn check_site_with_roots(
domain: &str,
root_certs: Vec<pki_types::CertificateDer<'static>>,
) -> Result<(), ()> {
let mut roots = rustls::RootCertStore::empty();
roots.add_parsable_certificates(root_certs);
let config = rustls::ClientConfig::builder()
.with_root_certificates(roots)
.with_no_client_auth();
let mut conn = rustls::ClientConnection::new(
Arc::new(config),
pki_types::ServerName::try_from(domain)
.unwrap()
.to_owned(),
)
.unwrap();
let mut sock = TcpStream::connect(format!("{domain}:443")).unwrap();
let mut tls = rustls::Stream::new(&mut conn, &mut sock);
let result = tls.write_all(
format!(
"GET / HTTP/1.1\r\n\
Host: {domain}\r\n\
Connection: close\r\n\
Accept-Encoding: identity\r\n\
\r\n"
)
.as_bytes(),
);
match result {
Ok(()) => (),
Err(e) if e.kind() == ErrorKind::InvalidData => return Err(()), // TLS error
Err(e) => panic!("{e}"),
}
let mut plaintext = [0u8; 1024];
let len = tls.read(&mut plaintext).unwrap();
assert!(plaintext[..len].starts_with(b"HTTP/1.1 ")); // or whatever
Ok(())
}
#[test]
#[serial]
#[ignore]
fn google() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
check_site("google.com").unwrap();
}
#[test]
#[serial]
#[ignore]
fn amazon() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
check_site("amazon.com").unwrap();
}
#[test]
#[serial]
#[ignore]
fn facebook() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
check_site("facebook.com").unwrap();
}
#[test]
#[serial]
#[ignore]
fn netflix() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
check_site("netflix.com").unwrap();
}
#[test]
#[serial]
#[ignore]
fn ebay() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
check_site("ebay.com").unwrap();
}
#[test]
#[serial]
#[ignore]
fn apple() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
check_site("apple.com").unwrap();
}
#[test]
#[serial]
#[ignore]
fn badssl_with_env() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
// Self-signed certs should never be trusted by default:
assert!(check_site("self-signed.badssl.com").is_err());
// But they should be trusted if SSL_CERT_FILE is set:
env::set_var(
"SSL_CERT_FILE",
// The CA cert, downloaded directly from the site itself:
PathBuf::from("./tests/badssl-com-chain.pem"),
);
check_site("self-signed.badssl.com").unwrap();
}
#[test]
#[serial]
#[ignore]
fn badssl_with_dir_from_env() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
let temp_dir = tempfile::TempDir::new().unwrap();
let original = Path::new("tests/badssl-com-chain.pem")
.canonicalize()
.unwrap();
let link1 = temp_dir.path().join("5d30f3c5.3");
#[cfg(unix)]
let link2 = temp_dir.path().join("fd3003c5.0");
env::set_var(
"SSL_CERT_DIR",
// The CA cert, downloaded directly from the site itself:
temp_dir.path(),
);
assert!(check_site("self-signed.badssl.com").is_err());
// OpenSSL uses symlinks too. So, use one for testing too, if possible.
#[cfg(unix)]
symlink(original, link1).unwrap();
#[cfg(not(unix))]
std::fs::copy(original, link1).unwrap();
// Dangling symlink
#[cfg(unix)]
symlink("/a/path/which/does/not/exist/hopefully", link2).unwrap();
check_site("self-signed.badssl.com").unwrap();
}
#[test]
#[serial]
#[ignore]
fn ssl_cert_dir_multiple_paths_are_respected() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
// Create 2 temporary directories
let temp_dir1 = tempfile::TempDir::new().unwrap();
let temp_dir2 = tempfile::TempDir::new().unwrap();
// Copy the certificate to the 2nd dir, leaving the 1st one
// empty.
let original = Path::new("tests/badssl-com-chain.pem")
.canonicalize()
.unwrap();
let cert = temp_dir2.path().join("5d30f3c5.3");
std::fs::copy(original, cert).unwrap();
let list_sep = if cfg!(windows) { ';' } else { ':' };
let value = format!(
"{}{}{}",
temp_dir1.path().display(),
list_sep,
temp_dir2.path().display()
);
env::set_var("SSL_CERT_DIR", value);
check_site("self-signed.badssl.com").unwrap();
}
#[test]
#[serial]
#[ignore]
fn ssl_cert_dir_non_hash_based_name() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
// Create temporary directory
let temp_dir = tempfile::TempDir::new().unwrap();
// Copy the certificate to the dir
let original = Path::new("tests/badssl-com-chain.pem")
.canonicalize()
.unwrap();
let cert = temp_dir.path().join("test.pem");
std::fs::copy(original, cert).unwrap();
env::set_var(
"SSL_CERT_DIR",
// The CA cert, downloaded directly from the site itself:
temp_dir.path(),
);
check_site("self-signed.badssl.com").unwrap();
}
#[test]
#[serial]
#[ignore]
#[cfg(target_os = "linux")]
fn google_with_dir_but_broken_file() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
env::set_var("SSL_CERT_DIR", "/etc/ssl/certs");
env::set_var("SSL_CERT_FILE", "not-exist");
let res = rustls_native_certs::load_native_certs();
let first_err = res.errors.first().unwrap().to_string();
dbg!(&first_err);
assert!(first_err.contains("from file"));
assert!(first_err.contains("not-exist"));
check_site_with_roots("google.com", res.certs).unwrap();
}
#[test]
#[serial]
#[ignore]
#[cfg(target_os = "linux")]
fn google_with_file_but_broken_dir() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
env::set_var("SSL_CERT_DIR", "/not-exist");
env::set_var("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt");
let res = rustls_native_certs::load_native_certs();
let first_err = res.errors.first().unwrap().to_string();
dbg!(&first_err);
assert!(first_err.contains("opening directory"));
assert!(first_err.contains("/not-exist"));
check_site_with_roots("google.com", res.certs).unwrap();
}
#[test]
#[serial]
#[ignore]
#[cfg(target_os = "linux")]
fn nothing_works_with_broken_file_and_dir() {
unsafe {
// SAFETY: safe because of #[serial]
common::clear_env();
}
env::set_var("SSL_CERT_DIR", "/not-exist");
env::set_var("SSL_CERT_FILE", "not-exist");
let res = rustls_native_certs::load_native_certs();
assert_eq!(res.errors.len(), 2);
let first_err = res.errors.first().unwrap().to_string();
dbg!(&first_err);
assert!(first_err.contains("from file"));
assert!(first_err.contains("not-exist"));
let second_err = res.errors.get(1).unwrap().to_string();
dbg!(&second_err);
assert!(second_err.contains("opening directory"));
assert!(second_err.contains("/not-exist"));
}