Breaking changes in rustls

Rustls 0.18 docs:

This is the minimum you need to do to make a TLS client connection.

First, we make a ClientConfig . You're likely to make one of these per process, and use it for all connections made by that process.

let mut config = rustls::ClientConfig::new();

Next we load some root certificates. These are used to authenticate the server. The recommended way is to depend on the webpki_roots crate which contains the Mozilla set of root certificates.

config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);

rustls 0.20 docs:

This is the minimum you need to do to make a TLS client connection.

First we load some root certificates. These are used to authenticate the server. The recommended way is to depend on the webpki_roots crate which contains the Mozilla set of root certificates.

let mut root_store = rustls::RootCertStore::empty();
root_store.add_server_trust_anchors(
    webpki_roots::TLS_SERVER_ROOTS
        .0
        .iter()
        .map(|ta| {
            rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
                ta.subject,
                ta.spki,
                ta.name_constraints,
            )
        })
);

Next, we make a ClientConfig . You’re likely to make one of these per process, and use it for all connections made by that process.

let config = rustls::ClientConfig::builder()
    .with_safe_defaults()
    .with_root_certificates(root_store)
    .with_no_client_auth();

WTF? There's a whole page of breaking changes. Was all this really necessary?

You have to copy and paste all that boilerplate. Since that obscure code is only in the docs, not the code itself, it's untested. Great place for a backdoor.

I got a compile error after an update, because I now had two versions of rustls. So I have to change my code to comply. I'm still trying to get a custom verify_server_cert to compile. "add_pem_file" has disappeared from the API, too. There's now a new crate, " rustls_pemfile", which now seems to be necessary. I managed to bash it into working. I think. I trust the code much less now.

All this makes rustls much more likely to have new security flaws. Usage is now much more complex and has far more moving parts.

Not to defend the change (I also feel this shouldn't be necessary), but do note that code examples in docs are automatically tested with cargo test.

5 Likes

I agree that this is a bad breaking change and makes client code more fragile, too.

Rustls should be instructing users to use the system root store by default if they have std, and only bundling roots if you don't have access to the system root store.

Bundling roots also commits you to a hard update delivery cadence, which violates people's assumptions of "compile once, run for ten years".

I hadn't realized what they are doing. They are nailing the root certs into the executable program as a constant. Here they are: lib.rs - source

Yeah, this was one of the most obscure things about rustls when I last used it (FWIW, that was about 2 years ago!)

If at all possible, use the system-provided root certs with a crate like rustls-native-certs. I don't know how well it's supported or kept in sync with upstream. But this was the conclusion I came to way back when.

"Status: rustls-native-certs is currently in development."

This is one of those areas where you really want stability. Churn in the crypto libraries is worrisome.

(We're making progress. There was a time when OpenSSL was supported by a World of Warcraft guild.)

I kind of see what happened. "rustls" doesn't do I/O. It's pure compute. So it can be used by both normal and "async" code. If you want to read the system-provided root certs, that involves a blocking I/O operation. So there has to be a sync and an async version.

You're not supposed to use "rustls" directly, apparently. If you use "reqwest", it calls the rustls layer internally.

1 Like

Perhaps they are very concerned about system root store attacks. It's come up more frequently in recent years; an organization or government distributing computers with custom root stores to enact MITM attacks on the recipients. Regardless, it sounds like the documentation around this could be better.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.