Add types for JWK/JWKS based on biscuit (#195)
* Add types for JWK/JWKS based on biscuit * Address comments * Fix issues
This commit is contained in:
parent
94fef12259
commit
a11106faff
|
@ -51,7 +51,7 @@ jobs:
|
||||||
include:
|
include:
|
||||||
- build: pinned
|
- build: pinned
|
||||||
os: ubuntu-18.04
|
os: ubuntu-18.04
|
||||||
rust: 1.40.0
|
rust: 1.46.0
|
||||||
- build: stable
|
- build: stable
|
||||||
os: ubuntu-18.04
|
os: ubuntu-18.04
|
||||||
rust: stable
|
rust: stable
|
||||||
|
|
|
@ -7,7 +7,7 @@ readme = "README.md"
|
||||||
description = "Create and decode JWTs in a strongly typed way."
|
description = "Create and decode JWTs in a strongly typed way."
|
||||||
homepage = "https://github.com/Keats/jsonwebtoken"
|
homepage = "https://github.com/Keats/jsonwebtoken"
|
||||||
repository = "https://github.com/Keats/jsonwebtoken"
|
repository = "https://github.com/Keats/jsonwebtoken"
|
||||||
keywords = ["jwt", "web", "api", "token", "jwk"]
|
keywords = ["jwt", "api", "token", "jwk"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
include = ["src/**/*", "benches/**/*", "tests/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
|
include = ["src/**/*", "benches/**/*", "tests/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ jsonwebtoken = "7"
|
||||||
serde = {version = "1.0", features = ["derive"] }
|
serde = {version = "1.0", features = ["derive"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
The minimum required Rust version is 1.40.
|
The minimum required Rust version is 1.46.
|
||||||
|
|
||||||
## Algorithms
|
## Algorithms
|
||||||
This library currently supports the following:
|
This library currently supports the following:
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/// Example for the backend to backend implementation
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use jsonwebtoken::jwk::AlgorithmParameters;
|
||||||
|
use jsonwebtoken::{decode, decode_header, jwk, DecodingKey, Validation};
|
||||||
|
|
||||||
|
const TOKEN: &str = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjFaNTdkX2k3VEU2S1RZNTdwS3pEeSJ9.eyJpc3MiOiJodHRwczovL2Rldi1kdXp5YXlrNC5ldS5hdXRoMC5jb20vIiwic3ViIjoiNDNxbW44c281R3VFU0U1N0Fkb3BhN09jYTZXeVNidmRAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZGV2LWR1enlheWs0LmV1LmF1dGgwLmNvbS9hcGkvdjIvIiwiaWF0IjoxNjIzNTg1MzAxLCJleHAiOjE2MjM2NzE3MDEsImF6cCI6IjQzcW1uOHNvNUd1RVNFNTdBZG9wYTdPY2E2V3lTYnZkIiwic2NvcGUiOiJyZWFkOnVzZXJzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.0MpewU1GgvRqn4F8fK_-Eu70cUgWA5JJrdbJhkCPCxXP-8WwfI-qx1ZQg2a7nbjXICYAEl-Z6z4opgy-H5fn35wGP0wywDqZpqL35IPqx6d0wRvpPMjJM75zVXuIjk7cEhDr2kaf1LOY9auWUwGzPiDB_wM-R0uvUMeRPMfrHaVN73xhAuQWVjCRBHvNscYS5-i6qBQKDMsql87dwR72DgHzMlaC8NnaGREBC-xiSamesqhKPVyGzSkFSaF3ZKpGrSDapqmHkNW9RDBE3GQ9OHM33vzUdVKOjU1g9Leb9PDt0o1U4p3NQoGJPShQ6zgWSUEaqvUZTfkbpD_DoYDRxA";
|
||||||
|
const JWKS_REPLY: &str = r#"
|
||||||
|
{"keys":[{"alg":"RS256","kty":"RSA","use":"sig","n":"2V31IZF-EY2GxXQPI5OaEE--sezizPamNZDW9AjBE2cCErfufM312nT2jUsCnfjsXnh6Z_b-ncOMr97zIZkq1ofU7avemv8nX7NpKmoPBpVrMPprOax2-e3wt-bSfFLIHyghjFLKpkT0LOL_Fimi7xY-J86R06WHojLo3yGzAgQCswZmD4CFf6NcBWDcb6l6kx5vk_AdzHIkVEZH4aikUL_fn3zq5qbE25oOg6pT7F7Pp4zdHOAEKnIRS8tvP8tvvVRkUCrjBxz_Kx6Ne1YOD-fkIMRk_MgIWeKZZzZOYx4VrC0vqYiM-PcKWbNdt1kNoTHOeL06XZeSE6WPZ3VB1Q","e":"AQAB","kid":"1Z57d_i7TE6KTY57pKzDy","x5t":"1gA-aTE9VglLXZnrqvzwWhHsFdk","x5c":["MIIDDTCCAfWgAwIBAgIJHwhLfcIbNvmkMA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMTGWRldi1kdXp5YXlrNC5ldS5hdXRoMC5jb20wHhcNMjEwNjEzMDcxMTQ1WhcNMzUwMjIwMDcxMTQ1WjAkMSIwIAYDVQQDExlkZXYtZHV6eWF5azQuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2V31IZF+EY2GxXQPI5OaEE++sezizPamNZDW9AjBE2cCErfufM312nT2jUsCnfjsXnh6Z/b+ncOMr97zIZkq1ofU7avemv8nX7NpKmoPBpVrMPprOax2+e3wt+bSfFLIHyghjFLKpkT0LOL/Fimi7xY+J86R06WHojLo3yGzAgQCswZmD4CFf6NcBWDcb6l6kx5vk/AdzHIkVEZH4aikUL/fn3zq5qbE25oOg6pT7F7Pp4zdHOAEKnIRS8tvP8tvvVRkUCrjBxz/Kx6Ne1YOD+fkIMRk/MgIWeKZZzZOYx4VrC0vqYiM+PcKWbNdt1kNoTHOeL06XZeSE6WPZ3VB1QIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRPX3shmtgajnR4ly5t9VYB66ufGDAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAHtKpX70WU4uXOMjbFKj0e9HMXyCrdcX6TuYiMFqqlOGWM4yghSM8Bd0HkKcirm4DUoC+1dDMzXMZ+tbntavPt1xG0eRFjeocP+kIYTMQEG2LDM5HQ+Z7bdcwlxnuYOZQfpgKAfYbQ8Cxu38sB6q82I+5NJ0w0VXuG7nUZ1RD+rkXaeMYHNoibAtKBoTWrCaFWGV0E55OM+H0ckcHKUUnNXJOyZ+zEOzPFY5iuYIUmn1LfR1P0SLgIMfiooNC5ZuR/wLdbtyKtor2vzz7niEiewz+aPvfuPnWe/vMtQrfS37/yEhCozFnbIps/+S2Ay78mNBDuOAA9fg5yrnOmjABCU="]},{"alg":"RS256","kty":"RSA","use":"sig","n":"0KDpAuJZyDwPg9CfKi0R3QwDROyH0rvd39lmAoqQNqtYPghDToxFMDLpul0QHttbofHPJMKrPfeEFEOvw7KJgelCHZmckVKaz0e4tfu_2Uvw2kFljCmJGfspUU3mXxLyEea9Ef9JqUru6L8f_0_JIDMT3dceqU5ZqbG8u6-HRgRQ5Jqc_fF29Xyw3gxNP_Q46nsp_0yE68UZE1iPy1om0mpu8mpsY1-Nbvm51C8i4_tFQHdUXbhF4cjAoR0gZFNkzr7FCrL4On0hKeLcvxIHD17SxaBsTuCBGd35g7TmXsA4hSimD9taRHA-SkXh558JG5dr-YV9x80qjeSAvTyjcQ","e":"AQAB","kid":"v2HFn4VqJB-U4vtQRJ3Ql","x5t":"AhUBZjtsFdx7C1PFtWAJ756bo5k","x5c":["MIIDDTCCAfWgAwIBAgIJSSFLkuG8uAM8MA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMTGWRldi1kdXp5YXlrNC5ldS5hdXRoMC5jb20wHhcNMjEwNjEzMDcxMTQ2WhcNMzUwMjIwMDcxMTQ2WjAkMSIwIAYDVQQDExlkZXYtZHV6eWF5azQuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0KDpAuJZyDwPg9CfKi0R3QwDROyH0rvd39lmAoqQNqtYPghDToxFMDLpul0QHttbofHPJMKrPfeEFEOvw7KJgelCHZmckVKaz0e4tfu/2Uvw2kFljCmJGfspUU3mXxLyEea9Ef9JqUru6L8f/0/JIDMT3dceqU5ZqbG8u6+HRgRQ5Jqc/fF29Xyw3gxNP/Q46nsp/0yE68UZE1iPy1om0mpu8mpsY1+Nbvm51C8i4/tFQHdUXbhF4cjAoR0gZFNkzr7FCrL4On0hKeLcvxIHD17SxaBsTuCBGd35g7TmXsA4hSimD9taRHA+SkXh558JG5dr+YV9x80qjeSAvTyjcQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSEkRwvkyYzzzY/jPd1n7/1VRQNdzAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAGtdl7QwzpaWZjbmd6UINAIlpuWIo2v4EJD9kGan/tUZTiUdBaJVwFHOkLRsbZHc5PmBB5IryjOcrqsmKvFdo6wUZA92qTuQVZrOTea07msOKSWE6yRUh1/VCXH2+vAiB9A4DFZ23WpZikBR+DmiD8NGwVgAwWw9jM6pe7ODY+qxFXGjQdTCHcDdbqG2160nKEHCBvjR1Sc/F0pzHPv8CBJCyGAPTCXX42sKZI92pPzdKSmNNijCuIEYLsjzKVxaUuwEqIshk3mYeu6im4VmXXFj+MlyMsusVWi2py7fGFadamzyiV/bxZe+4xzzrRG1Kow/WnVEizfTdEzFXO6YikE="]}]}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let jwks: jwk::JwkSet = serde_json::from_str(JWKS_REPLY).unwrap();
|
||||||
|
|
||||||
|
let header = decode_header(TOKEN)?;
|
||||||
|
let kid = match header.kid {
|
||||||
|
Some(k) => k,
|
||||||
|
None => return Err("Token doesn't have a `kid` header field".into()),
|
||||||
|
};
|
||||||
|
if let Some(j) = jwks.find(&kid) {
|
||||||
|
match j.algorithm {
|
||||||
|
AlgorithmParameters::RSA(ref rsa) => {
|
||||||
|
let decoding_key = DecodingKey::from_rsa_components(&rsa.n, &rsa.e).unwrap();
|
||||||
|
let mut validation = Validation::new(j.common.algorithm.unwrap());
|
||||||
|
validation.validate_exp = false;
|
||||||
|
let decoded_token =
|
||||||
|
decode::<HashMap<String, serde_json::Value>>(TOKEN, &decoding_key, &validation)
|
||||||
|
.unwrap();
|
||||||
|
println!("{:?}", decoded_token);
|
||||||
|
}
|
||||||
|
_ => unreachable!("this should be a RSA"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err("No matching JWK found for the given kid".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ pub(crate) enum AlgorithmFamily {
|
||||||
|
|
||||||
/// The algorithms supported for signing/verifying JWTs
|
/// The algorithms supported for signing/verifying JWTs
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
#[derive(Debug, PartialEq, Hash, Copy, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
|
||||||
pub enum Algorithm {
|
pub enum Algorithm {
|
||||||
/// HMAC using SHA-256
|
/// HMAC using SHA-256
|
||||||
HS256,
|
HS256,
|
||||||
|
|
|
@ -79,7 +79,6 @@ impl DecodingKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If you have (n, e) RSA public key components already decoded, use this.
|
/// If you have (n, e) RSA public key components already decoded, use this.
|
||||||
/// TODO: do we need that?
|
|
||||||
pub fn from_rsa_raw_components(modulus: &[u8], exponent: &[u8]) -> Self {
|
pub fn from_rsa_raw_components(modulus: &[u8], exponent: &[u8]) -> Self {
|
||||||
DecodingKey {
|
DecodingKey {
|
||||||
family: AlgorithmFamily::Rsa,
|
family: AlgorithmFamily::Rsa,
|
||||||
|
@ -132,7 +131,7 @@ impl DecodingKey {
|
||||||
}
|
}
|
||||||
pub(crate) fn as_bytes(&self) -> &[u8] {
|
pub(crate) fn as_bytes(&self) -> &[u8] {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
DecodingKeyKind::SecretOrDer(b) => &b,
|
DecodingKeyKind::SecretOrDer(b) => b,
|
||||||
DecodingKeyKind::RsaModulusExponent { .. } => unreachable!(),
|
DecodingKeyKind::RsaModulusExponent { .. } => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::algorithms::Algorithm;
|
use crate::algorithms::Algorithm;
|
||||||
use crate::errors::Result;
|
use crate::errors::Result;
|
||||||
|
use crate::jwk::Jwk;
|
||||||
use crate::serialization::b64_decode;
|
use crate::serialization::b64_decode;
|
||||||
|
|
||||||
/// A basic JWT header, the alg defaults to HS256 and typ is automatically
|
/// A basic JWT header, the alg defaults to HS256 and typ is automatically
|
||||||
/// set to `JWT`. All the other fields are optional.
|
/// set to `JWT`. All the other fields are optional.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Header {
|
pub struct Header {
|
||||||
/// The type of JWS: it can only be "JWT" here
|
/// The type of JWS: it can only be "JWT" here
|
||||||
///
|
///
|
||||||
|
@ -29,6 +30,11 @@ pub struct Header {
|
||||||
/// Defined in [RFC7515#4.1.2](https://tools.ietf.org/html/rfc7515#section-4.1.2).
|
/// Defined in [RFC7515#4.1.2](https://tools.ietf.org/html/rfc7515#section-4.1.2).
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub jku: Option<String>,
|
pub jku: Option<String>,
|
||||||
|
/// JSON Web Key
|
||||||
|
///
|
||||||
|
/// Defined in [RFC7515#4.1.3](https://tools.ietf.org/html/rfc7515#section-4.1.3).
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub jwk: Option<Jwk>,
|
||||||
/// Key ID
|
/// Key ID
|
||||||
///
|
///
|
||||||
/// Defined in [RFC7515#4.1.4](https://tools.ietf.org/html/rfc7515#section-4.1.4).
|
/// Defined in [RFC7515#4.1.4](https://tools.ietf.org/html/rfc7515#section-4.1.4).
|
||||||
|
@ -59,6 +65,7 @@ impl Header {
|
||||||
alg: algorithm,
|
alg: algorithm,
|
||||||
cty: None,
|
cty: None,
|
||||||
jku: None,
|
jku: None,
|
||||||
|
jwk: None,
|
||||||
kid: None,
|
kid: None,
|
||||||
x5u: None,
|
x5u: None,
|
||||||
x5c: None,
|
x5c: None,
|
||||||
|
|
|
@ -0,0 +1,357 @@
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
///! This crate contains types only for working JWK and JWK Sets
|
||||||
|
///! This is only meant to be used to deal with public JWK, not generate ones.
|
||||||
|
///! Most of the code in this file is taken from https://github.com/lawliet89/biscuit but
|
||||||
|
/// tweaked to remove the private bits as it's not the goal for this crate currently.
|
||||||
|
///!
|
||||||
|
use crate::Algorithm;
|
||||||
|
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// The intended usage of the public `KeyType`. This enum is serialized `untagged`
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
pub enum PublicKeyUse {
|
||||||
|
/// Indicates a public key is meant for signature verification
|
||||||
|
Signature,
|
||||||
|
/// Indicates a public key is meant for encryption
|
||||||
|
Encryption,
|
||||||
|
/// Other usage
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for PublicKeyUse {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let string = match *self {
|
||||||
|
PublicKeyUse::Signature => "sig",
|
||||||
|
PublicKeyUse::Encryption => "enc",
|
||||||
|
PublicKeyUse::Other(ref other) => other,
|
||||||
|
};
|
||||||
|
|
||||||
|
serializer.serialize_str(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for PublicKeyUse {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct PublicKeyUseVisitor;
|
||||||
|
impl<'de> de::Visitor<'de> for PublicKeyUseVisitor {
|
||||||
|
type Value = PublicKeyUse;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(formatter, "a string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(match v {
|
||||||
|
"sig" => PublicKeyUse::Signature,
|
||||||
|
"enc" => PublicKeyUse::Encryption,
|
||||||
|
other => PublicKeyUse::Other(other.to_string()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_string(PublicKeyUseVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Operations that the key is intended to be used for. This enum is serialized `untagged`
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
pub enum KeyOperations {
|
||||||
|
/// Computer digital signature or MAC
|
||||||
|
Sign,
|
||||||
|
/// Verify digital signature or MAC
|
||||||
|
Verify,
|
||||||
|
/// Encrypt content
|
||||||
|
Encrypt,
|
||||||
|
/// Decrypt content and validate decryption, if applicable
|
||||||
|
Decrypt,
|
||||||
|
/// Encrypt key
|
||||||
|
WrapKey,
|
||||||
|
/// Decrypt key and validate decryption, if applicable
|
||||||
|
UnwrapKey,
|
||||||
|
/// Derive key
|
||||||
|
DeriveKey,
|
||||||
|
/// Derive bits not to be used as a key
|
||||||
|
DeriveBits,
|
||||||
|
/// Other operation
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for KeyOperations {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let string = match *self {
|
||||||
|
KeyOperations::Sign => "sign",
|
||||||
|
KeyOperations::Verify => "verify",
|
||||||
|
KeyOperations::Encrypt => "encrypt",
|
||||||
|
KeyOperations::Decrypt => "decrypt",
|
||||||
|
KeyOperations::WrapKey => "wrapKey",
|
||||||
|
KeyOperations::UnwrapKey => "unwrapKey",
|
||||||
|
KeyOperations::DeriveKey => "deriveKey",
|
||||||
|
KeyOperations::DeriveBits => "deriveBits",
|
||||||
|
KeyOperations::Other(ref other) => other,
|
||||||
|
};
|
||||||
|
|
||||||
|
serializer.serialize_str(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for KeyOperations {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct KeyOperationsVisitor;
|
||||||
|
impl<'de> de::Visitor<'de> for KeyOperationsVisitor {
|
||||||
|
type Value = KeyOperations;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(formatter, "a string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(match v {
|
||||||
|
"sign" => KeyOperations::Sign,
|
||||||
|
"verify" => KeyOperations::Verify,
|
||||||
|
"encrypt" => KeyOperations::Encrypt,
|
||||||
|
"decrypt" => KeyOperations::Decrypt,
|
||||||
|
"wrapKey" => KeyOperations::WrapKey,
|
||||||
|
"unwrapKey" => KeyOperations::UnwrapKey,
|
||||||
|
"deriveKey" => KeyOperations::DeriveKey,
|
||||||
|
"deriveBits" => KeyOperations::DeriveBits,
|
||||||
|
other => KeyOperations::Other(other.to_string()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_string(KeyOperationsVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Common JWK parameters
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||||
|
pub struct CommonParameters {
|
||||||
|
/// The intended use of the public key. Should not be specified with `key_operations`.
|
||||||
|
/// See sections 4.2 and 4.3 of [RFC7517](https://tools.ietf.org/html/rfc7517).
|
||||||
|
#[serde(rename = "use", skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub public_key_use: Option<PublicKeyUse>,
|
||||||
|
|
||||||
|
/// The "key_ops" (key operations) parameter identifies the operation(s)
|
||||||
|
/// for which the key is intended to be used. The "key_ops" parameter is
|
||||||
|
/// intended for use cases in which public, private, or symmetric keys
|
||||||
|
/// may be present.
|
||||||
|
/// Should not be specified with `public_key_use`.
|
||||||
|
/// See sections 4.2 and 4.3 of [RFC7517](https://tools.ietf.org/html/rfc7517).
|
||||||
|
#[serde(rename = "key_ops", skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub key_operations: Option<Vec<KeyOperations>>,
|
||||||
|
|
||||||
|
/// The algorithm intended for use with the key
|
||||||
|
#[serde(rename = "alg", skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub algorithm: Option<Algorithm>,
|
||||||
|
|
||||||
|
/// The case sensitive Key ID for the key
|
||||||
|
#[serde(rename = "kid", skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub key_id: Option<String>,
|
||||||
|
|
||||||
|
/// X.509 Public key cerfificate URL. This is currently not implemented (correctly).
|
||||||
|
/// Serialized to `x5u`.
|
||||||
|
#[serde(rename = "x5u", skip_serializing_if = "Option::is_none")]
|
||||||
|
pub x509_url: Option<String>,
|
||||||
|
|
||||||
|
/// X.509 public key certificate chain. This is currently not implemented (correctly).
|
||||||
|
/// Serialized to `x5c`.
|
||||||
|
#[serde(rename = "x5c", skip_serializing_if = "Option::is_none")]
|
||||||
|
pub x509_chain: Option<Vec<String>>,
|
||||||
|
|
||||||
|
/// X.509 Certificate thumbprint. This is currently not implemented (correctly).
|
||||||
|
/// Also not implemented, is the SHA-256 thumbprint variant of this header.
|
||||||
|
/// Serialized to `x5t`.
|
||||||
|
// TODO: How to make sure the headers are mutually exclusive?
|
||||||
|
#[serde(rename = "x5t", skip_serializing_if = "Option::is_none")]
|
||||||
|
pub x509_fingerprint: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Key type value for an Elliptic Curve Key.
|
||||||
|
/// This single value enum is a workaround for Rust not supporting associated constants.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum EllipticCurveKeyType {
|
||||||
|
/// Key type value for an Elliptic Curve Key.
|
||||||
|
EC,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EllipticCurveKeyType {
|
||||||
|
fn default() -> Self {
|
||||||
|
EllipticCurveKeyType::EC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type of cryptographic curve used by a key. This is defined in
|
||||||
|
/// [RFC 7518 #7.6](https://tools.ietf.org/html/rfc7518#section-7.6)
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum EllipticCurve {
|
||||||
|
/// P-256 curve
|
||||||
|
#[serde(rename = "P-256")]
|
||||||
|
P256,
|
||||||
|
/// P-384 curve
|
||||||
|
#[serde(rename = "P-384")]
|
||||||
|
P384,
|
||||||
|
/// P-521 curve -- unsupported by `ring`.
|
||||||
|
#[serde(rename = "P-521")]
|
||||||
|
P521,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EllipticCurve {
|
||||||
|
fn default() -> Self {
|
||||||
|
EllipticCurve::P256
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parameters for an Elliptic Curve Key
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||||
|
pub struct EllipticCurveKeyParameters {
|
||||||
|
/// Key type value for an Elliptic Curve Key.
|
||||||
|
#[serde(rename = "kty")]
|
||||||
|
pub key_type: EllipticCurveKeyType,
|
||||||
|
/// The "crv" (curve) parameter identifies the cryptographic curve used
|
||||||
|
/// with the key.
|
||||||
|
#[serde(rename = "crv")]
|
||||||
|
pub curve: EllipticCurve,
|
||||||
|
/// The "x" (x coordinate) parameter contains the x coordinate for the
|
||||||
|
/// Elliptic Curve point.
|
||||||
|
pub x: String,
|
||||||
|
/// The "y" (y coordinate) parameter contains the y coordinate for the
|
||||||
|
/// Elliptic Curve point.
|
||||||
|
pub y: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Key type value for an RSA Key.
|
||||||
|
/// This single value enum is a workaround for Rust not supporting associated constants.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum RSAKeyType {
|
||||||
|
/// Key type value for an RSA Key.
|
||||||
|
RSA,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RSAKeyType {
|
||||||
|
fn default() -> Self {
|
||||||
|
RSAKeyType::RSA
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parameters for a RSA Key
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||||
|
pub struct RSAKeyParameters {
|
||||||
|
/// Key type value for a RSA Key
|
||||||
|
#[serde(rename = "kty")]
|
||||||
|
pub key_type: RSAKeyType,
|
||||||
|
|
||||||
|
/// The "n" (modulus) parameter contains the modulus value for the RSA
|
||||||
|
/// public key.
|
||||||
|
pub n: String,
|
||||||
|
|
||||||
|
/// The "e" (exponent) parameter contains the exponent value for the RSA
|
||||||
|
/// public key.
|
||||||
|
pub e: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Key type value for an Octet symmetric key.
|
||||||
|
/// This single value enum is a workaround for Rust not supporting associated constants.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum OctetKeyType {
|
||||||
|
/// Key type value for an Octet symmetric key.
|
||||||
|
#[serde(rename = "oct")]
|
||||||
|
Octet,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OctetKeyType {
|
||||||
|
fn default() -> Self {
|
||||||
|
OctetKeyType::Octet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parameters for an Octet Key
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||||
|
pub struct OctetKeyParameters {
|
||||||
|
/// Key type value for an Octet Key
|
||||||
|
#[serde(rename = "kty")]
|
||||||
|
pub key_type: OctetKeyType,
|
||||||
|
/// The octet key value
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Key type value for an Octet Key Pair.
|
||||||
|
/// This single value enum is a workaround for Rust not supporting associated constants.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum OctetKeyPairType {
|
||||||
|
/// Key type value for an Octet Key Pair.
|
||||||
|
#[serde(rename = "OKP")]
|
||||||
|
OctetKeyPair,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OctetKeyPairType {
|
||||||
|
fn default() -> Self {
|
||||||
|
OctetKeyPairType::OctetKeyPair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parameters for an Octet Key Pair
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||||
|
pub struct OctetKeyPairParameters {
|
||||||
|
/// Key type value for an Octet Key Pair
|
||||||
|
#[serde(rename = "kty")]
|
||||||
|
pub key_type: OctetKeyPairType,
|
||||||
|
/// The "crv" (curve) parameter identifies the cryptographic curve used
|
||||||
|
/// with the key.
|
||||||
|
#[serde(rename = "crv")]
|
||||||
|
pub curve: EllipticCurve,
|
||||||
|
/// The "x" parameter contains the base64 encoded public key
|
||||||
|
pub x: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Algorithm specific parameters
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum AlgorithmParameters {
|
||||||
|
EllipticCurve(EllipticCurveKeyParameters),
|
||||||
|
RSA(RSAKeyParameters),
|
||||||
|
OctetKey(OctetKeyParameters),
|
||||||
|
OctetKeyPair(OctetKeyPairParameters),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Jwk {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub common: CommonParameters,
|
||||||
|
/// Key algorithm specific parameters
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub algorithm: AlgorithmParameters,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A JWK set
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct JwkSet {
|
||||||
|
pub keys: Vec<Jwk>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JwkSet {
|
||||||
|
/// Find the key in the set that matches the given key id, if any.
|
||||||
|
pub fn find(&self, kid: &str) -> Option<&Jwk> {
|
||||||
|
self.keys
|
||||||
|
.iter()
|
||||||
|
.find(|jwk| jwk.common.key_id.is_some() && jwk.common.key_id.as_ref().unwrap() == kid)
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ mod encoding;
|
||||||
/// All the errors that can be encountered while encoding/decoding JWTs
|
/// All the errors that can be encountered while encoding/decoding JWTs
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
mod header;
|
mod header;
|
||||||
|
pub mod jwk;
|
||||||
mod pem;
|
mod pem;
|
||||||
mod serialization;
|
mod serialization;
|
||||||
mod validation;
|
mod validation;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use crate::errors::{ErrorKind, Result};
|
use crate::errors::{ErrorKind, Result};
|
||||||
|
|
||||||
use simple_asn1::{BigUint, OID};
|
|
||||||
|
|
||||||
/// Supported PEM files for EC and RSA Public and Private Keys
|
/// Supported PEM files for EC and RSA Public and Private Keys
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
enum PemType {
|
enum PemType {
|
||||||
|
|
Loading…
Reference in New Issue