Keats / jsonwebtoken

JWT lib in rust
MIT License
1.69k stars 271 forks source link

Signing/verifying JWTs with RSA DER encoded keys #122

Closed emfax closed 2 years ago

emfax commented 4 years ago

Hi,

I've met with a problem attempting to sign/verify with RSA DER encoded keys and have no idea what is going on. The source code mentions that you should know what you're doing with DER encoded keys, but I'm trying it anyway.

Here's some code:

use serde::{Deserialize, Serialize};
use jsonwebtoken::{ encode, Header, EncodingKey, Algorithm, errors };

#[derive(Serialize, Deserialize)]
pub struct Claims {
    email: String
}

pub fn mk_token (claims: &Claims, encoding_key: &EncodingKey) -> Result<String, errors::Error> {
    Ok(encode(&Header::new(Algorithm::RS256), claims, encoding_key)?)
}

#[cfg(test)]
mod tests {
    use super::*;
    use jsonwebtoken::{ decode, DecodingKey, Validation };
    use openssl::rsa::Rsa;
    use openssl::pkey::{ PKey };

    #[test]
    fn test_mk_token() {
        let rsa = Rsa::generate(2048).unwrap();
        let pkey = PKey::from_rsa(rsa).unwrap();
        let private_der = pkey.private_key_to_der().unwrap();
        let public_der = pkey.public_key_to_der().unwrap();
        let encoding_key = EncodingKey::from_rsa_der(&private_der);
        let decoding_key = DecodingKey::from_rsa_der(&public_der);

        let test_claims = Claims {
            email: "a@b.c".to_string()
        };

        let token = match encode(&Header::new(Algorithm::RS256), &test_claims, &encoding_key) {
            Ok(t) => t,
            Err(_) => {
                panic!();
            }
        };

        let token_data = match decode::<Claims>(
            &token,
            &decoding_key,
            &Validation::new(Algorithm::RS256)
        ) {
            Ok(t) => t,
            Err(e) => {
                eprintln!("{}", e);
                panic!("Could even decode")
            }
        };

        println!("{}", token_data.claims.email)
    }
}

I've created a DER encoded public and private keys and used them to create an EncodingKey and a DecodingKey. The JWT encodes just fine, but decoding returns an InvalidSignature error.

I've looked through the source and even step through execution with lldb to try and determine the cause of the error, but to no avail.

Is there an endianess issue here I haven't considered? How to properly use DER encoded keys?

Keats commented 4 years ago

I have only used DER keys created with the openssl cli tool, I'm not sure what's happening there :/

emfax commented 4 years ago

What would be a good direction to go in to try and figure this one out?

dewey4iv commented 4 years ago

hey @ttxndrx -- I'm sure this is later than you would have liked but I was able to get it working:


use std::ops::Add;
use std::time;

use serde::{Deserialize, Serialize};
use jsonwebtoken::{ encode, Header, EncodingKey, Algorithm, errors };

#[derive(Serialize, Deserialize)]
pub struct Claims {
    email: String,
    exp: usize,
}

pub fn mk_token (claims: &Claims, encoding_key: &EncodingKey) -> Result<String, errors::Error> {
    Ok(encode(&Header::new(Algorithm::RS256), claims, encoding_key)?)
}

#[cfg(test)]
mod tests {
    use super::*;
    use jsonwebtoken::{ decode, DecodingKey, Validation };
    use openssl::rsa::Rsa;

    #[test]
    fn test_mk_token() {
        let rsa = Rsa::generate(4096).unwrap();

        let private_der = rsa.private_key_to_der().unwrap();
        let public_der = rsa.public_key_to_der_pkcs1().unwrap();

        let encoding_key = EncodingKey::from_rsa_der(&private_der);
        let decoding_key = DecodingKey::from_rsa_der(&public_der);

        let exp = time::SystemTime::now()
            .duration_since(time::UNIX_EPOCH)
            .expect("unable to get the current time")
            .add(time::Duration::from_secs(60 * 20)) // 20 min
            .as_secs();

        let test_claims = Claims {
            email: "a@b.c".to_string(),
            exp: exp as usize,
        };

        let token = match encode(&Header::new(Algorithm::RS256), &test_claims, &encoding_key) {
            Ok(t) => t,
            Err(_) => {
                panic!();
            }
        };

        let token_data = match decode::<Claims>(
            &token,
            &decoding_key,
            &Validation::new(Algorithm::RS256)
        ) {
            Ok(t) => t,
            Err(e) => {
                eprintln!("{}", e);
                panic!("Couldn't even decode")
            }
        };

        println!("{}", token_data.claims.email)
    }
}