diff --git a/MIGRATE.md b/MIGRATE.md index bebbf0bbe..f2df6b867 100644 --- a/MIGRATE.md +++ b/MIGRATE.md @@ -109,10 +109,10 @@ For each way the survey found: tables map to rind's own API, where `finish` takes `&mut self`. - **aws-lc-rs's API.** Port each call to rind's, using MIGRATING.md's tables. -rind panics on a CPU missing a feature it requires. Depend on `rind` and call -`rind::cpu::check()` at the start of each binary's `main`, exiting with its -error. A library leaves this to the binaries that use it, and says so in its -docs. +rind panics on a CPU missing a feature it requires. At the start of each +binary's `main`, refuse one by exiting with the error from an adapter's +`default_provider()`, rind-ring's `cpu::check()`, or `rind::cpu::check()`. +A library leaves this to the binaries that use it, and says so in its docs. Commit as you go, with messages in the project's style. diff --git a/MIGRATING.md b/MIGRATING.md index bc38de968..71a51e491 100644 --- a/MIGRATING.md +++ b/MIGRATING.md @@ -344,11 +344,11 @@ ring has none. Each `rind-*` crate stands in for a crate's aws-lc-rs or ring backend. rind panics on a CPU missing a feature it requires, so every adapter function -that builds a provider or ticketer refuses one with the adapter's own -`MissingFeature` instead, which displays rind's message. A static that the -upstream crate requires, such as `DEFAULT_PROVIDER`, cannot; nor can -rind-ring, whose signatures are ring's, or rind-rcgen's `KeyPair`, whose -errors are rcgen's. Call `rind::cpu::check()`, or rind-ring's `cpu::check()`, before using them. +that returns a provider or ticketer refuses one with the adapter's own +`MissingFeature` instead, which displays rind's message. rind-ring, whose +signatures are ring's, and rind-rcgen's `KeyPair`, whose errors are rcgen's, +cannot. Call rind-ring's `cpu::check()`, or `rind::cpu::check()` for +rind-rcgen, before using them. ### rind-ring @@ -407,8 +407,8 @@ those algorithms only with its `aws_lc_rs` feature. |---|---| | dimpl's `crypto::aws_lc_rs::default_provider()` | `rind_dimpl::default_provider()?` | | object_store's `aws`, `azure`, and `gcp` features | the `*-base` features, with `with_crypto_provider(rind_object_store::default_provider()?)` | -| jsonwebtoken's `crypto::aws_lc::DEFAULT_PROVIDER` | `rind_jsonwebtoken::DEFAULT_PROVIDER`, after `rind::cpu::check()?` | -| instant-acme's built-in provider | `Account::builder(http, &rind_instant_acme::DEFAULT_PROVIDER)`, after `rind::cpu::check()?` | +| jsonwebtoken's `crypto::aws_lc::DEFAULT_PROVIDER` | `rind_jsonwebtoken::default_provider()?` | +| instant-acme's built-in provider | `Account::builder(http, rind_instant_acme::default_provider()?)` | ## Crates with their own crypto backend diff --git a/quest/m1/README.md b/quest/m1/README.md index dc3e9e312..53800c614 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -12,5 +12,4 @@ Bun's fastest asymmetric operations run on rind, ahead of Bun writing its own. - [The launch post can say what building rind cost in AI tokens, time, and money](/quest/m1/ai-usage.md) - tokens, agent and maintainer hours, and API-price cost, before the post - [rind's launch blog post is published](/quest/m1/launch-post.md) - the Bun PR waits on it - [The bench report has a quiet Arrow Lake run and kixtop's build cost](/quest/m1/bench-apple-m4.md) - a fresh desktop column and M4 build costs before the launch post -- [rind-jsonwebtoken and rind-instant-acme check the CPU themselves](/quest/m1/adapter-cpu-check.md) - `default_provider()` like the other adapters, before 11.0.0 publishes - [rind covers MoQ](/quest/m1/moq/README.md) - the primitives, CPU check, armv7 backend, and `rind-*` adapters MoQ needs, verified and released diff --git a/quest/m1/adapter-cpu-check.md b/quest/m1/adapter-cpu-check.md deleted file mode 100644 index fd0bfdbf8..000000000 --- a/quest/m1/adapter-cpu-check.md +++ /dev/null @@ -1,13 +0,0 @@ -# [XS] rind-jsonwebtoken and rind-instant-acme check the CPU themselves - -## Goal - -Every adapter refuses a CPU missing a feature rind requires through its own API, returning its own `MissingFeature`, so no adapter's user depends on `rind` directly just to call `rind::cpu::check()`. - -## Plan - -Decided with the maintainer on 2026-11-07. Since [moq-dev/rind#420](https://github.com/moq-dev/rind/pull/420), rind-rustls, rind-dimpl, and rind-object-store refuse such a CPU in `default_provider()`, returning their own `MissingFeature`. rind-jsonwebtoken and rind-instant-acme expose a `DEFAULT_PROVIDER` static instead, and their docs tell callers to run `rind::cpu::check()` first, which needs `rind` as a direct dependency. - -- Replace each public `DEFAULT_PROVIDER` with `default_provider() -> Result<&'static CryptoProvider, MissingFeature>`, matching the other adapters' name and error. Keep one way to do it: the static becomes private. If an upstream API needs something other than `&'static`, say so in the PR. -- Release this with rind-jsonwebtoken 11.0.0, before the open release PR publishes it, so the break rides the major bump the adapter-version change already takes. rind-instant-acme is unpublished. -- Update the READMEs, crate docs, MIGRATING.md, and MIGRATE.md examples. diff --git a/rind-bench/benches/jsonwebtoken.rs b/rind-bench/benches/jsonwebtoken.rs index dde477512..014971ee5 100644 --- a/rind-bench/benches/jsonwebtoken.rs +++ b/rind-bench/benches/jsonwebtoken.rs @@ -15,10 +15,12 @@ use criterion::{Criterion, Throughput, criterion_group, criterion_main}; use jsonwebtoken::crypto::{CryptoProvider, aws_lc}; use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey}; -const PROVIDERS: [(&str, &CryptoProvider); 2] = [ - ("aws-lc-rs", &aws_lc::DEFAULT_PROVIDER), - ("rind", &rind_jsonwebtoken::DEFAULT_PROVIDER), -]; +fn providers() -> [(&'static str, &'static CryptoProvider); 2] { + [ + ("aws-lc-rs", &aws_lc::DEFAULT_PROVIDER), + ("rind", rind_jsonwebtoken::default_provider().unwrap()), + ] +} // The header and claims of a typical token, as jsonwebtoken signs them. const MESSAGE: &[u8] = b"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb290IjoiZGVtbyIsInB1dCI6WyIiXSwiZ2V0IjpbIiJdLCJleHAiOjE3OTI4MTYwMDAsImlhdCI6MTc2MTI4MDAwMH0"; @@ -81,7 +83,7 @@ fn sign(c: &mut Criterion) { let mut group = c.benchmark_group(format!("jwt-{algorithm:?}-sign").to_lowercase()); group.throughput(Throughput::Elements(1)); - for (name, provider) in PROVIDERS { + for (name, provider) in providers() { group.bench_function(format!("{name}/token"), |b| { b.iter(|| { let signer = (provider.signer_factory)(&algorithm, &encoding).unwrap(); @@ -105,7 +107,7 @@ fn verify(c: &mut Criterion) { .try_sign(MESSAGE) .unwrap(); - for (name, provider) in PROVIDERS { + for (name, provider) in providers() { group.bench_function(format!("{name}/token"), |b| { b.iter(|| { let verifier = (provider.verifier_factory)(&algorithm, &decoding).unwrap(); diff --git a/rind-instant-acme/README.md b/rind-instant-acme/README.md index 504f6263a..63865e94a 100644 --- a/rind-instant-acme/README.md +++ b/rind-instant-acme/README.md @@ -11,13 +11,13 @@ use std::sync::Arc; use instant_acme::{Account, DefaultClient}; -// Refuses a CPU missing a feature rind requires, which DEFAULT_PROVIDER cannot. let http = DefaultClient::new(Arc::new(rind_rustls::default_provider()?))?; -let builder = Account::builder(Box::new(http), &rind_instant_acme::DEFAULT_PROVIDER)?; +let builder = Account::builder(Box::new(http), rind_instant_acme::default_provider()?)?; ``` -rind panics on a CPU missing a feature it requires, so call `rind::cpu::check()` -before using `DEFAULT_PROVIDER`, as `rind_rustls::default_provider()` does. +rind panics on a CPU missing a feature it requires, so `default_provider()` +checks first and returns an error naming it instead, as +`rind_rustls::default_provider()` does. It signs account requests with ECDSA P-256 (ES256) keys, the same PKCS#8 keys instant-acme's aws-lc-rs and ring providers make, so stored credentials keep working. It signs External Account Binding with HMAC-SHA256 and hashes JWK thumbprints and challenge digests with SHA-256. diff --git a/rind-instant-acme/src/lib.rs b/rind-instant-acme/src/lib.rs index 1957aaae6..73420b205 100644 --- a/rind-instant-acme/src/lib.rs +++ b/rind-instant-acme/src/lib.rs @@ -13,13 +13,14 @@ //! use instant_acme::{Account, DefaultClient}; //! //! # fn main() -> Result<(), Box> { -//! // Refuses a CPU missing a feature rind requires, which DEFAULT_PROVIDER cannot. //! let http = DefaultClient::new(Arc::new(rind_rustls::default_provider()?))?; -//! let builder = Account::builder(Box::new(http), &rind_instant_acme::DEFAULT_PROVIDER)?; +//! let builder = Account::builder(Box::new(http), rind_instant_acme::default_provider()?)?; //! # Ok(()) //! # } //! ``` +use core::fmt; + use instant_acme::{ CryptoProvider, EcCurve, Error, HmacKey, HmacKeyProvider, Jwk, JwkThumbFields, Sha256, SigningAlgorithm, SigningKey, SigningKeyProvider, @@ -28,14 +29,30 @@ use rind::signature::{EcdsaKeyPair, EcdsaSigningAlgorithm, PublicKey, sign}; use rind::{digest, hmac}; use rustls_pki_types::PrivatePkcs8KeyDer; -/// An instant-acme [`CryptoProvider`] that signs with ECDSA P-256 account keys and HS256 EAB keys on rind. +/// A CPU feature rind requires that this CPU lacks. +#[derive(Debug)] +pub struct MissingFeature(rind::cpu::MissingFeature); + +impl fmt::Display for MissingFeature { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl std::error::Error for MissingFeature {} + +/// Returns an instant-acme [`CryptoProvider`] that signs with ECDSA P-256 +/// account keys and HS256 EAB keys on rind, or the CPU feature rind requires +/// that this CPU lacks. /// /// It loads and generates the same PKCS#8 account keys as instant-acme's /// aws-lc-rs and ring providers, so stored credentials move between them. -/// -/// rind panics on a CPU missing a feature it requires, so call -/// [`rind::cpu::check`] first, as `rind_rustls::default_provider()` does. -pub static DEFAULT_PROVIDER: CryptoProvider = CryptoProvider { +pub fn default_provider() -> Result<&'static CryptoProvider, MissingFeature> { + rind::cpu::check().map_err(MissingFeature)?; + Ok(&PROVIDER) +} + +static PROVIDER: CryptoProvider = CryptoProvider { key_provider: &P256KeyProvider, sha256: &RindSha256, hmac: &HmacSha256Provider, diff --git a/rind-instant-acme/tests/ctgrind.rs b/rind-instant-acme/tests/ctgrind.rs index 28afa688c..0e2e09ead 100644 --- a/rind-instant-acme/tests/ctgrind.rs +++ b/rind-instant-acme/tests/ctgrind.rs @@ -10,7 +10,6 @@ use crabgrind::memcheck::{self, MemState}; use crabgrind::valgrind::{self, RunningMode}; use instant_acme::{CryptoProvider, JwkThumbFields}; use rind::signature::{PublicKey, verify}; -use rind_instant_acme::DEFAULT_PROVIDER; /// Marks `value` secret: memcheck flags any branch or index that depends on it. fn secret(value: &T) { @@ -30,8 +29,9 @@ fn mark(value: &T, state: MemState) { #[test] fn account_key() { - let (generated, pkcs8) = DEFAULT_PROVIDER.key_provider.generate_key().unwrap(); - let loaded = DEFAULT_PROVIDER.key_provider.load_key(pkcs8).unwrap(); + let provider = rind_instant_acme::default_provider().unwrap(); + let (generated, pkcs8) = provider.key_provider.generate_key().unwrap(); + let loaded = provider.key_provider.load_key(pkcs8).unwrap(); let message = b"eyJhbGciOiJFUzI1NiJ9.eyJyaW5kIjp0cnVlfQ"; for key in [generated, loaded] { @@ -53,6 +53,7 @@ fn account_key() { #[test] fn external_account_binding() { + let provider = rind_instant_acme::default_provider().unwrap(); let key = [0x42u8; 32]; let message = b"eyJhbGciOiJIUzI1NiJ9.eyJyaW5kIjp0cnVlfQ"; let expected = CryptoProvider::aws_lc_rs() @@ -61,7 +62,7 @@ fn external_account_binding() { .sign(message); secret(&key); - let tag = DEFAULT_PROVIDER.hmac.load_key(&key).sign(message); + let tag = provider.hmac.load_key(&key).sign(message); public(&tag[..]); assert_eq!(tag, expected); } diff --git a/rind-instant-acme/tests/differential.rs b/rind-instant-acme/tests/differential.rs index 664755ba8..f70bf988b 100644 --- a/rind-instant-acme/tests/differential.rs +++ b/rind-instant-acme/tests/differential.rs @@ -5,7 +5,9 @@ use instant_acme::{CryptoProvider, Error, JwkThumbFields, SigningKey}; use rind::signature::{EcdsaKeyPair, Ed25519KeyPair, sign, verify}; use rustls_pki_types::PrivatePkcs8KeyDer; -const RIND: &CryptoProvider = &rind_instant_acme::DEFAULT_PROVIDER; +fn rind() -> &'static CryptoProvider { + rind_instant_acme::default_provider().unwrap() +} fn aws_lc() -> &'static CryptoProvider { CryptoProvider::aws_lc_rs() @@ -51,11 +53,11 @@ fn load(provider: &CryptoProvider, pkcs8: &[u8]) -> Result, #[test] fn generated_keys_load_in_both_providers() { - for (generator, name) in [(RIND, "rind"), (aws_lc(), "aws-lc-rs")] { + for (generator, name) in [(rind(), "rind"), (aws_lc(), "aws-lc-rs")] { let (key, pkcs8) = generator.key_provider.generate_key().unwrap(); let pkcs8 = pkcs8.secret_pkcs8_der(); - let ours = load(RIND, pkcs8).unwrap_or_else(|e| panic!("{name} key in rind: {e}")); + let ours = load(rind(), pkcs8).unwrap_or_else(|e| panic!("{name} key in rind: {e}")); let theirs = load(aws_lc(), pkcs8).unwrap_or_else(|e| panic!("{name} key in aws-lc: {e}")); assert_eq!(jwk(&*key), jwk(&*ours), "{name}"); @@ -66,7 +68,7 @@ fn generated_keys_load_in_both_providers() { #[test] fn signatures_verify_across_providers() { - let (key, pkcs8) = RIND.key_provider.generate_key().unwrap(); + let (key, pkcs8) = rind().key_provider.generate_key().unwrap(); let theirs = load(aws_lc(), pkcs8.secret_pkcs8_der()).unwrap(); let point = point(&*key); let message = b"eyJhbGciOiJFUzI1NiJ9.eyJyaW5kIjp0cnVlfQ"; @@ -88,7 +90,7 @@ fn signatures_verify_across_providers() { #[test] fn malformed_keys_are_rejected_by_both_providers() { - let (_, p256) = RIND.key_provider.generate_key().unwrap(); + let (_, p256) = rind().key_provider.generate_key().unwrap(); let p256 = p256.secret_pkcs8_der(); let p384 = EcdsaKeyPair::generate(&sign::ECDSA_P384_SHA384_FIXED) .unwrap() @@ -116,7 +118,7 @@ fn malformed_keys_are_rejected_by_both_providers() { "aws-lc-rs accepted {what}" ); assert!( - matches!(load(RIND, pkcs8), Err(Error::KeyRejected)), + matches!(load(rind(), pkcs8), Err(Error::KeyRejected)), "rind accepted {what}" ); } @@ -129,7 +131,7 @@ fn sha256_matches() { for len in 0..300 { let data = rng.bytes(len); assert_eq!( - RIND.sha256.hash(&data), + rind().sha256.hash(&data), aws_lc().sha256.hash(&data), "{len}" ); @@ -142,7 +144,7 @@ fn hmac_matches() { // Keys either side of the 64-byte block, past which HMAC hashes the key. for key_len in [0, 1, 16, 32, 63, 64, 65, 128, 200] { let key = rng.bytes(key_len); - let ours = RIND.hmac.load_key(&key); + let ours = rind().hmac.load_key(&key); let theirs = aws_lc().hmac.load_key(&key); assert_eq!( serde_json::to_string(&ours.algorithm()).unwrap(), diff --git a/rind-instant-acme/tests/pebble.rs b/rind-instant-acme/tests/pebble.rs index 4f6f9286f..98e40559d 100644 --- a/rind-instant-acme/tests/pebble.rs +++ b/rind-instant-acme/tests/pebble.rs @@ -19,7 +19,6 @@ use instant_acme::{ OrderStatus, RetryPolicy, }; use rcgen::{CertificateParams, PKCS_ECDSA_P256_SHA256, PublicKeyData, SerialNumber}; -use rind_instant_acme::DEFAULT_PROVIDER; use rustls_pki_types::CertificateDer; use rustls_pki_types::pem::PemObject; use tokio::io::{AsyncReadExt, AsyncWriteExt}; @@ -48,21 +47,23 @@ async fn issue_certificate() { Box::new(DefaultClient::with_pem_root(&root, provider).unwrap()) }; + let acme = rind_instant_acme::default_provider().unwrap(); + // Creating the account generates its key and signs the EAB with HS256. - let eab = ExternalAccountKey::new(EAB_KID.to_string(), DEFAULT_PROVIDER.hmac.load_key(EAB_KEY)); + let eab = ExternalAccountKey::new(EAB_KID.to_string(), acme.hmac.load_key(EAB_KEY)); let new_account = NewAccount { contact: &[], terms_of_service_agreed: true, only_return_existing: false, }; - let (_, credentials) = Account::builder(http(), &DEFAULT_PROVIDER) + let (_, credentials) = Account::builder(http(), acme) .unwrap() .create(&new_account, directory, Some(&eab)) .await .unwrap(); // Ordering from stored credentials loads the PKCS#8 key back. - let account = Account::builder(http(), &DEFAULT_PROVIDER) + let account = Account::builder(http(), acme) .unwrap() .from_credentials(credentials) .await diff --git a/rind-jsonwebtoken/README.md b/rind-jsonwebtoken/README.md index df197f9bb..e058e789d 100644 --- a/rind-jsonwebtoken/README.md +++ b/rind-jsonwebtoken/README.md @@ -9,12 +9,11 @@ This crate provides an integration between [jsonwebtoken](https://github.com/Kea Use it like: ```rust -// rind panics on a CPU missing a feature it requires, so refuse it first. -rind::cpu::check()?; -rind_jsonwebtoken::DEFAULT_PROVIDER.install_default().unwrap(); +rind_jsonwebtoken::default_provider()?.install_default().unwrap(); ``` And then use jsonwebtoken as normal. +rind panics on a CPU missing a feature it requires, so `default_provider()` checks first and returns an error naming it instead. It signs and verifies HS256/384/512, ES256/384, RS256/384/512, PS256/384/512, and EdDSA, and implements the key utilities jsonwebtoken needs for JWKs. License: Apache-2.0 OR ISC OR MIT-0 diff --git a/rind-jsonwebtoken/src/lib.rs b/rind-jsonwebtoken/src/lib.rs index 02680b7d4..6a5d4b245 100644 --- a/rind-jsonwebtoken/src/lib.rs +++ b/rind-jsonwebtoken/src/lib.rs @@ -6,10 +6,8 @@ //! Use it like: //! //! ```rust -//! # fn main() -> Result<(), rind::cpu::MissingFeature> { -//! // rind panics on a CPU missing a feature it requires, so refuse it first. -//! rind::cpu::check()?; -//! rind_jsonwebtoken::DEFAULT_PROVIDER +//! # fn main() -> Result<(), rind_jsonwebtoken::MissingFeature> { +//! rind_jsonwebtoken::default_provider()? //! .install_default() //! .unwrap(); //! # Ok(()) @@ -18,6 +16,8 @@ //! //! And then use jsonwebtoken as normal. +use core::fmt; + use jsonwebtoken::crypto::{CryptoProvider, JwtSigner, JwtVerifier, KeyUtils}; use jsonwebtoken::errors::{Error, ErrorKind, Result}; use jsonwebtoken::jwk::{EllipticCurve, ThumbprintHash}; @@ -31,11 +31,26 @@ use rind::signature::{ }; use rind::{digest, hmac}; -/// A jsonwebtoken [`CryptoProvider`] that signs and verifies every algorithm with rind. -/// -/// rind panics on a CPU missing a feature it requires, so call -/// [`rind::cpu::check`] first. -pub static DEFAULT_PROVIDER: CryptoProvider = CryptoProvider { +/// A CPU feature rind requires that this CPU lacks. +#[derive(Debug)] +pub struct MissingFeature(rind::cpu::MissingFeature); + +impl fmt::Display for MissingFeature { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl std::error::Error for MissingFeature {} + +/// Returns a jsonwebtoken [`CryptoProvider`] that signs and verifies every +/// algorithm with rind, or the CPU feature rind requires that this CPU lacks. +pub fn default_provider() -> std::result::Result<&'static CryptoProvider, MissingFeature> { + rind::cpu::check().map_err(MissingFeature)?; + Ok(&PROVIDER) +} + +static PROVIDER: CryptoProvider = CryptoProvider { signer_factory: new_signer, verifier_factory: new_verifier, key_utils: KeyUtils { diff --git a/rind-jsonwebtoken/tests/ctgrind.rs b/rind-jsonwebtoken/tests/ctgrind.rs index 48104f3f6..34f46435d 100644 --- a/rind-jsonwebtoken/tests/ctgrind.rs +++ b/rind-jsonwebtoken/tests/ctgrind.rs @@ -12,7 +12,6 @@ use crabgrind::memcheck::{self, MemState}; use crabgrind::valgrind::{self, RunningMode}; use jsonwebtoken::Algorithm; use jsonwebtoken::jwk::EllipticCurve; -use rind_jsonwebtoken::DEFAULT_PROVIDER; const MESSAGE: &[u8] = b"eyJhbGciOiJub25lIn0.eyJzdWIiOiJyaW5kIn0"; @@ -34,19 +33,20 @@ fn mark(value: &T, state: MemState) { #[test] fn sign_and_verify() { + let provider = rind_jsonwebtoken::default_provider().unwrap(); for key in common::all() { if common::HMAC.contains(&key.algorithm) { secret(key.encoding.as_bytes()); secret(key.decoding.try_get_as_bytes().unwrap()); } - let signature = (DEFAULT_PROVIDER.signer_factory)(&key.algorithm, &key.encoding) + let signature = (provider.signer_factory)(&key.algorithm, &key.encoding) .unwrap() .try_sign(MESSAGE) .unwrap(); public(&signature[..]); - (DEFAULT_PROVIDER.verifier_factory)(&key.algorithm, &key.decoding) + (provider.verifier_factory)(&key.algorithm, &key.decoding) .unwrap() .verify(MESSAGE, &signature) .unwrap_or_else(|e| panic!("{}: {e}", key.label())); @@ -55,7 +55,8 @@ fn sign_and_verify() { #[test] fn public_components() { - let utils = &DEFAULT_PROVIDER.key_utils; + let provider = rind_jsonwebtoken::default_provider().unwrap(); + let utils = &provider.key_utils; for key in common::all() { let der = key.encoding.as_bytes(); match key.algorithm { diff --git a/rind-jsonwebtoken/tests/install.rs b/rind-jsonwebtoken/tests/install.rs index f6bf0fd72..0f7a9aafe 100644 --- a/rind-jsonwebtoken/tests/install.rs +++ b/rind-jsonwebtoken/tests/install.rs @@ -9,7 +9,8 @@ use serde_json::{Value, json}; #[test] fn tokens_round_trip_through_jwks() { - rind_jsonwebtoken::DEFAULT_PROVIDER + rind_jsonwebtoken::default_provider() + .unwrap() .install_default() .unwrap(); diff --git a/rind-jsonwebtoken/tests/interop.rs b/rind-jsonwebtoken/tests/interop.rs index 08e40b4b9..bdf81092a 100644 --- a/rind-jsonwebtoken/tests/interop.rs +++ b/rind-jsonwebtoken/tests/interop.rs @@ -9,9 +9,12 @@ use jsonwebtoken::errors::ErrorKind; use jsonwebtoken::jwk::{EllipticCurve, ThumbprintHash}; use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey}; -const RIND: &CryptoProvider = &rind_jsonwebtoken::DEFAULT_PROVIDER; const AWS_LC: &CryptoProvider = &aws_lc::DEFAULT_PROVIDER; +fn rind() -> &'static CryptoProvider { + rind_jsonwebtoken::default_provider().unwrap() +} + const MESSAGE: &[u8] = b"eyJhbGciOiJub25lIn0.eyJzdWIiOiJyaW5kIn0"; fn sign(provider: &CryptoProvider, key: &Key, message: &[u8]) -> Vec { @@ -32,9 +35,9 @@ fn verifies(provider: &CryptoProvider, key: &Key, message: &[u8], signature: &[u fn signatures_verify_across_providers() { for key in common::all() { for (signer, verifier, direction) in [ - (RIND, AWS_LC, "rind to aws-lc-rs"), - (AWS_LC, RIND, "aws-lc-rs to rind"), - (RIND, RIND, "rind to rind"), + (rind(), AWS_LC, "rind to aws-lc-rs"), + (AWS_LC, rind(), "aws-lc-rs to rind"), + (rind(), rind(), "rind to rind"), ] { let label = format!("{} ({direction})", key.label()); let signature = sign(signer, &key, MESSAGE); @@ -47,7 +50,7 @@ fn signatures_verify_across_providers() { #[test] fn altered_signatures_fail_on_both_providers() { for key in common::all() { - let signature = sign(RIND, &key, MESSAGE); + let signature = sign(rind(), &key, MESSAGE); let mut flipped = signature.clone(); *flipped.last_mut().unwrap() ^= 1; @@ -64,7 +67,7 @@ fn altered_signatures_fail_on_both_providers() { (&signature[..signature.len() - 1], "last byte removed"), (&[][..], "empty"), ] { - for (provider, name) in [(RIND, "rind"), (AWS_LC, "aws-lc-rs")] { + for (provider, name) in [(rind(), "rind"), (AWS_LC, "aws-lc-rs")] { assert!( !verifies(provider, &key, MESSAGE, altered), "{} accepted with a {how} by {name}", @@ -83,14 +86,14 @@ fn key_of_another_family_is_refused() { .iter() .filter(|key| key.encoding.family() != algorithm.family()) { - let signer = (RIND.signer_factory)(&algorithm, &key.encoding); + let signer = (rind().signer_factory)(&algorithm, &key.encoding); assert_eq!( signer.err().map(|e| e.into_kind()), Some(ErrorKind::InvalidKeyFormat), "{algorithm:?} signer with {}", key.label() ); - let verifier = (RIND.verifier_factory)(&algorithm, &key.decoding); + let verifier = (rind().verifier_factory)(&algorithm, &key.decoding); assert_eq!( verifier.err().map(|e| e.into_kind()), Some(ErrorKind::InvalidKeyFormat), @@ -119,7 +122,7 @@ fn malformed_keys_are_errors() { ]; for (algorithm, key) in signers { assert!( - (RIND.signer_factory)(&algorithm, &key).is_err(), + (rind().signer_factory)(&algorithm, &key).is_err(), "{algorithm:?}" ); } @@ -147,7 +150,7 @@ fn malformed_keys_are_errors() { ]; for (algorithm, key) in verifiers { assert!( - (RIND.verifier_factory)(&algorithm, &key).is_err(), + (rind().verifier_factory)(&algorithm, &key).is_err(), "{algorithm:?}" ); } @@ -165,11 +168,11 @@ fn common_point(algorithm: Algorithm) -> DecodingKey { fn key_utils_match_aws_lc() { let (private, public) = common::rsa_key(); assert_eq!( - (RIND.key_utils.rsa_pub_components_from_private_key)(private).unwrap(), + (rind().key_utils.rsa_pub_components_from_private_key)(private).unwrap(), (AWS_LC.key_utils.rsa_pub_components_from_private_key)(private).unwrap(), ); assert_eq!( - (RIND.key_utils.rsa_pub_components_from_public_key)(public).unwrap(), + (rind().key_utils.rsa_pub_components_from_public_key)(public).unwrap(), (AWS_LC.key_utils.rsa_pub_components_from_public_key)(public).unwrap(), ); @@ -177,13 +180,13 @@ fn key_utils_match_aws_lc() { let der = key.encoding.as_bytes(); match key.algorithm { Algorithm::ES256 | Algorithm::ES384 => assert_eq!( - (RIND.key_utils.ec_pub_components_from_private_key)(der, key.algorithm).unwrap(), + (rind().key_utils.ec_pub_components_from_private_key)(der, key.algorithm).unwrap(), (AWS_LC.key_utils.ec_pub_components_from_private_key)(der, key.algorithm).unwrap(), "{}", key.label() ), Algorithm::EdDSA => assert_eq!( - (RIND.key_utils.ed_pub_components_from_private_key)(der, &EllipticCurve::Ed25519) + (rind().key_utils.ed_pub_components_from_private_key)(der, &EllipticCurve::Ed25519) .unwrap(), (AWS_LC.key_utils.ed_pub_components_from_private_key)(der, &EllipticCurve::Ed25519) .unwrap(), @@ -200,7 +203,7 @@ fn key_utils_match_aws_lc() { ThumbprintHash::SHA512, ] { assert_eq!( - (RIND.key_utils.compute_digest)(MESSAGE, hash.clone()).unwrap(), + (rind().key_utils.compute_digest)(MESSAGE, hash.clone()).unwrap(), (AWS_LC.key_utils.compute_digest)(MESSAGE, hash).unwrap(), ); }