build!: rename to -repaired suffix

This commit is contained in:
Matthieu Bessat 2025-06-03 16:14:04 +02:00
parent b4e4a4ad60
commit b95aaffe53
16 changed files with 8 additions and 8 deletions

View file

@ -0,0 +1,30 @@
[package]
name = "jsonwebkey-convert-repaired"
version = "0.3.1"
authors = ["Okamura Yasunobu <okamura@informationsea.info>"]
edition = "2018"
license = "Apache-2.0"
description = "Convert an RSA public key between Json Web Key and DER/PEM format (dependencies repaired)."
readme = "README.md"
homepage = "https://github.com/informationsea/jsonwebkey-rs"
repository = "https://github.com/informationsea/jsonwebkey-rs"
keywords = ["jsonwebkey", "jsonwebtoken"]
categories = ["authentication"]
[features]
default = []
full = ["jsonwebtoken", "pem_support"]
pem_support = ["simple_asn1", "pem"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
pem = { version = "0.8", optional = true }
jsonwebtoken = { version = "^7.2", optional = true }
simple_asn1 = { version = "^0.5.1", optional = true }
num-bigint = "^0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
base64 = "^0.13"
lazy_static = "1"
thiserror = "1"

View file

@ -0,0 +1,29 @@
# jsonwebkey-convert
Convert an RSA public key between Json Web Key and DER/PEM format.
## Convert PEM to JWK
``` rust
use jsonwebkey_convert::*;
use jsonwebkey_convert::der::FromPem;
fn main() -> Result<(), Error> {
let pem_data = include_str!("../testfiles/test1.pem");
let rsa_jwk = RSAPublicKey::from_pem(pem_data)?;
let jwk_byte_vec = serde_json::to_string(&rsa_jwk);
Ok(())
}
```
## Convert JWK to PEM
```rust
use jsonwebkey_convert::*;
use jsonwebkey_convert::der::ToPem;
fn main() -> Result<(), Error> {
let jwk_data = include_str!("../testfiles/test1.json");
let rsa_jwk: RSAPublicKey = jwk_data.parse()?;
let pem_data = rsa_jwk.to_pem()?;
Ok(())
}
```

View file

@ -0,0 +1,170 @@
use super::*;
use lazy_static::lazy_static;
use num_bigint::ToBigInt;
use simple_asn1::{oid, ASN1Block, BigUint, OID};
lazy_static! {
static ref RSA_OID: simple_asn1::OID = oid!(1, 2, 840, 113549, 1, 1, 1);
}
pub trait ToPem {
fn to_der(&self) -> Result<Vec<u8>, Error>;
fn to_pem(&self) -> Result<String, Error> {
let der = self.to_der()?;
let pem = pem::Pem {
tag: "PUBLIC KEY".to_string(),
contents: der,
};
Ok(pem::encode(&pem))
}
}
impl ToPem for RSAPublicKey {
fn to_der(&self) -> Result<Vec<u8>, Error> {
let pubkey_asn1 = ASN1Block::Sequence(
0,
vec![
ASN1Block::Integer(0, self.n.big_uint.to_bigint().unwrap()),
ASN1Block::Integer(0, self.e.big_uint.to_bigint().unwrap()),
],
);
let pubkey_der = simple_asn1::to_der(&pubkey_asn1)?;
let asn1 = ASN1Block::Sequence(
0,
vec![
ASN1Block::Sequence(
0,
vec![
ASN1Block::ObjectIdentifier(0, RSA_OID.clone()),
ASN1Block::Null(0),
],
),
ASN1Block::BitString(0, pubkey_der.len() * 8, pubkey_der),
],
);
Ok(simple_asn1::to_der(&asn1)?)
}
}
pub trait FromPem: Sized {
fn from_pem<T: AsRef<[u8]>>(pem: T) -> Result<Self, Error> {
let data = pem::parse(pem)?;
Self::from_der(&data.contents)
}
fn from_der(der: &[u8]) -> Result<Self, Error>;
}
impl FromPem for RSAPublicKey {
fn from_der(der: &[u8]) -> Result<Self, Error> {
let ans1_block_vec = simple_asn1::from_der(der)?;
if ans1_block_vec.len() != 1 {
return Err(Error::PubKeyParse(
"Invalid number of sequence: length of 1ans1_block_vec is not 1",
));
}
let ans1_seq = if let ASN1Block::Sequence(_, d) = &ans1_block_vec[0] {
d
} else {
return Err(Error::PubKeyParse("Invalid format: 2"));
};
if ans1_seq.len() != 2 {
return Err(Error::PubKeyParse("Invalid number of sequence: 3"));
}
//println!("pubkey der: {:?}", ans1_seq);
let oid_seq = if let ASN1Block::Sequence(_, s) = &ans1_seq[0] {
s
} else {
return Err(Error::PubKeyParse("Invalid format: 3"));
};
let oid = if let ASN1Block::ObjectIdentifier(_, o) = &oid_seq[0] {
o
} else {
return Err(Error::PubKeyParse("Invalid format: 4"));
};
if oid != *RSA_OID {
return Err(Error::PubKeyParse("Invalid format: 5"));
}
let bit_string = if let ASN1Block::BitString(_, _, s) = &ans1_seq[1] {
s
} else {
return Err(Error::PubKeyParse("Invalid format: 6"));
};
let parsed_der = simple_asn1::from_der(&bit_string).map_err(Error::ANS1DecodeError)?;
if parsed_der.len() != 1 {
return Err(Error::PubKeyParse("Invalid format: 7"));
}
let pubkey_seq = if let ASN1Block::Sequence(_, s) = &parsed_der[0] {
s
} else {
return Err(Error::PubKeyParse("Invalid format: 8"));
};
if pubkey_seq.len() != 2 {
return Err(Error::PubKeyParse("Invalid format: 9"));
}
let n = if let ASN1Block::Integer(_, n) = &pubkey_seq[0] {
n
} else {
return Err(Error::PubKeyParse("Invalid format: 10"));
};
let e = if let ASN1Block::Integer(_, e) = &pubkey_seq[1] {
e
} else {
return Err(Error::PubKeyParse("Invalid format: 11"));
};
let rsa_pub_key = RSAPublicKey {
generic: Generic {
kty: KeyType::Rsa,
use_: None,
key_ops: None,
alg: None,
kid: None,
x5u: None,
x5c: None,
x5t: None,
x5t_s256: None,
},
e: e.to_biguint().unwrap().into(),
n: n.to_biguint().unwrap().into(),
};
Ok(rsa_pub_key)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_convert_to_pem1() {
let jwk: RSAPublicKey =
serde_json::from_str(include_str!("../testfiles/test1.json")).unwrap();
let pem = jwk.to_pem().unwrap();
let pem_expected = include_str!("../testfiles/test1.pem");
assert_eq!(pem, pem_expected);
}
#[test]
fn test_convert_to_pem2() {
let jwk: RSAPublicKey =
serde_json::from_str(include_str!("../testfiles/test2.json")).unwrap();
let pem = jwk.to_pem().unwrap();
let pem_expected = include_str!("../testfiles/test2.pem");
assert_eq!(pem, pem_expected);
}
#[test]
fn test_convert_from_pem1() {
let pem = include_str!("../testfiles/test1.pem");
let mut jwk = RSAPublicKey::from_pem(pem).unwrap();
jwk.generic.kid = Some("fe41cf0f-7901-489f-9d4e-1437d6c1aa1f".to_string());
let jwk_expected: RSAPublicKey =
serde_json::from_str(include_str!("../testfiles/test1.json")).unwrap();
assert_eq!(jwk, jwk_expected);
}
}

View file

@ -0,0 +1,12 @@
use super::*;
use jsonwebtoken::DecodingKey;
pub trait ToDecodingKey {
fn to_decoding_key(&'_ self) -> DecodingKey<'_>;
}
impl ToDecodingKey for RSAPublicKey {
fn to_decoding_key(&'_ self) -> DecodingKey<'_> {
DecodingKey::from_rsa_components(&self.n.base64, &self.e.base64)
}
}

View file

@ -0,0 +1,495 @@
//! # jsonwebkey-convert
//! Handle Json Web Key without nightly rust compiler.
//!
//! ## Load JSON Web Key Set
//!
//! ```
//! use jsonwebkey_convert::JsonWebKeySet;
//! # use jsonwebkey_convert::Error;
//!
//! # fn main() -> Result<(), Error> {
//! # let jwks_str = include_str!("../testfiles/example-public-key.json");
//! let jwks: JsonWebKeySet = jwks_str.parse()?;
//! # Ok(())
//! # }
//! ```
//!
//!
//! ## Convert PEM to JWK
//! `pem_support` feature is required.
//!
//! ```
//! use jsonwebkey_convert::*;
//! use jsonwebkey_convert::der::FromPem;
//!
//! # fn main() -> Result<(), Error> {
//! # let pem_data = include_str!("../testfiles/test1.pem");
//! let rsa_jwk = RSAPublicKey::from_pem(pem_data)?;
//! let jwk_byte_vec = serde_json::to_string(&rsa_jwk);
//! # Ok(())
//! # }
//! ```
//!
//! ## Convert JWK to PEM
//! `pem_support` feature is required.
//!
//! ```
//! use jsonwebkey_convert::*;
//! use jsonwebkey_convert::der::ToPem;
//!
//! # fn main() -> Result<(), Error> {
//! # let jwk_data = include_str!("../testfiles/test1.json");
//! let rsa_jwk: RSAPublicKey = jwk_data.parse()?;
//! let pem_data = rsa_jwk.to_pem()?;
//! # Ok(())
//! # }
//! ```
/// DER and PEM format support
#[cfg(feature = "simple_asn1")]
pub mod der;
/// Json Web Token support
#[cfg(feature = "jsonwebtoken")]
pub mod jwt;
use num_bigint::BigUint;
use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
use std::str::FromStr;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("Public Key Parse Error: {0}")]
PubKeyParse(&'static str),
#[cfg(feature = "simple_asn1")]
#[error(transparent)]
ANS1DecodeError(#[from] simple_asn1::ASN1DecodeErr),
#[cfg(feature = "simple_asn1")]
#[error(transparent)]
ANS1EncodeError(#[from] simple_asn1::ASN1EncodeErr),
#[error(transparent)]
#[cfg(feature = "pem")]
PEMParseError(#[from] pem::PemError),
#[error(transparent)]
Base64UrlError(#[from] base64::DecodeError),
#[error(transparent)]
JSONParseError(#[from] serde_json::Error),
}
/// A set of Json Web Keys
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct JsonWebKeySet {
pub keys: Vec<JsonWebKey>,
}
impl JsonWebKeySet {
pub fn from_bytes(data: &[u8]) -> Result<JsonWebKeySet, Error> {
Ok(serde_json::from_slice(data)?)
}
}
impl FromStr for JsonWebKeySet {
type Err = Error;
fn from_str(data: &str) -> Result<JsonWebKeySet, Error> {
Ok(serde_json::from_str(data)?)
}
}
/// A JSON Web Key
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum JsonWebKey {
ECPrivateKey {
#[serde(flatten)]
value: ECPrivateKey,
},
ECPublicKey {
#[serde(flatten)]
value: ECPublicKey,
},
RSAPrivateKey {
#[serde(flatten)]
value: Box<RSAPrivateKey>,
},
RSAPublicKey {
#[serde(flatten)]
value: RSAPublicKey,
},
SymmetricKey {
#[serde(flatten)]
value: SymmetricKey,
},
}
impl FromStr for JsonWebKey {
type Err = Error;
fn from_str(data: &str) -> Result<JsonWebKey, Error> {
Ok(serde_json::from_str(data)?)
}
}
impl JsonWebKey {
pub fn from_bytes(data: &[u8]) -> Result<JsonWebKey, Error> {
Ok(serde_json::from_slice(data)?)
}
pub fn ec_private_key(&self) -> Option<&ECPrivateKey> {
match self {
JsonWebKey::ECPrivateKey { value } => Some(value),
_ => None,
}
}
pub fn ec_public_key(&self) -> Option<&ECPublicKey> {
match self {
JsonWebKey::ECPublicKey { value } => Some(value),
_ => None,
}
}
pub fn rsa_private_key(&self) -> Option<&RSAPrivateKey> {
match self {
JsonWebKey::RSAPrivateKey { value } => Some(value),
_ => None,
}
}
pub fn rsa_public_key(&self) -> Option<&RSAPublicKey> {
match self {
JsonWebKey::RSAPublicKey { value } => Some(value),
_ => None,
}
}
pub fn symmetric_key(&self) -> Option<&SymmetricKey> {
match self {
JsonWebKey::SymmetricKey { value } => Some(value),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Copy, Serialize, Deserialize)]
pub enum ECCurveParameter {
#[serde(rename = "P-256")]
P256,
#[serde(rename = "P-384")]
P384,
#[serde(rename = "P-521")]
P521,
}
/// BASE64 encoded big integer
#[derive(Debug, Clone, PartialEq)]
pub struct Base64BigUint {
big_uint: BigUint,
base64: String,
}
impl Base64BigUint {
pub fn to_base64url(&self) -> String {
base64::encode_config(&self.big_uint.to_bytes_be(), base64::URL_SAFE_NO_PAD)
}
pub fn from_base64url(value: &str) -> Result<Self, Error> {
Ok(Base64BigUint {
big_uint: BigUint::from_bytes_be(&base64::decode_config(
value,
base64::URL_SAFE_NO_PAD,
)?),
base64: value.to_string(),
})
}
}
impl Into<BigUint> for Base64BigUint {
fn into(self) -> BigUint {
self.big_uint
}
}
impl Into<Base64BigUint> for BigUint {
fn into(self) -> Base64BigUint {
Base64BigUint {
base64: base64::encode_config(self.to_bytes_be(), base64::URL_SAFE_NO_PAD),
big_uint: self,
}
}
}
impl Serialize for Base64BigUint {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.to_base64url().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Base64BigUint {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
Ok(Base64BigUint::from_base64url(&value).map_err(|e| {
D::Error::custom(format!("failed to decode BASE64 URL: {} : {}", value, e))
})?)
}
}
// RFC 7518
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
//#[serde(deny_unknown_fields)]
pub struct ECPublicKey {
#[serde(flatten)]
pub generic: Generic,
pub crv: ECCurveParameter,
pub x: Base64BigUint,
#[serde(skip_serializing_if = "Option::is_none")]
pub y: Option<Base64BigUint>,
}
impl FromStr for ECPublicKey {
type Err = Error;
fn from_str(data: &str) -> Result<Self, Error> {
Ok(serde_json::from_str(data)?)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
//#[serde(deny_unknown_fields)]
pub struct ECPrivateKey {
#[serde(flatten)]
pub public_key: ECPublicKey,
pub d: Base64BigUint,
}
impl FromStr for ECPrivateKey {
type Err = Error;
fn from_str(data: &str) -> Result<Self, Error> {
Ok(serde_json::from_str(data)?)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
//#[serde(deny_unknown_fields)]
pub struct RSAPublicKey {
#[serde(flatten)]
pub generic: Generic,
pub n: Base64BigUint,
pub e: Base64BigUint,
}
impl FromStr for RSAPublicKey {
type Err = Error;
fn from_str(data: &str) -> Result<Self, Error> {
Ok(serde_json::from_str(data)?)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
//#[serde(deny_unknown_fields)]
pub struct RSAPrivateKey {
#[serde(flatten)]
pub public_key: RSAPublicKey,
pub d: Base64BigUint,
#[serde(flatten)]
pub optimizations: Option<RSAPrivateKeyOptimizations>,
pub oth: Option<Vec<RSAPrivateKeyOtherPrimesInfo>>,
}
impl FromStr for RSAPrivateKey {
type Err = Error;
fn from_str(data: &str) -> Result<Self, Error> {
Ok(serde_json::from_str(data)?)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
//#[serde(deny_unknown_fields)]
pub struct RSAPrivateKeyOptimizations {
pub p: Base64BigUint,
pub q: Base64BigUint,
pub dp: Base64BigUint,
pub dq: Base64BigUint,
pub qi: Base64BigUint,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
//#[serde(deny_unknown_fields)]
pub struct RSAPrivateKeyOtherPrimesInfo {
pub r: Base64BigUint,
pub d: Base64BigUint,
pub t: Base64BigUint,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SymmetricKey {
#[serde(flatten)]
pub generic: Generic,
pub k: String,
}
impl FromStr for SymmetricKey {
type Err = Error;
fn from_str(data: &str) -> Result<Self, Error> {
Ok(serde_json::from_str(data)?)
}
}
/// A type of JWK.
/// See RFC 7518 Section 6.1.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum KeyType {
#[serde(rename = "EC")]
EllipticCurve,
#[serde(rename = "RSA")]
Rsa,
#[serde(rename = "oct")]
OctetSequence,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum KeyUse {
#[serde(rename = "sig")]
Signature,
#[serde(rename = "enc")]
Encryption,
}
/// Generic parameters for JSON Web Key.
/// See RFC 7517, Section 4.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Generic {
// Generic parameters
pub kty: KeyType,
#[serde(skip_serializing_if = "Option::is_none", rename = "use")]
pub use_: Option<KeyUse>,
#[serde(skip_serializing_if = "Option::is_none")]
pub key_ops: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub alg: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub kid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub x5u: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub x5c: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub x5t: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "x5t#S256")]
pub x5t_s256: Option<String>,
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn load_rsa_pubkey1() -> Result<(), serde_json::Error> {
let pubkey_json: JsonWebKey =
serde_json::from_str(include_str!("../testfiles/test1.json"))?;
let pubkey_data = pubkey_json.rsa_public_key().unwrap();
assert_eq!(pubkey_data.generic.kty, KeyType::Rsa);
assert_eq!(pubkey_data.e.big_uint, BigUint::from(65537u64));
Ok(())
}
#[test]
fn load_rsa_pubkey2() -> Result<(), serde_json::Error> {
let pubkey_json: JsonWebKey =
serde_json::from_str(include_str!("../testfiles/test2.json"))?;
let pubkey_data = pubkey_json.rsa_public_key().unwrap();
assert_eq!(pubkey_data.generic.kty, KeyType::Rsa);
assert_eq!(pubkey_data.generic.alg.as_ref().unwrap(), "RS256");
assert_eq!(pubkey_data.generic.use_.unwrap(), KeyUse::Signature);
assert_eq!(
pubkey_data.generic.kid.as_ref().unwrap(),
"ctFNPw6mrKynlD3atDovZGBlbWRXj7IK0IBODJ_hqeI"
);
assert_eq!(
pubkey_data.generic.x5t.as_ref().unwrap(),
"ZsHe1ebgPQqmqNF8rjKqWEjh4hk"
);
assert_eq!(
pubkey_data.generic.x5t_s256.as_ref().unwrap(),
"VaYCCwkyvl8K71fldYXJtNjHAPTGom2ylqdAbedtKUI"
);
assert_eq!(pubkey_data.e.big_uint, BigUint::from(65537u64));
Ok(())
}
#[test]
fn load_private_keys() -> Result<(), serde_json::Error> {
let privkey_json: JsonWebKeySet =
serde_json::from_str(include_str!("../testfiles/example-private-key.json"))?;
assert_eq!(privkey_json.keys.len(), 2);
let ec_private_key = privkey_json.keys[0].ec_private_key().unwrap();
assert_eq!(
ec_private_key.public_key.generic.kty,
KeyType::EllipticCurve
);
assert_eq!(ec_private_key.public_key.crv, ECCurveParameter::P256);
assert_eq!(
ec_private_key.public_key.generic.use_.unwrap(),
KeyUse::Encryption
);
assert_eq!(ec_private_key.public_key.generic.kid.as_ref().unwrap(), "1");
let rsa_private_key = privkey_json.keys[1].rsa_private_key().unwrap();
assert_eq!(rsa_private_key.public_key.generic.kty, KeyType::Rsa);
assert!(rsa_private_key.optimizations.is_some());
Ok(())
}
#[test]
fn load_public_keys() -> Result<(), serde_json::Error> {
let pubkey_json: JsonWebKeySet =
serde_json::from_str(include_str!("../testfiles/example-public-key.json"))?;
let ec_public_key = pubkey_json.keys[0].ec_public_key().unwrap();
assert_eq!(ec_public_key.generic.kty, KeyType::EllipticCurve);
assert_eq!(ec_public_key.crv, ECCurveParameter::P256);
assert_eq!(ec_public_key.generic.use_.unwrap(), KeyUse::Encryption);
assert_eq!(ec_public_key.generic.kid.as_ref().unwrap(), "1");
assert_eq!(
ec_public_key.x.to_base64url(),
"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4"
);
assert_eq!(
ec_public_key.y.as_ref().unwrap().to_base64url(),
"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"
);
let rsa_public_key = pubkey_json.keys[1].rsa_public_key().unwrap();
assert_eq!(rsa_public_key.generic.kty, KeyType::Rsa);
assert_eq!(rsa_public_key.e.to_base64url(), "AQAB");
assert_eq!(rsa_public_key.n.to_base64url(), "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw");
assert_eq!(rsa_public_key.generic.alg.as_ref().unwrap(), "RS256");
Ok(())
}
#[test]
fn load_symmetric_keys() -> Result<(), serde_json::Error> {
let symmetric_json: JsonWebKeySet =
serde_json::from_str(include_str!("../testfiles/example-symmetric-keys.json"))?;
let symmetric_key = symmetric_json.keys[0].symmetric_key().unwrap();
assert_eq!(symmetric_key.generic.kty, KeyType::OctetSequence);
assert_eq!(symmetric_key.generic.alg.as_ref().unwrap(), "A128KW");
assert_eq!(symmetric_key.k, "GawgguFyGrWKav7AX4VKUg");
let symmetric_key = symmetric_json.keys[1].symmetric_key().unwrap();
assert_eq!(symmetric_key.generic.kty, KeyType::OctetSequence);
assert_eq!(symmetric_key.k, "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow");
assert_eq!(
symmetric_key.generic.kid.as_ref().unwrap(),
"HMAC key used in JWS spec Appendix A.1 example"
);
Ok(())
}
}

View file

@ -0,0 +1,26 @@
{
"keys": [
{
"kty": "EC",
"crv": "P-256",
"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
"d": "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE",
"use": "enc",
"kid": "1"
},
{
"kty": "RSA",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e": "AQAB",
"d": "X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q",
"p": "83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs",
"q": "3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk",
"dp": "G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0",
"dq": "s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk",
"qi": "GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU",
"alg": "RS256",
"kid": "2011-04-29"
}
]
}

View file

@ -0,0 +1,19 @@
{
"keys": [
{
"kty": "EC",
"crv": "P-256",
"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
"use": "enc",
"kid": "1"
},
{
"kty": "RSA",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e": "AQAB",
"alg": "RS256",
"kid": "2011-04-29"
}
]
}

View file

@ -0,0 +1,14 @@
{
"keys": [
{
"kty": "oct",
"alg": "A128KW",
"k": "GawgguFyGrWKav7AX4VKUg"
},
{
"kty": "oct",
"k": "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow",
"kid": "HMAC key used in JWS spec Appendix A.1 example"
}
]
}

View file

@ -0,0 +1,6 @@
{
"kty": "RSA",
"e": "AQAB",
"kid": "fe41cf0f-7901-489f-9d4e-1437d6c1aa1f",
"n": "rAINWn65QjweP2o9mzZF0dj1V_qlyBs9anRd_OA_iJUk2vTXU9FrzPl1AT8xT570ZGq7UW_dLE-ANUcL10Xr2I-bzVL9IL6aYnjO9L_lqbilfScfJSfT81Oho-vnj5FJH1LaD6s90vStEcSH49kwNoDDK9BXYovFEtxFeFx-H0eRoxHdxo7_91YBPyez4JjBYrBs29Sro2DbVSRxaW384HWXhEYNtGp2Z3Qf22t2o4tUkfxs_fuaU24mwKCWykfnQ5Cq8V7NAIqgWxhVsubjy9yCZ0kFxCNf_cs9hkWIYtVNSDjFg9P30bwy1-37Y01Lb4KVBW6fN7whCq_y-NlJWQ"
}

View file

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArAINWn65QjweP2o9mzZF
0dj1V/qlyBs9anRd/OA/iJUk2vTXU9FrzPl1AT8xT570ZGq7UW/dLE+ANUcL10Xr
2I+bzVL9IL6aYnjO9L/lqbilfScfJSfT81Oho+vnj5FJH1LaD6s90vStEcSH49kw
NoDDK9BXYovFEtxFeFx+H0eRoxHdxo7/91YBPyez4JjBYrBs29Sro2DbVSRxaW38
4HWXhEYNtGp2Z3Qf22t2o4tUkfxs/fuaU24mwKCWykfnQ5Cq8V7NAIqgWxhVsubj
y9yCZ0kFxCNf/cs9hkWIYtVNSDjFg9P30bwy1+37Y01Lb4KVBW6fN7whCq/y+NlJ
WQIDAQAB
-----END PUBLIC KEY-----

View file

@ -0,0 +1,13 @@
{
"kid": "ctFNPw6mrKynlD3atDovZGBlbWRXj7IK0IBODJ_hqeI",
"kty": "RSA",
"alg": "RS256",
"use": "sig",
"n": "r3tms5oOWdyOO-XqMdNkLdp7tm5Eb7kY2ENPCCt-bpU6pC1-QOO3dfTs9LeiyeyonZpqD93ghW1pe5LB49rt1e2BqPNZdndGJZWmtAlv9YXCkLKat6GaG2e7gNzuq7Ls-my-vAYmS6B71KpkBTze2S3KcTjTEP6tPbJzgqZ6vPNK3EYbdCPZHi-QujRmGWUBeUdwsOnGWslaVlmkd4nIeqWYjV-mFD07WwB1y-pWBlC39A_RY4XUGP8WFxd0RSFNy3EoJw1yDK6_-1_xZZfzlRn0JpZsl6p-8zI8FgvMpQmXTSiAgfhYJGhBRZuvOPUrHBhwNE0GeqYYbUiOsXQHiw",
"e": "AQAB",
"x5c": [
"MIIClTCCAX0CBgFzYPXiUDANBgkqhkiG9w0BAQsFADAOMQwwCgYDVQQDDAN2bmMwHhcNMjAwNzE4MDgwNDUzWhcNMzAwNzE4MDgwNjMzWjAOMQwwCgYDVQQDDAN2bmMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCve2azmg5Z3I475eox02Qt2nu2bkRvuRjYQ08IK35ulTqkLX5A47d19Oz0t6LJ7KidmmoP3eCFbWl7ksHj2u3V7YGo81l2d0Yllaa0CW/1hcKQspq3oZobZ7uA3O6rsuz6bL68BiZLoHvUqmQFPN7ZLcpxONMQ/q09snOCpnq880rcRht0I9keL5C6NGYZZQF5R3Cw6cZayVpWWaR3ich6pZiNX6YUPTtbAHXL6lYGULf0D9FjhdQY/xYXF3RFIU3LcSgnDXIMrr/7X/Fll/OVGfQmlmyXqn7zMjwWC8ylCZdNKICB+FgkaEFFm6849SscGHA0TQZ6phhtSI6xdAeLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBACRzkIzJcASypr/CVsI30JAQLfWHJWqBrPq3WEch9oCXQ6J567MNRptV40/rLqep6CizJxO+eogip7z/9cSyLGiZrz36YwNvxjzDw7MvwAgbSR18QRjMAzGhLm2EKdJWSpJXGFVfuzOHklEDstx0ZuNO11XgWrx7RZdeSQDyKEoQ1hJH0tc+8UCYRRZq3M1rm9obTWX+rLz5nmFFucn+4pjcfwl1wYFUWToEkOKHm4e45hDFXaX/Z3GmeCXhs8kdCtYMYKjNSMdAGc1/NCnNF56tUI3bIPbZqWtl5U+rI3Gzm6DX82DyVcwi/A0KltsB9yF335FsXFLneO51xTcFSR4="
],
"x5t": "ZsHe1ebgPQqmqNF8rjKqWEjh4hk",
"x5t#S256": "VaYCCwkyvl8K71fldYXJtNjHAPTGom2ylqdAbedtKUI"
}

View file

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3tms5oOWdyOO+XqMdNk
Ldp7tm5Eb7kY2ENPCCt+bpU6pC1+QOO3dfTs9LeiyeyonZpqD93ghW1pe5LB49rt
1e2BqPNZdndGJZWmtAlv9YXCkLKat6GaG2e7gNzuq7Ls+my+vAYmS6B71KpkBTze
2S3KcTjTEP6tPbJzgqZ6vPNK3EYbdCPZHi+QujRmGWUBeUdwsOnGWslaVlmkd4nI
eqWYjV+mFD07WwB1y+pWBlC39A/RY4XUGP8WFxd0RSFNy3EoJw1yDK6/+1/xZZfz
lRn0JpZsl6p+8zI8FgvMpQmXTSiAgfhYJGhBRZuvOPUrHBhwNE0GeqYYbUiOsXQH
iwIDAQAB
-----END PUBLIC KEY-----