1
0
mirror of https://github.com/BitskiCo/jwk-rs synced 2024-11-22 03:49:22 +00:00

Add x509 registered claims

This commit is contained in:
Nick Hynes 2021-01-25 21:06:26 +03:00
parent 9592cad01c
commit 0d890ca6d7
No known key found for this signature in database
GPG Key ID: 5B3463E9F1D73C83
2 changed files with 79 additions and 10 deletions

View File

@ -93,6 +93,42 @@ pub struct JsonWebKey {
#[serde(default, rename = "alg", skip_serializing_if = "Option::is_none")] #[serde(default, rename = "alg", skip_serializing_if = "Option::is_none")]
pub algorithm: Option<Algorithm>, pub algorithm: Option<Algorithm>,
#[serde(default, flatten, skip_serializing_if = "X509Params::is_empty")]
pub x5: X509Params,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct X509Params {
/// x5u: The URL of the X.509 cert corresponding to this key.
#[serde(default, rename = "x5u", skip_serializing_if = "Option::is_none")]
url: Option<String>,
/// x5c: The certificate chain used to verify this key.
#[serde(default, rename = "x5c", skip_serializing_if = "Option::is_none")]
cert_chain: Option<String>,
/// x5t: The SHA-1 thumbprint of the DER-encoded X.509 version of the public key.
#[serde(default, rename = "x5t", skip_serializing_if = "Option::is_none")]
thumbprint: Option<String>,
/// x5t#S256: The same data as the thumbprint, but digested using SHA-256
#[serde(default, rename = "x5t#S256", skip_serializing_if = "Option::is_none")]
thumbprint_sha256: Option<String>,
}
impl X509Params {
fn is_empty(&self) -> bool {
matches!(
self,
X509Params {
url: None,
cert_chain: None,
thumbprint: None,
thumbprint_sha256: None,
}
)
}
} }
impl JsonWebKey { impl JsonWebKey {
@ -103,6 +139,7 @@ impl JsonWebKey {
key_ops: KeyOps::empty(), key_ops: KeyOps::empty(),
key_id: None, key_id: None,
algorithm: None, algorithm: None,
x5: Default::default(),
} }
} }
@ -184,17 +221,15 @@ impl Key {
/// Returns true iff this key only contains private components (i.e. a private asymmetric /// Returns true iff this key only contains private components (i.e. a private asymmetric
/// key or a symmetric key). /// key or a symmetric key).
pub fn is_private(&self) -> bool { pub fn is_private(&self) -> bool {
match self { matches!(self, Self::Symmetric { .. }
Self::Symmetric { .. } | Self::EC {
| Self::EC { curve: Curve::P256 { d: Some(_), .. },
curve: Curve::P256 { d: Some(_), .. }, ..
..
}
| Self::RSA {
private: Some(_), ..
} => true,
_ => false,
} }
| Self::RSA {
private: Some(_), ..
}
)
} }
/// Returns the public part of this key (symmetric keys have no public parts). /// Returns the public part of this key (symmetric keys have no public parts).

View File

@ -64,6 +64,7 @@ fn deserialize_es256() {
key_id: Some("a key".into()), key_id: Some("a key".into()),
key_ops: KeyOps::empty(), key_ops: KeyOps::empty(),
key_use: Some(KeyUse::Encryption), key_use: Some(KeyUse::Encryption),
x5: Default::default(),
} }
); );
} }
@ -82,6 +83,7 @@ fn serialize_es256() {
algorithm: None, algorithm: None,
key_ops: KeyOps::empty(), key_ops: KeyOps::empty(),
key_use: None, key_use: None,
x5: Default::default(),
}; };
assert_eq!( assert_eq!(
jwk.to_string(), jwk.to_string(),
@ -135,6 +137,7 @@ fn deserialize_hs256() {
key_id: None, key_id: None,
key_ops: KeyOps::SIGN | KeyOps::VERIFY, key_ops: KeyOps::SIGN | KeyOps::VERIFY,
key_use: None, key_use: None,
x5: Default::default(),
} }
); );
} }
@ -149,6 +152,7 @@ fn serialize_hs256() {
algorithm: None, algorithm: None,
key_ops: KeyOps::empty(), key_ops: KeyOps::empty(),
key_use: None, key_use: None,
x5: Default::default(),
}; };
assert_eq!( assert_eq!(
jwk.to_string(), jwk.to_string(),
@ -225,6 +229,7 @@ fn deserialize_rs256() {
key_id: None, key_id: None,
key_ops: KeyOps::WRAP_KEY, key_ops: KeyOps::WRAP_KEY,
key_use: Some(KeyUse::Encryption), key_use: Some(KeyUse::Encryption),
x5: Default::default(),
} }
); );
} }
@ -250,6 +255,7 @@ fn serialize_rs256() {
algorithm: None, algorithm: None,
key_ops: KeyOps::empty(), key_ops: KeyOps::empty(),
key_use: None, key_use: None,
x5: Default::default(),
}; };
assert_eq!( assert_eq!(
jwk.to_string(), jwk.to_string(),
@ -413,3 +419,31 @@ fn rsa_is_private() {
assert!(!public_jwk.key.is_private()); assert!(!public_jwk.key.is_private());
assert!(!public_jwk.key.to_public().unwrap().is_private()); assert!(!public_jwk.key.to_public().unwrap().is_private());
} }
#[test]
fn x509_params() {
let private_jwk = JsonWebKey::from_str(RSA_JWK_FIXTURE).unwrap();
assert!(private_jwk.key.is_private());
assert!(!private_jwk.key.to_public().unwrap().is_private());
static X509_JWK_FIXTURE: &str = r#"{
"kty": "oct",
"k": "TdSBZdXL5n39JXlQc7QL3w",
"x5u": "https://example.com/testing.crt",
"x5c": "---BEGIN CERTIFICATE---...",
"x5t": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d",
"x5t#S256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}"#;
let jwk = JsonWebKey::from_str(X509_JWK_FIXTURE).unwrap();
assert_eq!(jwk.x5.url.unwrap(), "https://example.com/testing.crt");
assert_eq!(jwk.x5.cert_chain.unwrap(), "---BEGIN CERTIFICATE---...");
assert_eq!(
jwk.x5.thumbprint.unwrap(),
"aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"
);
assert_eq!(
jwk.x5.thumbprint_sha256.unwrap(),
"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
);
}