Skip to content

Vendor OpenSSL + Minor Fixes #98

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
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
18 changes: 13 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,27 @@ repository = "http://github.com/mikkyang/rust-jwt"
readme = "README.md"
keywords = ["JWT", "token", "web"]
license = "MIT"
edition = "2018"
edition = "2021"

[package.metadata.docs.rs]
features = ["openssl"]
[features]
openssl = ["dep:openssl"]
openssl-vendored = ["openssl", "openssl/vendored"]
default = []

[dependencies]
base64 = "0.13"
base64 = "0.21"
crypto-common = "0.1"
digest = "0.10"
digest = { version = "0.10", features = ["oid"] }
signature = { version = "2.2", features = ["digest"] }
hmac = { version = "0.12", features = ["reset"] }
sha2 = "0.10"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
ecdsa = { version = "0.16", features = ["verifying", "signing"] }
rsa = { version = "0.9", features = ["sha2"] }
p256 = { version = "0.13", features = ["pem"] }
p384 = { version = "0.13", features = ["pem"] }
pem = "3.0"

[dependencies.openssl]
version = "0.10"
Expand Down
2 changes: 1 addition & 1 deletion examples/custom_claims.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ fn login(token: &str) -> Result<String, &'static str> {
fn main() -> Result<(), &'static str> {
let token = new_token("Michael Yang", "password")?;

let logged_in_user = login(&*token)?;
let logged_in_user = login(&token)?;

assert_eq!(logged_in_user, "Michael Yang");
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion examples/hs256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn login(token: &str) -> Result<String, &'static str> {
fn main() -> Result<(), &'static str> {
let token = new_token("Michael Yang", "password")?;

let logged_in_user = login(&*token)?;
let logged_in_user = login(&token)?;

assert_eq!(logged_in_user, "Michael Yang");
Ok(())
Expand Down
14 changes: 6 additions & 8 deletions src/algorithm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,24 @@
//! let hs256_key: Hmac<Sha256> = Hmac::new_from_slice(b"some-secret").unwrap();
//! ```

use base64::Engine;
use serde::{Deserialize, Serialize};

use crate::error::Error;

#[cfg(feature = "openssl")]
pub mod openssl;

pub mod rust_crypto;
pub mod store;

/// The type of an algorithm, corresponding to the
/// [JWA](https://tools.ietf.org/html/rfc7518) specification.
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
#[derive(Default)]
pub enum AlgorithmType {
#[default]
Hs256,
Hs384,
Hs512,
Expand All @@ -40,12 +44,6 @@ pub enum AlgorithmType {
None,
}

impl Default for AlgorithmType {
fn default() -> Self {
AlgorithmType::Hs256
}
}

/// An algorithm capable of signing base64 encoded header and claims strings.
/// strings.
pub trait SigningAlgorithm {
Expand All @@ -61,8 +59,8 @@ pub trait VerifyingAlgorithm {
fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error>;

fn verify(&self, header: &str, claims: &str, signature: &str) -> Result<bool, Error> {
let signature_bytes = base64::decode_config(signature, base64::URL_SAFE_NO_PAD)?;
self.verify_bytes(header, claims, &*signature_bytes)
let signature_bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(signature)?;
self.verify_bytes(header, claims, &signature_bytes)
}
}

Expand Down
42 changes: 31 additions & 11 deletions src/algorithm/openssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
use crate::error::Error;
use crate::SEPARATOR;

use base64::Engine;
use openssl::bn::BigNum;
use openssl::ecdsa::EcdsaSig;
use openssl::hash::MessageDigest;
Expand Down Expand Up @@ -52,7 +53,7 @@ impl SigningAlgorithm for PKeyWithDigest<Private> {
}

fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
let mut signer = Signer::new(self.digest.clone(), &self.key)?;
let mut signer = Signer::new(self.digest, &self.key)?;
signer.update(header.as_bytes())?;
signer.update(SEPARATOR.as_bytes())?;
signer.update(claims.as_bytes())?;
Expand All @@ -64,7 +65,7 @@ impl SigningAlgorithm for PKeyWithDigest<Private> {
signer_signature
};

Ok(base64::encode_config(&signature, base64::URL_SAFE_NO_PAD))
Ok(base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(signature))
}
}

Expand All @@ -74,7 +75,7 @@ impl VerifyingAlgorithm for PKeyWithDigest<Public> {
}

fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
let mut verifier = Verifier::new(self.digest.clone(), &self.key)?;
let mut verifier = Verifier::new(self.digest, &self.key)?;
verifier.update(header.as_bytes())?;
verifier.update(SEPARATOR.as_bytes())?;
verifier.update(claims.as_bytes())?;
Expand All @@ -92,7 +93,7 @@ impl VerifyingAlgorithm for PKeyWithDigest<Public> {

/// OpenSSL by default signs ECDSA in DER, but JOSE expects them in a concatenated (R, S) format
fn der_to_jose(der: &[u8]) -> Result<Vec<u8>, Error> {
let signature = EcdsaSig::from_der(&der)?;
let signature = EcdsaSig::from_der(der)?;
let r = signature.r().to_vec();
let s = signature.s().to_vec();
Ok([r, s].concat())
Expand All @@ -119,12 +120,14 @@ mod tests {
use openssl::pkey::PKey;

// {"sub":"1234567890","name":"John Doe","admin":true}
const CLAIMS: &'static str =
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
const CLAIMS: &str = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";

const RS256_SIGNATURE: &'static str =
const RS256_SIGNATURE: &str =
"cQsAHF2jHvPGFP5zTD8BgoJrnzEx6JNQCpupebWLFnOc2r_punDDTylI6Ia4JZNkvy2dQP-7W-DEbFQ3oaarHsDndqUgwf9iYlDQxz4Rr2nEZX1FX0-FMEgFPeQpdwveCgjtTYUbVy37ijUySN_rW-xZTrsh_Ug-ica8t-zHRIw";

const PREGENERATED_ES256_SIGNATURE: &str =
"6SgeIURSNz_qFcxsKQOWZmi_ALiBctj_ZINvce4AOa-OQn9QI6lh8P78FTZx5LQtOleF3XeBlGIAdYms_VPecA";

#[test]
fn rs256_sign() -> Result<(), Error> {
let pem = include_bytes!("../../test/rs256-private.pem");
Expand Down Expand Up @@ -155,25 +158,42 @@ mod tests {
}

#[test]
fn es256() -> Result<(), Error> {
fn es256_sign() -> Result<(), Error> {
let private_pem = include_bytes!("../../test/es256-private.pem");
let private_key = PKeyWithDigest {
digest: MessageDigest::sha256(),
key: PKey::private_key_from_pem(private_pem)?,
};

let signature = private_key.sign(&AlgOnly(Es256).to_base64()?, CLAIMS)?;

let public_pem = include_bytes!("../../test/es256-public.pem");

let public_key = PKeyWithDigest {
digest: MessageDigest::sha256(),
key: PKey::public_key_from_pem(public_pem)?,
};

let verification_result =
public_key.verify(&AlgOnly(Es256).to_base64()?, CLAIMS, &*signature)?;
public_key.verify(&AlgOnly(Es256).to_base64()?, CLAIMS, &signature)?;

assert!(verification_result);
Ok(())
}

#[test]
fn es256_verify() -> Result<(), Error> {
let public_pem = include_bytes!("../../test/es256-public.pem");
let public_key = PKeyWithDigest {
digest: MessageDigest::sha256(),
key: PKey::public_key_from_pem(public_pem)?,
};

let verification_result = public_key.verify(
&AlgOnly(Es256).to_base64()?,
CLAIMS,
PREGENERATED_ES256_SIGNATURE,
)?;
assert!(verification_result);

Ok(())
}
}
6 changes: 5 additions & 1 deletion src/algorithm/rust_crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! According to that organization, only hmac is safely implemented at the
//! moment.

use base64::Engine;
use digest::{
block_buffer::Eager,
consts::U256,
Expand All @@ -14,6 +15,9 @@ use hmac::{Hmac, Mac};
use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
use crate::error::Error;
use crate::SEPARATOR;

pub mod asymmetric;

/// A trait used to make the implementation of `SigningAlgorithm` and
/// `VerifyingAlgorithm` easier.
/// RustCrypto crates tend to have algorithm types defined at the type level,
Expand Down Expand Up @@ -56,7 +60,7 @@ where
let hmac = get_hmac_with_data(self, header, claims);
let mac_result = hmac.finalize();
let code = mac_result.into_bytes();
Ok(base64::encode_config(&code, base64::URL_SAFE_NO_PAD))
Ok(base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(code))
}
}

Expand Down
Loading