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

Compatibility for YACME #16

Merged
merged 10 commits into from
Dec 2, 2023
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ digest = { version = "0.10" }
ecdsa = { version = "0.16", features = ["signing", "der"], optional = true }
hmac = { version = "0.12", optional = true }
p256 = { version = "0.13", features = ["ecdsa", "jwk"], optional = true }
p384 = { version = "0.13", optional = true }
p521 = { version = "0.13", optional = true }
p384 = { version = "0.13", features = ["ecdsa", "jwk"], optional = true }
p521 = { version = "0.13", features = ["ecdsa", "jwk"], optional = true }
pkcs8 = "0.10"
rand_core = { version = "0.6.4", optional = true, default-features = false }
rsa = { version = "0.9", features = ["sha2"], optional = true }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ ecosystem.

This is an example [JWT][], taken from the ACME standard ([RFC 8555][RFC8555]):

```json
```javascript
{
"protected": base64url({
"alg": "ES256",
Expand Down
40 changes: 40 additions & 0 deletions src/algorithms/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,4 +454,44 @@ mod test {
)
.expect("signature verification for RFC7515a3 example failed");
}

macro_rules! ecdsa_algorithm_test {
($name:ident, $curve:ty) => {
#[cfg(feature = "rand")]
#[test]
fn $name() {
let key = SigningKey::<$curve>::random(&mut rand_core::OsRng);
let verify = *key.verifying_key();

let payload = json! {
{
"iss": "joe",
"exp": 1300819380,
"http://example.com/is_root": true
}
};

let token = crate::Token::compact((), payload);

let signed = token
.clone()
.sign::<_, ecdsa::Signature<$curve>>(&key)
.unwrap();
let unverified = signed.unverify();
unverified
.verify::<_, ecdsa::Signature<$curve>>(&verify)
.unwrap();

let signed = token.clone().sign::<_, SignatureBytes>(&key).unwrap();
let unverified = signed.unverify();
unverified.verify::<_, SignatureBytes>(&verify).unwrap();
}
};
}

#[cfg(feature = "p256")]
ecdsa_algorithm_test!(p256_roundtrip, NistP256);

#[cfg(feature = "p384")]
ecdsa_algorithm_test!(p384_roundtrip, NistP384);
}
24 changes: 22 additions & 2 deletions src/algorithms/hmac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ use digest::{Digest, Mac};
use hmac::SimpleHmac;
use signature::{Keypair, SignatureEncoding};

use crate::key::{JWKeyType, SerializeJWK};
use crate::{
key::{JWKeyType, SerializeJWK},
SignatureBytes,
};

use super::JsonWebAlgorithm;

Expand Down Expand Up @@ -204,6 +207,23 @@ where
}
}

impl<D> super::TokenSigner<SignatureBytes> for Hmac<D>
where
Hmac<D>: JsonWebAlgorithm,
D: Digest + digest::core_api::BlockSizeUser + Clone,
{
fn try_sign_token(
&self,
header: &str,
payload: &str,
) -> Result<SignatureBytes, signature::Error> {
let signature = <Self as super::TokenSigner<DigestSignature<D>>>::try_sign_token(
self, header, payload,
)?;
Ok(signature.to_bytes().as_ref().into())
}
}

impl<D> super::TokenVerifier<DigestSignature<D>> for Hmac<D>
where
Hmac<D>: JsonWebAlgorithm,
Expand Down Expand Up @@ -269,7 +289,7 @@ mod test {

let algorithm: Hmac<Sha256> = Hmac::new(key);

let signature = algorithm.sign_token(&header, &payload);
let signature: DigestSignature<_> = algorithm.sign_token(&header, &payload);

let sig = base64ct::Base64UrlUnpadded::encode_string(signature.to_bytes().as_ref());

Expand Down
11 changes: 7 additions & 4 deletions src/algorithms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
//! - RS512: RSASSA-PKCS1-v1_5 using SHA-512 via [`rsa::pkcs1v15::SigningKey<Sha512>`][rsa::pkcs1v15::SigningKey] / [`rsa::pkcs1v15::VerifyingKey<Sha512>`][rsa::pkcs1v15::VerifyingKey]
//! - PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256 via [`rsa::pss::SigningKey<Sha256>`][rsa::pss::SigningKey] / [`rsa::pss::VerifyingKey<Sha256>`][rsa::pss::VerifyingKey]
//! - PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384 via [`rsa::pss::SigningKey<Sha384>`][rsa::pss::SigningKey] / [`rsa::pss::VerifyingKey<Sha384>`][rsa::pss::VerifyingKey]
//! - PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-384 via [`rsa::pss::SigningKey<Sha512>`][rsa::pss::SigningKey] / [`rsa::pss::VerifyingKey<Sha512>`][rsa::pss::VerifyingKey]
//!
//! ## ECDSA
//!
Expand Down Expand Up @@ -159,7 +160,7 @@ pub trait JsonWebAlgorithm {
const IDENTIFIER: AlgorithmIdentifier;
}

/// A trait to associate an alogritm identifier with an algorithm.
/// An object-safe trait to associate an alogritm identifier with an algorithm.
///
/// This is a dynamic version of [`JsonWebAlgorithm`], which allows for
/// dynamic dispatch of the algorithm, and object-safety for the trait.
Expand Down Expand Up @@ -189,7 +190,7 @@ pub trait JsonWebAlgorithmDigest: JsonWebAlgorithm {
/// A trait to represent an algorithm which can sign a JWT.
///
/// This trait should apply to signing keys.
pub trait TokenSigner<S>: DynJsonWebAlgorithm + SerializePublicJWK
pub trait TokenSigner<S = SignatureBytes>: DynJsonWebAlgorithm + SerializePublicJWK
where
S: SignatureEncoding,
{
Expand Down Expand Up @@ -229,7 +230,8 @@ where
#[cfg(feature = "rand")]
/// A trait to represent an algorithm which can sign a JWT, with a source of
/// randomness.
pub trait RandomizedTokenSigner<S>: DynJsonWebAlgorithm + SerializePublicJWK
pub trait RandomizedTokenSigner<S = SignatureBytes>:
DynJsonWebAlgorithm + SerializePublicJWK
where
S: SignatureEncoding,
{
Expand Down Expand Up @@ -259,7 +261,7 @@ where
///
/// This trait should apply to the equivalent of public keys, which have enough information
/// to verify a JWT signature, but not necessarily to sing it.
pub trait TokenVerifier<S>: DynJsonWebAlgorithm
pub trait TokenVerifier<S = SignatureBytes>: DynJsonWebAlgorithm
where
S: SignatureEncoding,
{
Expand Down Expand Up @@ -434,4 +436,5 @@ mod test {
// a concrete `Signature` type, or an object-safe trait.
sa::assert_obj_safe!(TokenSigner<SignatureBytes>);
sa::assert_obj_safe!(TokenVerifier<SignatureBytes>);
sa::assert_obj_safe!(DynJsonWebAlgorithm);
}
Loading