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

How I use CryptoProvider::install_default() ? #1938

Closed
incker opened this issue May 3, 2024 · 16 comments
Closed

How I use CryptoProvider::install_default() ? #1938

incker opened this issue May 3, 2024 · 16 comments

Comments

@incker
Copy link

incker commented May 3, 2024

Hello, I receive panic
PanicInfo { payload: Any { .. }, message: Some(no process-level CryptoProvider available -- call CryptoProvider::install_default() before this point), location: Location { file: "/home/incker/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rustls-0.23.5/src/crypto/mod.rs", line: 260, col: 14 }, can_unwind: true, force_no_backtrace: false }

But there is no example how to use CryptoProvider::install_default()

Cargo.toml:
rustls = {version = "0.23.5", default-features = false, features = ["std"]}

If I remove default-features = false it requires
Please enable the 'bindgen' feature on aws-lc-rs or aws-lc-sys.For more information, see the aws-lc-rs User Guide: https://aws.github.io/aws-lc-rs/index.html

but adding this:
aws-lc-rs = {version = "1.7.0", features = ["bindgen"]}
requires:
/usr/include/stdio.h:27:10: fatal error: 'bits/libc-header-start.h' file not found
thread 'main' panicked at /home/builder/.cargo/registry/src/index.crates.io-6f17d22bba15001f/aws-lc-sys-0.15.0/builder/bindgen.rs:155:10:
Unable to generate bindings.: ClangDiagnostic("/usr/include/stdio.h:27:10: fatal error: 'bits/libc-header-start.h' file not found\n")

And i haven't found package gcc-multilib for arm-buildroot-linux-musleabihf ((

Forward thank you!

@ctz
Copy link
Member

ctz commented May 3, 2024

But there is no example how to use CryptoProvider::install_default()

See https://docs.rs/rustls/latest/rustls/index.html#crate-features

/usr/include/stdio.h:27:10: fatal error: 'bits/libc-header-start.h' file not found

https://rust-lang.github.io/rust-bindgen/requirements.html#requirements aside from that, yes, you will need a working sysroot for the target and to tell bindgen where it is.

@KarstenB
Copy link

KarstenB commented May 8, 2024

Ok, maybe it is just me, but the simplest solution boils down to using the ring feature of rustls:

cargo add rustls --features ring

And then, early in your main fn call:

rustls::crypto::ring::default_provider().install_default().expect("Failed to install rustls crypto provider");

Correct?

@incker
Copy link
Author

incker commented May 18, 2024

Installing just gcc-multilib helped me
Thanks for everyone!

@lcmgh
Copy link

lcmgh commented Jul 18, 2024

Am I correct that one also has to set rustls::crypto::aws_lc_rs::default_provider().install_default(); for each test that involves rustls?

@cpu
Copy link
Member

cpu commented Jul 18, 2024

@lcmgh The answer to that depends. If your crate only activates one of the ring or aws_lc_rs features of Rustls then no, the tests can use the config constructors that assume the default without you needing to explicitly set it. If however, your crate activates both features, yes, your tests will need to install a default explicitly or stop using the constructors that assume a default is set.

@lcmgh
Copy link

lcmgh commented Jul 18, 2024

rustls = { version = "0.23.5" }

In that case might it be that another dep of me brings rustls with ring and aws_lc_rs into the game because I have not enabled those features explicitly.

@cpu
Copy link
Member

cpu commented Jul 19, 2024

@lcmgh You can likely get to the bottom of that using cargo tree --edges features. Rustls uses aws_lc_rs by default, so you're probably looking for a dependency that is activating ring in addition.

@Tomasz-Kluczkowski
Copy link

Tomasz-Kluczkowski commented Jan 1, 2025

I have code where I am using google-calendar3 CalendarHub struct to communicate with google calendar api.

let mut hub: CalendarHub<HttpsConnector<HttpConnector>>  = ...

Whilst in main I did not need to invoke CryptoProvider I do need to in tests.

The issue is since tests run in parallel I run into a problem that

rustls::crypto::ring::default_provider().install_default().unwrap();

can be called only once per process. So in random order, depending which test managed to call it, it will pass, other tests will fail.
I am assuming this is because of this mentioned in CryptoProvider:

    /// Sets this `CryptoProvider` as the default for this process.
    ///
    /// This can be called successfully at most once in any process execution.
    ///
    /// Call this early in your process to configure which provider is used for
    /// the provider.  The configuration should happen before any use of
    /// [`ClientConfig::builder()`] or [`ServerConfig::builder()`].
    pub fn install_default(self) -> Result<(), Arc<Self>> {
        static_default::install_default(self)
    }

key item: This can be called successfully at most once in any process execution.

So instead of calling:

rustls::crypto::ring::default_provider().install_default().unwrap();

in tests I implemented a little helper function which is thread safe and I call it before instantiation CalendarHub in each test:

static CRYPTO_PROVIDER_LOCK: OnceLock<()> = OnceLock::new();

fn setup_default_crypto_provider() {
    CRYPTO_PROVIDER_LOCK.get_or_init(|| rustls::crypto::ring::default_provider().install_default().unwrap());
}

Anyone has any advise if this is the right way to go about it? I am very new to rust...

@cpu
Copy link
Member

cpu commented Jan 2, 2025

@Tomasz-Kluczkowski Did you read the discussion above? I recommend you change the code in question to use only constructors that take an explicit crypto provider of your choice, or figure out where in your dependency tree both the ring and aws-lc-rs features are activated and fix this so only one is used.

@Tomasz-Kluczkowski
Copy link

Tomasz-Kluczkowski commented Jan 2, 2025

@cpu

Yes I did, only I am extremely new to rust (1 month :) ) and getting a bit lost.
My question is, even if I explicitly instantiate the crypto provider before the object which needs it is instantiated, will I run into same issue - namely same problem as with calling install_default from multiple threads is not possible? Is creating an explicit provider without this issue?

I also checked the dependency tree and crates I use for my code do indeed bring ring in

$ cargo tree --edges features | grep 'ring'
│           │   │   │   ├── ring feature "default"
│           │   │   │   │   ├── ring v0.17.8
│           │   │   │   │   ├── ring feature "alloc"
│           │   │   │   │   │   └── ring v0.17.8 (*)
│           │   │   │   │   └── ring feature "dev_urandom_fallback"
│           │   │   │   │       └── ring v0.17.8 (*)
│           │   │   │   │   │   ├── ring v0.17.8 (*)
│           │   │   │   │   ├── ring feature "alloc" (*)
│           │   │           ├── yup-oauth2 feature "ring"
│           │   │           │   ├── hyper-rustls feature "ring"
│           │   │           │   │   └── rustls feature "ring"
│           │   │           │   │       └── rustls-webpki feature "ring"
│           │   │           │   └── rustls feature "ring" (*)

The aws_lc_rs is not in the dependency tree (also checked aws-lc-rs as both are mentioned in this thread..

@ctz
Copy link
Member

ctz commented Jan 2, 2025

I'd suggest just let _ = rustls::crypto::ring::default_provider().install_default(); -- the thread which "wins" will install the provider, the others will fail (safely) and ignore the error.

@Tomasz-Kluczkowski
Copy link

Tomasz-Kluczkowski commented Jan 2, 2025

The thing is, install_default called from multiple threads causes tests to fail. It can be called only once per process as per its own docs and I am assuming that cargo tests is running in single process, just multiple threads?

BTW I did replace my code with your suggestion @ctz , thank you, and it works, could you briefly explain to a rust noob why this works:

let _ = rustls::crypto::ring::default_provider().install_default();

and this was not:
rustls::crypto::ring::default_provider().install_default().unwrap();

was it because I called unwrap on it?

@ctz
Copy link
Member

ctz commented Jan 2, 2025

So the docs for that say "This can be called successfully at most once in any process execution." -- note successfully -- extra calls just return an error.

Your earlier code was calling unwrap() on this, which promotes the error to a panic. Instead my suggestion is to ignore the error, for which let _ = ... is a typical rust idiom.

@Tomasz-Kluczkowski
Copy link

thanks a lot @ctz

Tomasz-Kluczkowski added a commit to Tomasz-Kluczkowski/slack-gcal-sync that referenced this issue Jan 2, 2025
…er setup in tests

As per this thread: rustls/rustls#1938 I received an advice on how  to avoid using a lock object to assure `install_default()` is called only once per process.
Simply ignore the error caused by it by reading result into unused variable.
@robklg
Copy link

robklg commented Jan 19, 2025

@Tomasz-Kluczkowski I solved this issue using the hints in this thread, by overriding the default ring feature of yup-oauth2. Perhaps that works more neatly for you as well.

yup-oauth2 = { version = "11.0.0", default-features = false, features = ["hyper-rustls", "service-account", "aws-lc-rs"]}

@Tomasz-Kluczkowski
Copy link

@robklg thx, I tried but in my project this method broke other functionality. For now what I am doing, whilst not perfect will do.

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

No branches or pull requests

8 participants