jwtk 0.5.0

JWT signing (JWS) and verification, with first class JWK and JWK Set (JWKS) support.
Documentation
use super::*;
use crate::{jwk::Jwk, PublicKeyToJwk, VerificationKey, URL_SAFE_TRAILING_BITS};
use aws_lc_rs::rsa::{PublicKeyComponents, RsaParameters};
use aws_lc_rs::signature;
use base64::Engine as _;

/// RSA Public Key (aws-lc-rs backend, verification only).
#[derive(Debug, Clone)]
pub struct RsaPublicKey {
    components: PublicKeyComponents<Vec<u8>>,
    /// If this is `None`, this key verifies signatures generated by ANY RSA
    /// algorithms. Otherwise it ONLY verifies signatures generated by this
    /// algorithm.
    pub algorithm: Option<RsaAlgorithm>,
}

impl RsaPublicKey {
    pub fn from_components(n: &[u8], e: &[u8], algorithm: Option<RsaAlgorithm>) -> Result<Self> {
        Ok(Self {
            components: PublicKeyComponents {
                n: n.to_vec(),
                e: e.to_vec(),
            },
            algorithm,
        })
    }
}

impl PublicKeyToJwk for RsaPublicKey {
    fn public_key_to_jwk(&self) -> Result<Jwk> {
        Ok(Jwk {
            kty: "RSA".into(),
            alg: self.algorithm.map(|alg| alg.name().to_string()),
            use_: Some("sig".into()),
            n: Some(URL_SAFE_TRAILING_BITS.encode(&self.components.n)),
            e: Some(URL_SAFE_TRAILING_BITS.encode(&self.components.e)),
            ..Jwk::default()
        })
    }
}

fn rsa_params(alg: RsaAlgorithm) -> &'static RsaParameters {
    use RsaAlgorithm::*;
    match alg {
        RS256 => &signature::RSA_PKCS1_2048_8192_SHA256,
        RS384 => &signature::RSA_PKCS1_2048_8192_SHA384,
        RS512 => &signature::RSA_PKCS1_2048_8192_SHA512,
        PS256 => &signature::RSA_PSS_2048_8192_SHA256,
        PS384 => &signature::RSA_PSS_2048_8192_SHA384,
        PS512 => &signature::RSA_PSS_2048_8192_SHA512,
    }
}

impl VerificationKey for RsaPublicKey {
    fn verify(&self, v: &[u8], sig: &[u8], alg: &str) -> Result<()> {
        let alg = if let Some(self_alg) = self.algorithm {
            if self_alg.name() != alg {
                return Err(Error::VerificationError);
            }
            self_alg
        } else {
            RsaAlgorithm::from_name(alg)?
        };
        self.components
            .verify(rsa_params(alg), v, sig)
            .map_err(|_| Error::VerificationError)
    }
}