Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
run: cargo install wasm-pack

- name: Run tests default features
run: wasm-pack test --node --features rust_crypto,getrandom/js
run: wasm-pack test --node --features rust_crypto,getrandom/wasm_js

- name: Run tests no features
run: wasm-pack test --node --no-default-features --features rust_crypto,getrandom/js
run: wasm-pack test --node --no-default-features --features rust_crypto,getrandom/wasm_js
27 changes: 15 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ features = ["rust_crypto"]
base64 = "0.22"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0"
signature = { version = "2.2.0", features = ["std"] }
signature = { version = "3.0.0", features = ["alloc"] }

# For PEM decoding
pem = { version = "3", optional = true }
Expand All @@ -36,26 +36,28 @@ simple_asn1 = { version = "0.6", optional = true }
aws-lc-rs = { version = "1.15.0", optional = true }

# "rust_crypto" feature
ed25519-dalek = { version = "2.1.1", optional = true, features = ["pkcs8"] }
hmac = { version = "0.12.1", optional = true, features = ["reset"] }
p256 = { version = "0.13.2", optional = true, features = ["ecdsa"] }
p384 = { version = "0.13.0", optional = true, features = ["ecdsa"] }
rand = { version = "0.8.5", optional = true, features = [
ed25519-dalek = { version = "3.0.0", optional = true, features = ["pkcs8"] }
hmac = { version = "0.13.0", optional = true }
p256 = { version = "0.14", optional = true, features = ["ecdsa"] }
p384 = { version = "0.14", optional = true, features = ["ecdsa"] }
p521 = { version = "0.14", optional = true, features = ["ecdsa", "pkcs8"] }
rand = { version = "0.10.0", optional = true, features = [
"std",
"std_rng",
"thread_rng",
], default-features = false }
rsa = { version = "0.9.6", optional = true }
sha2 = { version = "0.10.7", optional = true, features = ["oid"] }
rsa = { version = "0.10.0-rc.18", optional = true }
sha2 = { version = "0.11", optional = true, features = ["oid"] }
zeroize = { version = "1.8.2", features = ["derive"] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
js-sys = "0.3"
getrandom = "0.2"
getrandom = { version = "0.4", features = ["wasm_js"] }

[dev-dependencies]
wasm-bindgen-test = "0.3.1"
ed25519-dalek = { version = "2.1.1", features = ["pkcs8", "rand_core"] }
rand = { version = "0.8.5", features = ["std"], default-features = false }
rand_core = "0.6.4"
ed25519-dalek = { version = "3.0.0", features = ["pkcs8", "rand_core", "alloc"] }
rand = { version = "0.10.0", features = ["std", "std_rng", "thread_rng"], default-features = false }
[target.'cfg(not(all(target_arch = "wasm32", not(any(target_os = "emscripten", target_os = "wasi")))))'.dev-dependencies]
# For the custom time example
time = "0.3"
Expand All @@ -74,6 +76,7 @@ rust_crypto = [
"dep:hmac",
"dep:p256",
"dep:p384",
"dep:p521",
"dep:rand",
"dep:rsa",
"dep:sha2",
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ This library currently supports the following:
- PS512
- ES256
- ES384
- ES512
- EdDSA


Expand Down
15 changes: 4 additions & 11 deletions examples/ed25519.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use ed25519_dalek::SigningKey;
use ed25519_dalek::pkcs8::EncodePrivateKey;
use rand_core::OsRng;
use serde::{Deserialize, Serialize};

use jsonwebtoken::{
Expand All @@ -14,12 +13,9 @@ pub struct Claims {
}

fn main() {
let signing_key = SigningKey::generate(&mut OsRng);
let signing_key = SigningKey::generate(&mut rand::rng());
let pkcs8 = signing_key.to_pkcs8_der().unwrap();
let pkcs8 = pkcs8.as_bytes();
// The `to_pkcs8_der` includes the public key, the first 48 bits are the private key.
let pkcs8 = &pkcs8[..48];
let encoding_key = EncodingKey::from_ed_der(pkcs8);
let encoding_key = EncodingKey::from_ed_der(pkcs8.as_bytes());

let verifying_key = signing_key.verifying_key();
let public_key = verifying_key.as_bytes();
Expand All @@ -45,12 +41,9 @@ mod tests {

impl Jot {
fn new() -> Jot {
let signing_key = SigningKey::generate(&mut OsRng);
let signing_key = SigningKey::generate(&mut rand::rng());
let pkcs8 = signing_key.to_pkcs8_der().unwrap();
let pkcs8 = pkcs8.as_bytes();
// The `to_pkcs8_der` includes the public key, the first 48 bits are the private key.
let pkcs8 = &pkcs8[..48];
let encoding_key = EncodingKey::from_ed_der(&pkcs8);
let encoding_key = EncodingKey::from_ed_der(pkcs8.as_bytes());

let verifying_key = signing_key.verifying_key();
let public_key = verifying_key.as_bytes();
Expand Down
7 changes: 5 additions & 2 deletions src/algorithms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl AlgorithmFamily {
Algorithm::PS384,
Algorithm::PS512,
],
Self::Ec => &[Algorithm::ES256, Algorithm::ES384],
Self::Ec => &[Algorithm::ES256, Algorithm::ES384, Algorithm::ES512],
Self::Ed => &[Algorithm::EdDSA],
}
}
Expand All @@ -53,6 +53,8 @@ pub enum Algorithm {
ES256,
/// ECDSA using SHA-384
ES384,
/// ECDSA using SHA-512
ES512,

/// RSASSA-PKCS1-v1_5 using SHA-256
RS256,
Expand Down Expand Up @@ -81,6 +83,7 @@ impl FromStr for Algorithm {
"HS512" => Ok(Algorithm::HS512),
"ES256" => Ok(Algorithm::ES256),
"ES384" => Ok(Algorithm::ES384),
"ES512" => Ok(Algorithm::ES512),
"RS256" => Ok(Algorithm::RS256),
"RS384" => Ok(Algorithm::RS384),
"PS256" => Ok(Algorithm::PS256),
Expand All @@ -104,7 +107,7 @@ impl Algorithm {
| Algorithm::PS256
| Algorithm::PS384
| Algorithm::PS512 => AlgorithmFamily::Rsa,
Algorithm::ES256 | Algorithm::ES384 => AlgorithmFamily::Ec,
Algorithm::ES256 | Algorithm::ES384 | Algorithm::ES512 => AlgorithmFamily::Ec,
Algorithm::EdDSA => AlgorithmFamily::Ed,
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/crypto/aws_lc/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use crate::{Algorithm, DecodingKey, EncodingKey};
use aws_lc_rs::rand::SystemRandom;
use aws_lc_rs::signature::{
ECDSA_P256_SHA256_FIXED, ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED,
ECDSA_P384_SHA384_FIXED_SIGNING, EcdsaKeyPair, VerificationAlgorithm,
ECDSA_P384_SHA384_FIXED_SIGNING, ECDSA_P521_SHA512_FIXED, ECDSA_P521_SHA512_FIXED_SIGNING,
EcdsaKeyPair, VerificationAlgorithm,
};
use signature::{Error, Signer, Verifier};

Expand Down Expand Up @@ -85,3 +86,6 @@ define_ecdsa_verifier!(Es256Verifier, Algorithm::ES256, ECDSA_P256_SHA256_FIXED)

define_ecdsa_signer!(Es384Signer, Algorithm::ES384, &ECDSA_P384_SHA384_FIXED_SIGNING);
define_ecdsa_verifier!(Es384Verifier, Algorithm::ES384, ECDSA_P384_SHA384_FIXED);

define_ecdsa_signer!(Es512Signer, Algorithm::ES512, &ECDSA_P521_SHA512_FIXED_SIGNING);
define_ecdsa_verifier!(Es512Verifier, Algorithm::ES512, ECDSA_P521_SHA512_FIXED);
5 changes: 4 additions & 1 deletion src/crypto/aws_lc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use aws_lc_rs::{
digest,
signature::{
self as aws_sig, ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED_SIGNING,
EcdsaKeyPair, Ed25519KeyPair, KeyPair,
ECDSA_P521_SHA512_FIXED_SIGNING, EcdsaKeyPair, Ed25519KeyPair, KeyPair,
},
};

Expand Down Expand Up @@ -41,6 +41,7 @@ fn ec_components_from_private_key(
let (signing_alg, curve, pub_elem_bytes) = match alg {
Algorithm::ES256 => (&ECDSA_P256_SHA256_FIXED_SIGNING, EllipticCurve::P256, 32),
Algorithm::ES384 => (&ECDSA_P384_SHA384_FIXED_SIGNING, EllipticCurve::P384, 48),
Algorithm::ES512 => (&ECDSA_P521_SHA512_FIXED_SIGNING, EllipticCurve::P521, 66),
_ => return Err(ErrorKind::InvalidEcdsaKey.into()),
};

Expand Down Expand Up @@ -86,6 +87,7 @@ fn new_signer(algorithm: &Algorithm, key: &EncodingKey) -> Result<Box<dyn JwtSig
Algorithm::HS512 => Box::new(hmac::Hs512Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::ES256 => Box::new(ecdsa::Es256Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::ES384 => Box::new(ecdsa::Es384Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::ES512 => Box::new(ecdsa::Es512Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::RS256 => Box::new(rsa::Rsa256Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::RS384 => Box::new(rsa::Rsa384Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::RS512 => Box::new(rsa::Rsa512Signer::new(key)?) as Box<dyn JwtSigner>,
Expand All @@ -108,6 +110,7 @@ fn new_verifier(
Algorithm::HS512 => Box::new(hmac::Hs512Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::ES256 => Box::new(ecdsa::Es256Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::ES384 => Box::new(ecdsa::Es384Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::ES512 => Box::new(ecdsa::Es512Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::RS256 => Box::new(rsa::Rsa256Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::RS384 => Box::new(rsa::Rsa384Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::RS512 => Box::new(rsa::Rsa512Verifier::new(key)?) as Box<dyn JwtVerifier>,
Expand Down
13 changes: 9 additions & 4 deletions src/crypto/rust_crypto/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ use p256::pkcs8::DecodePrivateKey;
use p384::ecdsa::{
Signature as Signature384, SigningKey as SigningKey384, VerifyingKey as VerifyingKey384,
};
use p521::ecdsa::{
Signature as Signature521, SigningKey as SigningKey521, VerifyingKey as VerifyingKey521,
};
use signature::{Error, Signer, Verifier};

macro_rules! define_ecdsa_signer {
($name:ident, $alg:expr, $signing_key:ty) => {
($name:ident, $alg:expr, $signing_key:ty, $signature:ty) => {
pub struct $name($signing_key);

impl $name {
Expand All @@ -33,7 +36,7 @@ macro_rules! define_ecdsa_signer {

impl Signer<Vec<u8>> for $name {
fn try_sign(&self, msg: &[u8]) -> std::result::Result<Vec<u8>, Error> {
let signature = self.0.sign_recoverable(msg).map_err(Error::from_source)?.0;
let signature: $signature = self.0.sign(msg);
Ok(signature.to_vec())
}
}
Expand Down Expand Up @@ -80,8 +83,10 @@ macro_rules! define_ecdsa_verifier {
};
}

define_ecdsa_signer!(Es256Signer, Algorithm::ES256, SigningKey256);
define_ecdsa_signer!(Es384Signer, Algorithm::ES384, SigningKey384);
define_ecdsa_signer!(Es256Signer, Algorithm::ES256, SigningKey256, Signature256);
define_ecdsa_signer!(Es384Signer, Algorithm::ES384, SigningKey384, Signature384);
define_ecdsa_signer!(Es512Signer, Algorithm::ES512, SigningKey521, Signature521);

define_ecdsa_verifier!(Es256Verifier, Algorithm::ES256, VerifyingKey256, Signature256);
define_ecdsa_verifier!(Es384Verifier, Algorithm::ES384, VerifyingKey384, Signature384);
define_ecdsa_verifier!(Es512Verifier, Algorithm::ES512, VerifyingKey521, Signature521);
8 changes: 4 additions & 4 deletions src/crypto/rust_crypto/hmac.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
//! Implementations of the [`JwtSigner`] and [`JwtVerifier`] traits for the
//! HMAC family of algorithms using `RustCrypto`'s [`hmac`].

use hmac::{Hmac, Mac};
use hmac::{HmacReset, KeyInit, Mac};
use sha2::{Sha256, Sha384, Sha512};
use signature::{Signer, Verifier};

use crate::crypto::{JwtSigner, JwtVerifier};
use crate::errors::{ErrorKind, Result, new_error};
use crate::{Algorithm, AlgorithmFamily, DecodingKey, EncodingKey};

type HmacSha256 = Hmac<Sha256>;
type HmacSha384 = Hmac<Sha384>;
type HmacSha512 = Hmac<Sha512>;
type HmacSha256 = HmacReset<Sha256>;
type HmacSha384 = HmacReset<Sha384>;
type HmacSha512 = HmacReset<Sha512>;

/// Macro to define an HMAC signer for a specific algorithm
macro_rules! define_hmac_signer {
Expand Down
29 changes: 25 additions & 4 deletions src/crypto/rust_crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ::rsa::{
use ed25519_dalek::SigningKey as Ed25519SigningKey;
use p256::{ecdsa::SigningKey as P256SigningKey, pkcs8::DecodePrivateKey};
use p384::ecdsa::SigningKey as P384SigningKey;
use p521::ecdsa::SigningKey as P521SigningKey;
use sha2::{Digest, Sha256, Sha384, Sha512};

use crate::{
Expand All @@ -24,13 +25,19 @@ fn rsa_components_from_private_key(key_content: &[u8]) -> errors::Result<(Vec<u8
let private_key = RsaPrivateKey::from_pkcs1_der(key_content)
.map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?;
let public_key = private_key.to_public_key();
Ok((public_key.n().to_bytes_be(), public_key.e().to_bytes_be()))
Ok((
public_key.n().to_be_bytes_trimmed_vartime().to_vec(),
public_key.e().to_be_bytes_trimmed_vartime().to_vec(),
))
}

fn rsa_components_from_public_key(key_content: &[u8]) -> errors::Result<(Vec<u8>, Vec<u8>)> {
let public_key = RsaPublicKey::from_pkcs1_der(key_content)
.map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?;
Ok((public_key.n().to_bytes_be(), public_key.e().to_bytes_be()))
Ok((
public_key.n().to_be_bytes_trimmed_vartime().to_vec(),
public_key.e().to_be_bytes_trimmed_vartime().to_vec(),
))
}

fn ec_components_from_private_key(
Expand All @@ -42,7 +49,7 @@ fn ec_components_from_private_key(
let signing_key = P256SigningKey::from_pkcs8_der(key_content)
.map_err(|_| ErrorKind::InvalidEcdsaKey)?;
let public_key = signing_key.verifying_key();
let encoded = public_key.to_encoded_point(false);
let encoded = public_key.to_sec1_point(false);
match encoded.coordinates() {
p256::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => {
Ok((EllipticCurve::P256, x.to_vec(), y.to_vec()))
Expand All @@ -54,14 +61,26 @@ fn ec_components_from_private_key(
let signing_key = P384SigningKey::from_pkcs8_der(key_content)
.map_err(|_| ErrorKind::InvalidEcdsaKey)?;
let public_key = signing_key.verifying_key();
let encoded = public_key.to_encoded_point(false);
let encoded = public_key.to_sec1_point(false);
match encoded.coordinates() {
p384::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => {
Ok((EllipticCurve::P384, x.to_vec(), y.to_vec()))
}
_ => Err(ErrorKind::InvalidEcdsaKey.into()),
}
}
Algorithm::ES512 => {
let signing_key = P521SigningKey::from_pkcs8_der(key_content)
.map_err(|_| ErrorKind::InvalidEcdsaKey)?;
let public_key = signing_key.verifying_key();
let encoded = public_key.to_sec1_point(false);
match encoded.coordinates() {
p521::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => {
Ok((EllipticCurve::P521, x.to_vec(), y.to_vec()))
}
_ => Err(ErrorKind::InvalidEcdsaKey.into()),
}
}
_ => Err(ErrorKind::InvalidEcdsaKey.into()),
}
}
Expand Down Expand Up @@ -95,6 +114,7 @@ fn new_signer(algorithm: &Algorithm, key: &EncodingKey) -> Result<Box<dyn JwtSig
Algorithm::HS512 => Box::new(hmac::Hs512Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::ES256 => Box::new(ecdsa::Es256Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::ES384 => Box::new(ecdsa::Es384Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::ES512 => Box::new(ecdsa::Es512Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::RS256 => Box::new(rsa::Rsa256Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::RS384 => Box::new(rsa::Rsa384Signer::new(key)?) as Box<dyn JwtSigner>,
Algorithm::RS512 => Box::new(rsa::Rsa512Signer::new(key)?) as Box<dyn JwtSigner>,
Expand All @@ -117,6 +137,7 @@ fn new_verifier(
Algorithm::HS512 => Box::new(hmac::Hs512Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::ES256 => Box::new(ecdsa::Es256Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::ES384 => Box::new(ecdsa::Es384Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::ES512 => Box::new(ecdsa::Es512Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::RS256 => Box::new(rsa::Rsa256Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::RS384 => Box::new(rsa::Rsa384Verifier::new(key)?) as Box<dyn JwtVerifier>,
Algorithm::RS512 => Box::new(rsa::Rsa512Verifier::new(key)?) as Box<dyn JwtVerifier>,
Expand Down
15 changes: 9 additions & 6 deletions src/crypto/rust_crypto/rsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! RSA family of algorithms using RustCrypto.

use rsa::{
BigUint, Pkcs1v15Sign, Pss, RsaPublicKey,
BoxedUint, Pkcs1v15Sign, Pss, RsaPublicKey,
pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey},
pkcs1v15::SigningKey,
pkcs8::AssociatedOid,
Expand All @@ -29,7 +29,7 @@ fn try_sign_rsa<H>(
where
H: Digest + AssociatedOid + FixedOutputReset,
{
let mut rng = rand::thread_rng();
let mut rng = rand::rng();
let private_key = rsa::RsaPrivateKey::from_pkcs1_der(encoding_key.as_bytes())
.map_err(signature::Error::from_source)?;
if pss {
Expand Down Expand Up @@ -57,9 +57,12 @@ fn verify_rsa<S: SignatureScheme, H: Digest + AssociatedOid>(
.map_err(signature::Error::from_source)?;
}
DecodingKeyKind::RsaModulusExponent { n, e } => {
RsaPublicKey::new(BigUint::from_bytes_be(n), BigUint::from_bytes_be(e))?
.verify(scheme, &digest, signature)
.map_err(signature::Error::from_source)?;
RsaPublicKey::new(
BoxedUint::from_be_slice_vartime(n),
BoxedUint::from_be_slice_vartime(e),
)?
.verify(scheme, &digest, signature)
.map_err(signature::Error::from_source)?;
}
};

Expand Down Expand Up @@ -115,7 +118,7 @@ macro_rules! define_rsa_verifier {
signature: &Vec<u8>,
) -> std::result::Result<(), signature::Error> {
if $pss {
verify_rsa::<Pss, $hash>(Pss::new::<$hash>(), &self.0, msg, signature)
verify_rsa::<Pss<$hash>, $hash>(Pss::<$hash>::new(), &self.0, msg, signature)
} else {
verify_rsa::<_, $hash>(Pkcs1v15Sign::new::<$hash>(), &self.0, msg, signature)
}
Expand Down
Loading