When building a client config or a server config using the default
provider we know that the ciphersuites will be compatible with any
choice of protocol version. By having the default `builder` method
configure itself with safe default versions, and offering
a `builder_with_protocol_versions` for customization we can transition
directly to `WantsVerifier` for these default provider builders,
removing a `Result` that will never be an error and making the API more
ergonomic in the common case.
This commit replaces the existing `CryptoProvider` trait with
a `CryptoProvider` struct. This has several advantages:
* it consolidates all of the cryptography related settings into one API
surface, the `CryptoProvider` struct members. Previously the provider
had methods to suggest default ciphersuites, key exchanges etc, but
the builder API methods could override them in confusing ways.
* it allows removing the `WantsCipherSuites` and `WantsKxGroups` builder
states - the "safe defaults" are automatically supplied by the choice
of a crypto provider. Customization is achieved by overriding the
provider's struct fields. Having fewer builder states makes the API
easier to understand and document.
* it makes customization easier: the end user can rely on "struct update
syntax"[0] to only specify fields values for the required
customization, and defer the rest to an existing `CryptoProvider`.
Achieving this requires a couple of additional changes:
* The cipher suite and key exchange groups are now expressed as `Vec`
elements. This avoids imposing a `&'static` lifetime that would
preclude runtime customization (e.g. the tls*-mio examples that
build the list of ciphersuites at runtime based on command line
flags).
* As a result of the `Vec` members we can no longer offer the concrete
`CryptoProvider`s as `static` members of their respective modules.
Instead we add `pub fn default_provider() -> CryptoProvider` methods
to the `ring` and `aws-lc-rs` module that construct the `CryptoProvider`
with the safe defaults, ready for further customization.
[0]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax
These helpers assumed the *ring* crypto provider. Consumers can now use
the exported `verify_tls12_signature` and `verify_tls13_signature`
helpers with the crypto provider of their choice to implement these fns.
Similarly since `WebPkiSupportedAlgorithms` now exposes the
`supported_schemes` fn there's no need for the
`default_supported_verify_schemes` helper.
This commit adds a `Debug` bound to the `ServerCertVerifier` trait in
addition to `Send` and `Sync`. Types implementing this trait are updated
to either derive `Debug` or implement it by hand as appropriate.
Naming cipher suites individually seems like a "detail" feature, and
therefore having to name the provider too is not a large imposition.
Naturally this is a breaking change.
The `rcgen` crate has cut a 0.11.2 release that includes the CRL
functionality we were using a Cargo patch to depend on previously. This
commit removes the patch, fixes one breakage in the server acceptor
example, and updates the `Cargo.toml` and `Cargo.lock` files.
In an effort to reduce our feature list, this commit replaces the
`dangerous_configuration` feature flag with separate `danger` modules.
Cargo features are additive, which means transitive dependencies could
enable them for you without explicit opt-in. Using obviously named
modules will maintain the property that it's easy to grep for imports,
but avoids feature flag bloat and the additive downsides.
After discussion we've chosen to not include the webpki verifier and
helper functions as part of the dangerous API surface. Functionality for
setting a custom verifier, or implementing one to make assertions about
verification status, remain marked as dangerous via their module name.
Instead of the type `rustls::crypto:💍:Ring`, the value
`rustls::crypto:💍:RING` implements this, and is more
entertaining to write.
`ServerConfig::builder()` references this by default, and
is equivalent to `ServerConfig::builder_with_provider(crypto:💍:RING)`.
This turns `SupportedKxGroup` into a trait, which can tell you
which `NamedGroup` it is, and `start()` an `ActiveKeyExchange`.
An `ActiveKeyExchange` represents the need for the peer's public key
which can be passed to `ActiveKeyExchange::complete`.
Unfortunately we can't be generic at compile-time over the various uses
of the resulting shared secret, so define a further type
which encapsulates the resulting shared secret.
Predefined key exchange algorithms (eg `rustls::kx_group::X25519`)
are now `&'static dyn rustls::SupportedKxGroup`.
The remainder of this commit is noise as much code ceased needing
to be generic of CryptoProvider (for its `KeyExchange` associated type).
The example programs distributed with Rustls are often used to
demonstrate TLS features, or debug issues, that require being able to
view plaintext data captured in a pcap (e.g. with Wireshark).
To make this convenient this commit updates the examples (minus the MIO
examples that already did so ) to configure Rustls with a `KeyLogFile`
implementation of the `KeyLog` trait. Users can then specify the
`SSLKEYLOGFILE` environment variable to log the required session secrets
for use with their pcap tool of choice.
This example has two main purposes:
1. It shows how to use the `Acceptor` API to customize a `ServerConfig`
per-connection, possibly using information from the received
`ClientHello`.
2. It shows how to load CRL information per-connection to ensure the
freshest CRL content is used when validating client certificate
revocation status.
Additionally this example uses `rcgen` to generate its own test PKI,
potentially being a helpful reference for folks that want to do similar
without needing to manually construct certs with `openssl`.
To simulate CRL updates this example program spawns a background thread
that periodically replaces the CRL content, flipping back and forth
between a CRL that lists the client certificate as revoked, and a CRL
that has no revoked certificates.
Using `tlsclient-mio` (or another TLS client program) with the generated
client certificate/key you can observe the CRL updates happening by
connecting to the server, waiting a little bit, and then connecting
again. The result will differ based on the CRL update:
```
$ cargo run --bin tlsclient-mio -- --auth-certs ./client-cert.pem --auth-key ./client-key.pem --cafile ca-cert.pem --port 4443 --http localhost
TLS error: AlertReceived(CertificateRevoked)
Connection closed
<waiting>
$ cargo run --bin tlsclient-mio -- --auth-certs ./client-cert.pem --auth-key ./client-key.pem --cafile ca-cert.pem --port 4443 --http localhost
EOF
Connection closed
```
In the server, bind `::` instead of `0.0.0.0`.
In the client:
* delete a comment about `openssl s_client/s_server` not supporting
IPv6 - we don't test these examples against OpenSSL anymore.
* rework `lookup_ipv4` as `lookup_ip`, returning the first socket
address whether or not it's IPv4.
This is a breaking change.
These introduced an implicit dependency on the `webpki` crate
for anyone who wanted to implement these traits.
Instead, someone who wants to benefit from the `webpki`-backed
implementations should dispatch to `WebPkiServerVerifier` themselves.
Expose these defaults explicitly, and dispatch to them in our
various bits of example and test code.
As pointed out by Jsha, an implementation of the `Acceptor` API may want
to create a verifier on something approaching a per-handshake basis in
order to provide up-to-date CRLs and client trust anchors.
We can improve on the cost of this operation by allowing shared use of
a `RootCertStore` across verifiers by wrapping it in an `Arc`.
This commit updates the `WebPkiClientVerifier`, and
`ClientCertVerifierBuilder` to take a `Arc<RootCertStore>` instead of
`RootCertStore`.
One side-effect of this change is the removal of the `add_roots` fn of
the `ClientCertVerifierBuilder` - once we take an `Arc` we can't modify
the backing `RootCertStore` without introducing some form of locking.
I think the use-case for adding additional `RootCertStore`'s after
constructing the builder is weak enough that we should drop that feature
rather than introduce locking.
The `RootCertStore` type is used for both client and server trust
anchors. This commit renames the `add_server_trust_anchors` method to be
`add_trust_anchors` to reflect its general purpose.
Previously users configuring a `ServerConfig` that wanted to use
a webpki backed client certificate verifier had to make a choice of
which concrete implementation to construct, and how to configure it
(e.g. with trust anchors and CRLs). This made for a somewhat cumbersome
experience.
In its place, this commit:
* Adds a `WebPkiClientVerifier` type that replace both the
`AllowAnyAuthenticatedClient` and `AllowAnyAnonymousOrAuthenticatedClient`
verifiers. The name emphasizes that the implementation is backed by
`rustls/webpki` to help distinguish it from platform verifiers.
The new type can only be constructed external to the crate using
a `ClientCertVerifierBuilder` builder that walks the user through
specifying roots, CRLs, and policy for anonymous clients.
* Turns the `NoClientAuth` verifier into a crate internal type that also
only be constructed via the `ClientCertVerifierBuilder`.
* Removes the `boxed()` fn's of the above, since they won't be needed
anymore - consumers will construct a `Arc<dyn ClientCertVerifier>`
through the builder and don't need to have `ClientCertVerifier`
in-scope via the dangerous config feature.
* Updates all existing usages in tests and examples to use the new
builder API.
This commit adds a `KeyExchange` associated type to the `CryptoProvider`
trait. The `KeyExchange` type is constrained with its own `KeyExchange`
trait that has an associated type for the `SupportedGroup`.
In the `crypto::ring` package we adapt the existing *ring* specific
`KeyExchange` and `SupportedKxGroup` types to these new traits.
Throughout the codebase we tighten generic bounds where required to
ensure we have a `CryptoProvider` bound that allows accessing the
associated `KeyExchange` and `SupportedGroup`. We also make the
`CryptoProvider` an associated type on the `Side` config.
For better code organization this commit moves the generic crypto
interface code from `src/crypto.rs` to `src/crypto/lib.rs`.
The *ring* specific code implementing the generic interfaces is moved to
`src/crypto/ring.rs` as a sub-module of `crypto. All imports are
adjusted accordingly.
This has the advantage of leaving `src/crypto/lib.rs` small, and without
any *ring* specific imports. In the future we may choose to feature-gate
the ring sub-module to allow building the crate without a dependency on
ring.
This commit renames the `ClientConfig` builder's `with_single_cert`
function to be called `with_client_auth_cert`. The old
`with_single_cert` function is left as an alias for
`with_client_auth_cert` and marked as deprecated to encourage users to
switch to the new name.
I believe this offers better symmetry with the `with_no_client_auth`
function that's used to disable client authentication, and more clearly
conveys the purpose of this function is for providing a client
authentication certificate.
This commit introduces `api.rs` integration tests that verify
a server configured with client authentication (mandatory or optional),
and a CRL that specifies a client cert as revoked, will correctly return
a revoked error for that client cert.
In addition to the test CRL data generated in a previous commit this
work requires `rustls-pemfile` >= 1.0.3 to use unreleased CRL support in
the `rustls-pemfile` crate. The rustls dev-dependency and the rustls
example dependency on this crate are adjusted accordingly.