Skip to content

Commit

Permalink
platform-verifier as feature
Browse files Browse the repository at this point in the history
  • Loading branch information
algesten committed Oct 12, 2024
1 parent b0b321f commit 19536f1
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 10 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ exclude = ["/cargo_deny.sh", "/deny.toml", "/test.sh"]
rust-version = "1.67"

[package.metadata.docs.rs]
features = ["rustls", "native-tls", "socks-proxy", "cookies", "gzip", "brotli", "charset", "json", "_test"]
features = ["rustls", "platform-verifier", "native-tls", "socks-proxy", "cookies", "gzip", "brotli", "charset", "json", "_test"]

[features]
default = ["rustls", "gzip", "json"]
rustls = ["dep:rustls", "_tls", "dep:rustls-platform-verifier", "dep:webpki-roots"]
rustls = ["dep:rustls", "_tls", "dep:webpki-roots"]
platform-verifier = ["dep:rustls-platform-verifier"]
native-tls = ["dep:native-tls", "dep:der", "_tls", "dep:webpki-root-certs"]
socks-proxy = ["dep:socks"]
cookies = ["dep:cookie_store", "_url"]
Expand Down
53 changes: 51 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ The default enabled features are: **rustls**, **gzip** and **json**.
accidentally switching on an unwanted TLS implementation, `native-tls` is never picked up as
a default or used by the crate level convenience calls (`ureq::get` etc) – it must be configured
on the agent.
* **platform-verifier** enables verifying the server certificates using a method native to the
platform ureq is executing on. See [rustls-platform-verifier] crate.
* **socks-proxy** enables proxy config using the `socks4://`, `socks4a://`, `socks5://`
and `socks://` (equal to `socks5://`) prefix.
* **cookies** enables cookies.
Expand All @@ -166,12 +168,12 @@ The default enabled features are: **rustls**, **gzip** and **json**.

## TLS (https)

### rustls

By default, ureq uses [`rustls` crate] with the `ring` cryptographic provider.
As of Sep 2024, the `ring` provider has a higher chance of compiling successfully. If the user
installs another [default provider], that choice is respected.

### rustls

```rust
// This uses rustls
ureq::get("https://www.google.com/").call().unwrap();
Expand Down Expand Up @@ -203,6 +205,51 @@ let agent = config.new_agent();
agent.get("https://www.google.com/").call().unwrap();
```

### Root certificates

#### webpki-roots

By default, ureq uses Mozilla's root certificates via the [webpki-roots] crate. This is a static
bundle of root certificates that do not update automatically. It also circumvents whatever root
certificates are installed on the host running ureq, which might be a good or a bad thing depending
on your perspective. There is also no mechanism for
[SCT](https://en.wikipedia.org/wiki/Certificate_Transparency),
[CRLs](https://en.wikipedia.org/wiki/Certificate_revocation_list) or other revocations.
To maintain a "fresh" list of root certs, you need to bump the ureq dependency from time to time.

The main reason for chosing this as the default is to minimize the number of dependencies. More
details about this decision can be found at [PR 818](https://github.com/algesten/ureq/pull/818)

If your use case for ureq is talking to a limited number of servers with high trust, the
default setting is likely sufficient. If you use ureq with a high number of servers, or servers
you don't trust, we recommend using the platform verifier (see below).

#### platform-verifier

The [rustls-platform-verifier] crate provides access to natively checking the certificate via your OS.
To use this verifier, you need to enable it using feature flag **platform-verifier** as well as
configure an agent to use it.

```rust
use ureq::Agent;
use ureq::tls::{TlsConfig, RootCerts};

let agent = Agent::config_builder()
.tls_config(
TlsConfig::builder()
.root_certs(RootCerts::PlatformVerifier)
.build()
)
.build()
.new_agent();

let response = agent.get("https://httpbin.org/get").call()?;
```

Setting `RootCerts::PlatformVerifier` together with `TlsProvider::NativeTls` means
also native-tls will use the OS roots instead of [webpki-roots] crate. Whether that
results in a config that has CRLs and revocations is up to whatever native-tls links to.

## JSON

By enabling the **json** feature, the library supports serde json.
Expand Down Expand Up @@ -322,6 +369,8 @@ Proxies settings are configured on an [Agent]. All request sent through the agen
[`rustls` crate]: https://crates.io/crates/rustls
[default provider]: https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html#method.install_default
[`native-tls`]: https://crates.io/crates/native-tls
[rustls-platform-verifier]: https://crates.io/crates/rustls-platform-verifier
[webpki-roots]: https://crates.io/crates/webpki-roots

### Example using HTTP

Expand Down
56 changes: 54 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@
//! accidentally switching on an unwanted TLS implementation, `native-tls` is never picked up as
//! a default or used by the crate level convenience calls (`ureq::get` etc) – it must be configured
//! on the agent.
//! * **platform-verifier** enables verifying the server certificates using a method native to the
//! platform ureq is executing on. See [rustls-platform-verifier] crate.
//! * **socks-proxy** enables proxy config using the `socks4://`, `socks4a://`, `socks5://`
//! and `socks://` (equal to `socks5://`) prefix.
//! * **cookies** enables cookies.
Expand All @@ -158,12 +160,12 @@
//!
//! # TLS (https)
//!
//! ## rustls
//!
//! By default, ureq uses [`rustls` crate] with the `ring` cryptographic provider.
//! As of Sep 2024, the `ring` provider has a higher chance of compiling successfully. If the user
//! installs another [default provider], that choice is respected.
//!
//! ## rustls
//!
//! ```
//! # #[cfg(feature = "rustls")]
//! # {
Expand Down Expand Up @@ -201,6 +203,54 @@
//! # } Ok::<_, ureq::Error>(())
//! ```
//!
//! ## Root certificates
//!
//! ### webpki-roots
//!
//! By default, ureq uses Mozilla's root certificates via the [webpki-roots] crate. This is a static
//! bundle of root certificates that do not update automatically. It also circumvents whatever root
//! certificates are installed on the host running ureq, which might be a good or a bad thing depending
//! on your perspective. There is also no mechanism for
//! [SCT](https://en.wikipedia.org/wiki/Certificate_Transparency),
//! [CRLs](https://en.wikipedia.org/wiki/Certificate_revocation_list) or other revocations.
//! To maintain a "fresh" list of root certs, you need to bump the ureq dependency from time to time.
//!
//! The main reason for chosing this as the default is to minimize the number of dependencies. More
//! details about this decision can be found at [PR 818](https://github.com/algesten/ureq/pull/818)
//!
//! If your use case for ureq is talking to a limited number of servers with high trust, the
//! default setting is likely sufficient. If you use ureq with a high number of servers, or servers
//! you don't trust, we recommend using the platform verifier (see below).
//!
//! ### platform-verifier
//!
//! The [rustls-platform-verifier] crate provides access to natively checking the certificate via your OS.
//! To use this verifier, you need to enable it using feature flag **platform-verifier** as well as
//! configure an agent to use it.
//!
//! ```
//! # #[cfg(all(feature = "rustls", feature="platform-verifier"))]
//! # {
//! use ureq::Agent;
//! use ureq::tls::{TlsConfig, RootCerts};
//!
//! let agent = Agent::config_builder()
//! .tls_config(
//! TlsConfig::builder()
//! .root_certs(RootCerts::PlatformVerifier)
//! .build()
//! )
//! .build()
//! .new_agent();
//!
//! let response = agent.get("https://httpbin.org/get").call()?;
//! # } Ok::<_, ureq::Error>(())
//! ```
//!
//! Setting `RootCerts::PlatformVerifier` together with `TlsProvider::NativeTls` means
//! also native-tls will use the OS roots instead of [webpki-roots] crate. Whether that
//! results in a config that has CRLs and revocations is up to whatever native-tls links to.
//!
//! # JSON
//!
//! By enabling the **json** feature, the library supports serde json.
Expand Down Expand Up @@ -321,6 +371,8 @@
//! [`rustls` crate]: https://crates.io/crates/rustls
//! [default provider]: https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html#method.install_default
//! [`native-tls`]: https://crates.io/crates/native-tls
//! [rustls-platform-verifier]: https://crates.io/crates/rustls-platform-verifier
//! [webpki-roots]: https://crates.io/crates/webpki-roots
//!
//! ## Example using HTTP
//!
Expand Down
11 changes: 7 additions & 4 deletions src/tls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub struct TlsConfig {

/// The set of trusted root certificates to use to validate server certificates.
///
/// Defaults to `PlatformVerifier` to use the platform default root certs.
/// Defaults to `WebPki`.
pub(crate) root_certs: RootCerts,

/// Whether to send SNI (Server Name Indication) to the remote server.
Expand Down Expand Up @@ -132,7 +132,7 @@ impl TlsConfigBuilder {

/// The set of trusted root certificates to use to validate server certificates.
///
/// Defaults to `PlatformVerifier` to use the platform default root certs.
/// Defaults to `WebPki`.
pub fn root_certs(mut self, v: RootCerts) -> Self {
self.config.root_certs = v;
self
Expand Down Expand Up @@ -184,14 +184,17 @@ pub enum RootCerts {

/// Use the platform's verifier.
///
/// * For **rustls**, this uses the `rustls-platform-verifier` crate.
/// * For **rustls**, this uses the `rustls-platform-verifier` crate. It requires
/// the feature **platform-verifier**.
/// * For **native-tls**, this uses the roots that native-tls loads by default.
PlatformVerifier,

/// Use Mozilla's root certificates instead of the platform.
///
/// This is useful when you can't trust the system roots, such as in
/// environments where TLS is intercepted and decrypted by a proxy (MITM attack).
///
/// This is the default value.
WebPki,
}

Expand All @@ -214,7 +217,7 @@ impl Default for TlsConfig {
Self {
provider,
client_cert: None,
root_certs: RootCerts::PlatformVerifier,
root_certs: RootCerts::WebPki,
use_sni: true,
disable_verification: false,
}
Expand Down
5 changes: 5 additions & 0 deletions src/tls/rustls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ fn build_config(tls_config: &TlsConfig) -> Arc<ClientConfig> {

builder.with_root_certificates(root_store)
}
#[cfg(not(feature = "platform-verifier"))]
RootCerts::PlatformVerifier => {
panic!("Rustls + PlatformVerifier requires feature: platform-verifier");
}
#[cfg(feature = "platform-verifier")]
RootCerts::PlatformVerifier => builder
// This actually not dangerous. The rustls_platform_verifier is safe.
.dangerous()
Expand Down

0 comments on commit 19536f1

Please sign in to comment.