Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add rustls-aws-lc-rs feature for alternative to ring #924

Closed
wants to merge 2 commits into from

Conversation

mrchantey
Copy link

I hope you dont mind me opening a pr without prior discussion, feel free to close for whatever reason.

We're working on adding ureq as a bevy dependency, its lightweight nature is perfect for a game engine, but we're unable to use ring due to its license requiring us to make acknowledgements in all advertising material.

This pr adds two features, each of which enables the rustls feature:

  • rustls-ring (default)
  • rustls-aws-lc-rs

More info for context:

@algesten
Copy link
Owner

algesten commented Jan 4, 2025

@mrchantey Hi there! Thanks for considering ureq!

The discussions you linked concerns ureq 2.x, but the changes you provide are against the main branch, which is ureq-3.x. So the first question in my mind is: which version are you looking at? For new usage, I advice using 3.0.0-RC4. I answered a question about that yesterday

For 3.x, the default choice is still ring, but there is an escape hatch by setting the process default: https://docs.rs/ureq/3.0.0-rc4/ureq/#rustls – this could arguably be elaborated better in the docs. Is this a sufficient fix for what you're trying to do?

@mrchantey
Copy link
Author

Ok great yep happy to wait for ureq-3.x, this feature isn't time critical.

If i understand correctly the following configuration will result in both ring and aws-lc-rs being compiled and included in the final binary, but ring would be ignored?

I'm not sure if including code but absolutely not using it is a licencing workaround, definitely above my pay grade 😅. I'll ask around on the bevy discord.

[dependencies]
ureq = { version = "3.0.0-rc.4", default-features = false, features = [
  "rustls",
  "gzip",
] }
# ensure the same version as ureq
rustls = { version = "0.23", default-features = false, features = [
  "aws_lc_rs",
] }
fn main(){

   rustls::crypto::aws_lc_rs::default_provider()
        .install_default()
        .expect("failed to install rustls https crypto provider");

   let res = ureq::get(str_path).call();
   // etc

}

@alice-i-cecile
Copy link

I don't think we should ship the code, even unlinked. It would be really nice to have it properly feature flagged out.

@algesten
Copy link
Owner

algesten commented Jan 5, 2025

@mrchantey @alice-i-cecile thanks for the feedback!

To explain where current situation. The choice of TLS backend is often made due to compliance. Typically the story goes "you must use the platform provided TLS library so we can update it centrally" (this is the NativeTls config option). Furthermore, when ureq is used in libraries, there's a risk feature flags are enabled that are beyond the user's control. Example:

myapp -> lib1 -> ureq [feature flag A]
myapp -> lib2 -> ureq [feature flag B]

This would end up merging feature flag A+B in the build. This is why we insist the choice of TLS is explicit config, not automatically picked up from feature flags.

The rewrite of ureq 3.x happened exactly at the same time as rustls switched from ring to aws-lc-rs. At the time, the chances of compiling correctly, was higher with ring. ureq's first and foremost imperative is to "work out of the box", hence defaulting to ring. I don't know if the situation has changed in the 6 months since then.

You present a new concern: avoid ring from a compliance perspective. I'm scratching my head a bit on how to approach it. Some thought in random order.

  • How common is this concern? This is the first time I encountered a situation where NativeTls option is not a good route.
  • We want to avoid maintaining multiple TLS backends inside ureq 3.x (this went wrong in 2.x)
  • ureq 3.x has a new "escape hatch" where Transport is possible to change. It's possible to provide other TLS transports in separate crates.
  • I don't want new users to ureq having to get their head around feature flags like rustls-ring vs rustls-aws-lc-rs. ureq is meant to be simple.

I'll fiddle around today and see if I can figure out a good way forward balancing all these thoughts.

Thanks for raising it!

@algesten
Copy link
Owner

algesten commented Jan 5, 2025

#931 is a potential way forward. I like it because it opens up for any CryptoProvider, not just aws-lc-rs. It does however fall outside of semver major-version guarantees. I don't see a way around that as long as rustls is not 1.x.

@algesten
Copy link
Owner

algesten commented Jan 5, 2025

Your specific use case would be:

ureq = { version = "3", default-features = false, features = ["rustls-no-provider"] }
rustls = { version = "0.23", features = ["aws-lc-rs"] }
use std::sync::Arc;
use ureq::{Agent};
use ureq::tls::{TlsConfig, TlsProvider};
use rustls::crypto;
///
let crypto = Arc::new(crypto::aws_lc_rs::default_provider());
///
let agent = Agent::config_builder()
    .tls_config(
        TlsConfig::builder()
            .provider(TlsProvider::Rustls)
            // requires rustls or rustls-no-provider feature
            .unversioned_rustls_crypto_provider(crypto)
            .build()
   )
   .build()
   .new_agent();

@mrchantey
Copy link
Author

Awesome i think we can close this in favor of #931

@mrchantey mrchantey closed this Jan 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants