Skip to content
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
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "compact_jwt"
version = "0.5.6"
edition = "2021"
edition = "2024"
authors = ["William Brown <william@blackhats.net.au>"]
description = "Minimal implementation of JWT for OIDC and other applications"
repository = "https://github.com/kanidm/compact-jwt"
Expand All @@ -24,19 +24,19 @@ all-features = true

[dependencies]
base64 = "^0.22.1"
base64urlsafedata = "^0.5.1"
crypto-glue = "^0.1.12"
crypto-glue = "^0.1.16"
hex = "0.4"
kanidm-hsm-crypto = "^0.3.2"
serde = { version = "^1.0.228", features = ["derive"] }
serde_json = "^1.0.145"
serde_with = { version = "3.18.0", features = ["base64", "macros"] }
time = { version = "0.3.44", features = ["macros", "parsing", "serde"] }
tracing = "^0.1.34"
url = { version = "^2.5.7", features = ["serde"] }
uuid = { version = "^1.19.0", features = ["serde"] }
uuid = { version = "^1.23.1", features = ["serde"] }

[dev-dependencies]
tracing-subscriber = "^0.3.22"
tracing-subscriber = "^0.3.23"

[profile.dev.package.num-bigint-dig]
opt-level = 3
50 changes: 29 additions & 21 deletions src/compact.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
//! Compact serialisation formats
use base64::{engine::general_purpose, Engine as _};

use crate::error::JwtError;
use crate::jws::Jws;
use crate::traits::JwsVerifiable;
use base64::{Engine as _, engine::general_purpose};
use serde::{Deserialize, Serialize};
use serde_with::{
IfIsHumanReadable,
base64::{Base64, UrlSafe},
formats::Unpadded,
serde_as,
};
use std::fmt;
use std::str::FromStr;
use url::Url;

use crate::error::JwtError;
use crate::jws::Jws;
use crate::traits::JwsVerifiable;
use base64urlsafedata::Base64UrlSafeData;

// https://datatracker.ietf.org/doc/html/rfc7515

#[derive(Debug, Serialize, Clone, Deserialize)]
Expand All @@ -29,6 +32,7 @@ pub enum EcCurve {
P256,
}

#[serde_as]
#[derive(Debug, Serialize, Clone, Deserialize, PartialEq)]
#[allow(non_camel_case_types)]
#[serde(tag = "kty")]
Expand All @@ -39,9 +43,11 @@ pub enum Jwk {
/// The Eliptic Curve in use
crv: EcCurve,
/// The public X component
x: Base64UrlSafeData,
#[serde_as(as = "IfIsHumanReadable<Base64<UrlSafe, Unpadded>>")]
x: Vec<u8>,
/// The public Y component
y: Base64UrlSafeData,
#[serde_as(as = "IfIsHumanReadable<Base64<UrlSafe, Unpadded>>")]
y: Vec<u8>,
// We don't decode d (private key) because that way we error defending from
// the fact that ... well you leaked your private key.
// d: Base64UrlSafeData
Expand All @@ -58,9 +64,11 @@ pub enum Jwk {
/// Legacy RSA public key
RSA {
/// Public n value
n: Base64UrlSafeData,
#[serde_as(as = "IfIsHumanReadable<Base64<UrlSafe, Unpadded>>")]
n: Vec<u8>,
/// Public exponent
e: Base64UrlSafeData,
#[serde_as(as = "IfIsHumanReadable<Base64<UrlSafe, Unpadded>>")]
e: Vec<u8>,
/// The algorithm in use for this key
#[serde(skip_serializing_if = "Option::is_none")]
alg: Option<JwaAlg>,
Expand Down Expand Up @@ -219,11 +227,11 @@ impl FromStr for JwsCompact {

// Assert that from the critical field of the header, we have decoded all the needed types.
// Remember, anything in rfc7515 can NOT be in the crit field.
if let Some(crit) = &header.crit {
if !crit.is_empty() {
error!("critical extension - unable to process critical extensions");
return Err(JwtError::CriticalExtension);
}
if let Some(crit) = &header.crit
&& !crit.is_empty()
{
error!("critical extension - unable to process critical extensions");
return Err(JwtError::CriticalExtension);
}

// Now we have a header, lets get the rest.
Expand Down Expand Up @@ -539,11 +547,11 @@ impl FromStr for JweCompact {

// Assert that from the critical field of the header, we have decoded all the needed types.
// Remember, anything in rfc7515 can NOT be in the crit field.
if let Some(crit) = &header.crit {
if !crit.is_empty() {
error!("critical extension - unable to process critical extensions");
return Err(JwtError::CriticalExtension);
}
if let Some(crit) = &header.crit
&& !crit.is_empty()
{
error!("critical extension - unable to process critical extensions");
return Err(JwtError::CriticalExtension);
}

// Now we have a header, lets get the rest.
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/a128gcm.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::JwtError;
use crate::compact::{JweCompact, JweEnc};
use crate::jwe::Jwe;
use crate::traits::*;
use crate::JwtError;
use base64::{engine::general_purpose, Engine as _};
use base64::{Engine as _, engine::general_purpose};
use crypto_glue::{
aes128::{self, Aes128Key},
aes128gcm::{self, Aes128Gcm, Aes128GcmNonce, Aes128GcmTag},
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/a256gcm.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::JwtError;
use crate::compact::{JweCompact, JweEnc};
use crate::jwe::Jwe;
use crate::traits::*;
use crate::JwtError;
use base64::{engine::general_purpose, Engine as _};
use base64::{Engine as _, engine::general_purpose};
use crypto_glue::{
aes256::{self, Aes256Key},
aes256gcm::{self, Aes256Gcm, Aes256GcmNonce, Aes256GcmTag},
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/a256kw.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::JwtError;
use crate::compact::{JweAlg, JweCompact, JweProtectedHeader};
use crate::jwe::Jwe;
use crate::traits::*;
use crate::JwtError;
use crypto_glue::{
aes256::{self, Aes256Key},
aes256kw::{Aes256Kw, Aes256KwWrapped},
Expand Down
6 changes: 3 additions & 3 deletions src/crypto/ecdhes_a256kw.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use super::a256kw::JweA256KWEncipher;
use crate::JwtError;
use crate::compact::{EcCurve, JweAlg, JweCompact, JweProtectedHeader, Jwk};
use crate::jwe::Jwe;
use crate::traits::*;
use crate::JwtError;
use crypto_glue::{
aes256::Aes256Key,
ecdh_p256::{
Expand Down Expand Up @@ -38,8 +38,8 @@ impl JweEncipherOuterA256 for JweEcdhEsA256KWEncipher {

hdr.epk = Some(Jwk::EC {
crv: EcCurve::P256,
x: public_key_x.into(),
y: public_key_y.into(),
x: public_key_x,
y: public_key_y,
alg: None,
use_: None,
kid: None,
Expand Down
12 changes: 6 additions & 6 deletions src/crypto/es256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ use crypto_glue::{
},
};

use crate::KID_LEN;
use crate::compact::{EcCurve, JwaAlg, Jwk, JwkUse, JwsCompact, ProtectedHeader};
use crate::error::JwtError;
use crate::traits::*;
use crate::KID_LEN;
use base64::{engine::general_purpose, Engine as _};
use base64::{Engine as _, engine::general_purpose};
use std::fmt;
use std::hash::{Hash, Hasher};

Expand Down Expand Up @@ -180,8 +180,8 @@ impl JwsEs256Signer {

Ok(Jwk::EC {
crv: EcCurve::P256,
x: public_key_x.into(),
y: public_key_y.into(),
x: public_key_x,
y: public_key_y,
alg: Some(JwaAlg::ES256),
use_: Some(JwkUse::Sig),
kid: Some(kid),
Expand Down Expand Up @@ -389,8 +389,8 @@ impl JwsEs256Verifier {

Ok(Jwk::EC {
crv: EcCurve::P256,
x: public_key_x.into(),
y: public_key_y.into(),
x: public_key_x,
y: public_key_y,
alg: Some(JwaAlg::ES256),
use_: Some(JwkUse::Sig),
kid: Some(self.kid.clone()),
Expand Down
8 changes: 4 additions & 4 deletions src/crypto/hs256.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//! JWS Signing and Verification Structures
use crate::KID_LEN;
use crate::compact::{JwaAlg, JwsCompact, ProtectedHeader};
use crate::error::JwtError;
use crate::jws::JwsCompactSign2Data;
use crate::traits::*;
use crate::KID_LEN;
use base64::{engine::general_purpose, Engine as _};
use base64::{Engine as _, engine::general_purpose};
use crypto_glue::{
hmac_s256::{self, HmacSha256, HmacSha256Bytes, HmacSha256Key, HmacSha256Output},
traits::Mac,
Expand Down Expand Up @@ -213,11 +213,11 @@ fn kid(skey: &HmacSha256Key) -> String {

#[cfg(test)]
mod tests {
use super::{hmac_s256, JwsHs256Signer};
use super::{JwsHs256Signer, hmac_s256};
use crate::compact::JwsCompact;
use crate::jws::JwsBuilder;
use crate::traits::*;
use base64::{engine::general_purpose, Engine as _};
use base64::{Engine as _, engine::general_purpose};
use std::convert::TryFrom;
use std::str::FromStr;

Expand Down
2 changes: 1 addition & 1 deletion src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::compact::{JweCompact, JweEnc, JwsCompact};
use crate::error::JwtError;
use base64::{engine::general_purpose, Engine as _};
use base64::{Engine as _, engine::general_purpose};
use crypto_glue::aes128::Aes128Key;
use crypto_glue::aes256::Aes256Key;

Expand Down
16 changes: 8 additions & 8 deletions src/crypto/ms_oapxbc.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use super::a256gcm::JweA256GCMEncipher;
use super::hs256::JwsHs256Signer;
use crate::JwtError;
use crate::compact::{JweAlg, JweCompact, JweEnc, JweProtectedHeader, ProtectedHeader};
use crate::jwe::Jwe;
use crate::traits::*;
use crate::JwtError;
use base64::{engine::general_purpose, Engine as _};
use base64::{Engine as _, engine::general_purpose};
use crypto_glue::{
aes256::{self, Aes256Key},
aes256cbc::{block_padding, Aes256CbcDec, Aes256CbcIv, BlockDecryptMut, KeyIvInit},
aes256cbc::{Aes256CbcDec, Aes256CbcIv, BlockDecryptMut, KeyIvInit, block_padding},
rand::{self, Rng},
traits::Zeroizing,
};
Expand Down Expand Up @@ -391,34 +391,34 @@ pub(crate) fn nist_sp800_108_kdf_hmac_sha256(
#[cfg(test)]
mod tests {
use super::MsOapxbcSessionKey;
use super::{nist_sp800_108_kdf_hmac_sha256, AAD_KDF_LABEL};
use super::{AAD_KDF_LABEL, nist_sp800_108_kdf_hmac_sha256};
use crate::JwtError;
use crate::compact::JweAlg;
use crate::compact::JweCompact;
use crate::compact::JweEnc;
use crate::crypto::JweRSAOAEPEncipher;
use crate::crypto::hs256::JwsHs256Signer;
use crate::crypto::ms_oapxbc::JweA256GCMEncipher;
use crate::crypto::JweRSAOAEPEncipher;
use crate::jwe::Jwe;
use crate::jwe::JweBuilder;
use crate::jws::JwsBuilder;
use crate::traits::JweEncipherInnerA256;
use crate::traits::JwsVerifiable;
use crate::traits::JwsVerifier;
use crate::JwtError;
use base64::{engine::general_purpose, Engine as _};
use base64::{Engine as _, engine::general_purpose};
use crypto_glue::{
aes256::Aes256Key,
rsa::{RS256PrivateKey, RS256PublicKey},
traits::Pkcs1DecodeRsaPrivateKey,
};
use kanidm_hsm_crypto::{
AuthValue,
provider::{
// TpmMsExtensions,
SoftTpm,
Tpm,
TpmRS256,
},
AuthValue,
};
use std::str::FromStr;

Expand Down
12 changes: 6 additions & 6 deletions src/crypto/rs256.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//! JWS Signing and Verification Structures

use crate::KID_LEN;
use crate::compact::{JwaAlg, Jwk, JwkUse, JwsCompact, ProtectedHeader};
use crate::error::JwtError;
use crate::traits::*;
use crate::KID_LEN;
use base64::{engine::general_purpose, Engine as _};
use base64::{Engine as _, engine::general_purpose};
use crypto_glue::{
rsa::{
self, BigUint, RS256Digest, RS256PrivateKey, RS256PublicKey, RS256Signature,
Expand Down Expand Up @@ -120,8 +120,8 @@ impl JwsRs256Signer {
let public_key_e = self.skey.e().to_bytes_be();

Ok(Jwk::RSA {
n: public_key_n.into(),
e: public_key_e.into(),
n: public_key_n,
e: public_key_e,
alg: Some(JwaAlg::RS256),
use_: Some(JwkUse::Sig),
kid: Some(self.kid.clone()),
Expand Down Expand Up @@ -255,8 +255,8 @@ impl JwsRs256Verifier {
let public_key_e = self.pkey.e().to_bytes_be();

Ok(Jwk::RSA {
n: public_key_n.into(),
e: public_key_e.into(),
n: public_key_n,
e: public_key_e,
alg: Some(JwaAlg::RS256),
use_: Some(JwkUse::Sig),
kid: Some(self.kid.clone()),
Expand Down
12 changes: 6 additions & 6 deletions src/crypto/rsaes_oaep.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::JwtError;
use crate::compact::JweProtectedHeader;
use crate::compact::{JweAlg, JweCompact};
use crate::jwe::Jwe;
use crate::traits::{JweEncipherInnerA256, JweEncipherOuterA256};
use crate::JwtError;

use crypto_glue::{
aes256::{self, Aes256Key},
Expand Down Expand Up @@ -107,7 +107,7 @@ mod tests {
use crate::compact::JweCompact;
use crate::crypto::a256gcm::JweA256GCMEncipher;
use crate::jwe::JweBuilder;
use base64::{engine::general_purpose, Engine as _};
use base64::{Engine as _, engine::general_purpose};
use crypto_glue::rsa::{self, BigUint, RS256PrivateKey, RS256PublicKey};
use std::str::FromStr;

Expand Down Expand Up @@ -140,10 +140,10 @@ mod tests {
let test_jwe = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ";

let rsa_priv_key = rsa_from_private_components(
"oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUWcJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3Spsk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2asbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMStPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2djYgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw",
"AQAB",
"kLdtIj6GbDks_ApCSTYQtelcNttlKiOyPzMrXHeI-yk1F7-kpDxY4-WY5NWV5KntaEeXS1j82E375xxhWMHXyvjYecPT9fpwR_M9gV8n9Hrh2anTpTD93Dt62ypW3yDsJzBnTnrYu1iwWRgBKrEYY46qAZIrA2xAwnm2X7uGR1hghkqDp0Vqj3kbSCz1XyfCs6_LehBwtxHIyh8Ripy40p24moOAbgxVw3rxT_vlt3UVe4WO3JkJOzlpUf-KTVI2Ptgm-dARxTEtE-id-4OJr0h-K-VFs3VSndVTIznSxfyrj8ILL6MG_Uv8YAu7VILSB3lOW085-4qE3DzgrTjgyQ",
);
"oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUWcJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3Spsk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2asbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMStPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2djYgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw",
"AQAB",
"kLdtIj6GbDks_ApCSTYQtelcNttlKiOyPzMrXHeI-yk1F7-kpDxY4-WY5NWV5KntaEeXS1j82E375xxhWMHXyvjYecPT9fpwR_M9gV8n9Hrh2anTpTD93Dt62ypW3yDsJzBnTnrYu1iwWRgBKrEYY46qAZIrA2xAwnm2X7uGR1hghkqDp0Vqj3kbSCz1XyfCs6_LehBwtxHIyh8Ripy40p24moOAbgxVw3rxT_vlt3UVe4WO3JkJOzlpUf-KTVI2Ptgm-dARxTEtE-id-4OJr0h-K-VFs3VSndVTIznSxfyrj8ILL6MG_Uv8YAu7VILSB3lOW085-4qE3DzgrTjgyQ",
);

let jwec = JweCompact::from_str(test_jwe).expect("Unable to parse JWE");

Expand Down
Loading
Loading