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

Feature request: Support arbitrary crypto backends #409

Open
sidrubs opened this issue Sep 22, 2024 · 9 comments
Open

Feature request: Support arbitrary crypto backends #409

sidrubs opened this issue Sep 22, 2024 · 9 comments

Comments

@sidrubs
Copy link

sidrubs commented Sep 22, 2024

Hi,

I see there has already been a bit of activity surrounding crypto backend support. We have a use-case where we would like to provide an arbitrary "signer" and "verifier" (e.g. a call out to an HSM). I would, personally, prefer to get this into the jsonwebtoken crate, rather than maintaining a fork, as I don't like unnecessary fragmentation of the ecosystem.

I am more than happy to make the PR (making sure that we don't break backwards compatibility). Is this something that the jsonwebtoken crate would consider including?

I did a very rough POC making use of RustCrypto's signature::Signer and signature::Verifier traits.

Setting up signing and verifying traits:

use signature::{Signer, Verifier};

use crate::Algorithm;

/// Provide the type of algorithm implemented by the signing module.
///
/// This is used to populate and verify the header of the JWT.
pub trait AlgorithmType {
    /// Return the [`Algorithm`] corresponding to the signing module.
    fn algorithm_type(&self) -> Algorithm;
}

/// Provides the functionality required to sign a JWT.
///
/// This would usually be implemented to provide custom signing mechanisms (e.g. HSM).
pub trait SigningModule<S>: AlgorithmType + Signer<S> {}

/// Provides the functionality required to verify a JWT.
///
/// This would usually be implemented to provide custom verifying mechanisms (e.g. HSM).
pub trait VerifyingModule<S>: AlgorithmType + Verifier<S> {}

Performing the encoding:

use serde::Serialize;

use crate::{errors::Error, serialization::b64_encode_part, Header};

use super::SigningModule;

/// Encodes the claims into a JWT.
///
/// The header is generated from the `signing_module.algorithm_type`.
pub fn encode<T: Serialize, M: SigningModule<String>>(
    claims: &T,
    signing_module: M,
) -> Result<String, Error> {
    let header = Header::new(signing_module.algorithm_type());

    let encoded_header = b64_encode_part(&header)?;
    let encoded_claims = b64_encode_part(claims)?;
    let message = [encoded_header, encoded_claims].join(".");

    let signature = signing_module.sign(message.as_bytes());

    Ok([message, signature].join("."))
}

One could implement default signing and verifying modules using ring (or RustCrypto, or aws-lc-rs) and could put all the "complexity" of the creating the signing and verifying modules behind the current public facing encode and decode functions so that this does not introduce breaking changes.

Is there anything else I would need to consider?

@Keats
Copy link
Owner

Keats commented Sep 22, 2024

There's #402 which is the start of the same idea minus traits. The idea was to support aws-lc-rs and rust-crypto. I didn't consider traits but i guess it would work fine.

@sidrubs
Copy link
Author

sidrubs commented Sep 23, 2024

Aah ok I see how #402 is being done.

If one were to extend that to use traits, and expose the trait API in addition to the current encode and decode functions, it would allow an escape hatch for people to provide whichever crypto their use-case requires.

Should I write up a PR incorporating ring, aws-lc-rs, and RustCrypto using a traits implementation?

I don't want to step on anyone's toes or mess with PRs currently in progress. So if you feel the traits route isn't the correct direction, I'm fine with maintaining a fork for my use-case.

@Keats
Copy link
Owner

Keats commented Sep 23, 2024

#318 has been merged on the next branch as well.

As for doing the PR, you can see with @GlenDC what he prefers

@sidrubs
Copy link
Author

sidrubs commented Oct 3, 2024

I have not received any response from @GlenDC, so have gone ahead an make a draft PR with a POC. It shows how I propose the use of JwtSigner and JwtVerifier traits whiles still maintaining backward compatibility with the current API.

Feel free to make suggestions.

@c2bo
Copy link

c2bo commented Oct 10, 2024

I just came across a similar issue -> +1 for the Feature, especially with the ability/freedom to use other backends.

@GlenDC
Copy link

GlenDC commented Jan 9, 2025

@Keats / @sidrubs I have some bandwidth to spare and in light of #399 I can help maintenance given this is the JWT lib with the most future benefit. Want me to take over your draft PR. is that still the way to go, and what with the aws-ls-rs PR?

Once this big ticket is fixed I can also start digging through the other open tickets.

@Keats
Copy link
Owner

Keats commented Jan 9, 2025

#410 is definitely the way to go. It's missing some stuff but the base is there and it should be possible to finish it.

@GlenDC
Copy link

GlenDC commented Jan 9, 2025

Sure, @sidrubs are you okay with me taking over? I respect the choice either way.
@Keats can you do a braindump for anything not yet mentioned in that PR? That can help as guidance and help me complete it (if @sidrubs would be ok with it).

@sidrubs
Copy link
Author

sidrubs commented Jan 9, 2025

@GlenDC sure, that would be great! Let me know if you have any questions.

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

4 participants