Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
use jsonwebtoken::{Algorithm, TokenData, dangerous::insecure_decode};
use wasm_bindgen_test::wasm_bindgen_test;
#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
pub struct Claims {
sub: String,
aud: Vec<String>,
iat: i64,
exp: i64,
}
#[test]
#[wasm_bindgen_test]
fn dangerous_insecure_decode_valid_jwt() {
let token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IkRReWk2eEFmVVRPWmhJV2R5VWtKZTBFMUJmM1VXV05QIiwidHlwIjoiSldUIn0.eyJhdWQiOlsianNvbndlYnRva2VudGVzdCJdLCJleHAiOjE3NTk4MjYyMTcsImlhdCI6MTc1OTgyNTkxNywic3ViIjoic3BpZmZlOi8vZXhhbXBsZS5vcmcvdGVzdHNlcnZpY2UifQ.1qr1zmMM1hmF-sDZupGc7sT2zGQxl1hFfaUKFWz3UGUeJfUweZfFymGR4jIOJb9ywXmfaafGQbNypaHILPWpeXT8RB7GZ7APu09ZPFvLiKBqagCVWgwhXc30giYPfTq5iNct1ejdYgB1wLxtnrsDRoD_k3EMkB58pDz4H5ZFXc_3xB9TLGw2UdaZ7AloV1yFV6OC5PdleSKchb9E_WaBlbZWLjQNSLhN-YhCRLJ4K59lmL_Z2rnR2812kan8xicyxJAzZ6k0y6K8tpKxUhT--THz2ikUk_olOwDIMfjYe9xmAk-PVvIGwHUVR6fMYv74vhdpwVJACkI2U7HVUhRFkg";
let TokenData { header, claims } = insecure_decode::<Claims>(token).unwrap();
assert_eq!(Algorithm::RS256, header.alg);
assert_eq!("DQyi6xAfUTOZhIWdyUkJe0E1Bf3UWWNP".to_string(), header.kid.unwrap());
assert_eq!(Some("JWT".to_string()), header.typ);
assert_eq!(vec!["jsonwebtokentest"], claims.aud);
assert_eq!("spiffe://example.org/testservice", claims.sub);
assert_eq!(1759825917, claims.iat);
assert_eq!(1759826217, claims.exp);
}
#[test]
#[wasm_bindgen_test]
fn dangerous_insecure_decode_invalid_sig() {
let token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IkRReWk2eEFmVVRPWmhJV2R5VWtKZTBFMUJmM1VXV05QIiwidHlwIjoiSldUIn0.eyJhdWQiOlsianNvbndlYnRva2VudGVzdCJdLCJleHAiOjE3NTk4MjYyMTcsImlhdCI6MTc1OTgyNTkxNywic3ViIjoic3BpZmZlOi8vZXhhbXBsZS5vcmcvdGVzdHNlcnZpY2UifQ.sig";
let TokenData { header, claims } = insecure_decode::<Claims>(token).unwrap();
assert_eq!(Algorithm::RS256, header.alg);
assert_eq!("DQyi6xAfUTOZhIWdyUkJe0E1Bf3UWWNP".to_string(), header.kid.unwrap());
assert_eq!(Some("JWT".to_string()), header.typ);
assert_eq!(vec!["jsonwebtokentest"], claims.aud);
assert_eq!("spiffe://example.org/testservice", claims.sub);
assert_eq!(1759825917, claims.iat);
assert_eq!(1759826217, claims.exp);
}
#[test]
#[wasm_bindgen_test]
fn dangerous_insecure_decode_invalid_header() {
let token = "badz.eyJhdWQiOlsianNvbndlYnRva2VudGVzdCJdLCJleHAiOjE3NTk4MjYyMTcsImlhdCI6MTc1OTgyNTkxNywic3ViIjoic3BpZmZlOi8vZXhhbXBsZS5vcmcvdGVzdHNlcnZpY2UifQ.sig";
insecure_decode::<Claims>(token).unwrap_err();
}
#[test]
#[wasm_bindgen_test]
fn dangerous_insecure_decode_invalid_claims() {
let token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IkRReWk2eEFmVVRPWmhJV2R5VWtKZTBFMUJmM1VXV05QIiwidHlwIjoiSldUIn0.badz.sig";
insecure_decode::<Claims>(token).unwrap_err();
}
+193
View File
@@ -0,0 +1,193 @@
use serde::{Deserialize, Serialize};
#[cfg(feature = "use_pem")]
use time::OffsetDateTime;
use wasm_bindgen_test::wasm_bindgen_test;
use jsonwebtoken::{
Algorithm, DecodingKey, EncodingKey,
crypto::{sign, verify},
};
#[cfg(feature = "use_pem")]
use jsonwebtoken::{Header, Validation, decode, encode};
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Claims {
sub: String,
company: String,
exp: i64,
}
#[test]
#[wasm_bindgen_test]
fn round_trip_sign_verification_pk8() {
let privkey = include_bytes!("private_ecdsa_key.pk8");
let pubkey = include_bytes!("public_ecdsa_key.pk8");
let encrypted =
sign(b"hello world", &EncodingKey::from_ec_der(privkey), Algorithm::ES256).unwrap();
let is_valid =
verify(&encrypted, b"hello world", &DecodingKey::from_ec_der(pubkey), Algorithm::ES256)
.unwrap();
assert!(is_valid);
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn round_trip_sign_verification_pem() {
let privkey_pem = include_bytes!("private_ecdsa_key.pem");
let pubkey_pem = include_bytes!("public_ecdsa_key.pem");
let encrypted =
sign(b"hello world", &EncodingKey::from_ec_pem(privkey_pem).unwrap(), Algorithm::ES256)
.unwrap();
let is_valid = verify(
&encrypted,
b"hello world",
&DecodingKey::from_ec_pem(pubkey_pem).unwrap(),
Algorithm::ES256,
)
.unwrap();
assert!(is_valid);
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn round_trip_claim() {
let privkey_pem = include_bytes!("private_ecdsa_key.pem");
let pubkey_pem = include_bytes!("public_ecdsa_key.pem");
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let token = encode(
&Header::new(Algorithm::ES256),
&my_claims,
&EncodingKey::from_ec_pem(privkey_pem).unwrap(),
)
.unwrap();
let token_data = decode::<Claims>(
&token,
&DecodingKey::from_ec_pem(pubkey_pem).unwrap(),
&Validation::new(Algorithm::ES256),
)
.unwrap();
assert_eq!(my_claims, token_data.claims);
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn ec_x_y() {
let privkey = include_str!("private_ecdsa_key.pem");
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let x = "w7JAoU_gJbZJvV-zCOvU9yFJq0FNC_edCMRM78P8eQQ";
let y = "wQg1EytcsEmGrM70Gb53oluoDbVhCZ3Uq3hHMslHVb4";
let encrypted = encode(
&Header::new(Algorithm::ES256),
&my_claims,
&EncodingKey::from_ec_pem(privkey.as_ref()).unwrap(),
)
.unwrap();
let res = decode::<Claims>(
&encrypted,
&DecodingKey::from_ec_components(x, y).unwrap(),
&Validation::new(Algorithm::ES256),
);
assert!(res.is_ok());
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn ed_jwk() {
use jsonwebtoken::jwk::Jwk;
use serde_json::json;
let privkey = include_str!("private_ecdsa_key.pem");
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let jwk: Jwk = serde_json::from_value(json!({
"kty": "EC",
"crv": "P-256",
"x": "w7JAoU_gJbZJvV-zCOvU9yFJq0FNC_edCMRM78P8eQQ",
"y": "wQg1EytcsEmGrM70Gb53oluoDbVhCZ3Uq3hHMslHVb4",
"kid": "ec01",
"alg": "ES256",
"use": "sig"
}))
.unwrap();
let encrypted = encode(
&Header::new(Algorithm::ES256),
&my_claims,
&EncodingKey::from_ec_pem(privkey.as_ref()).unwrap(),
)
.unwrap();
let res = decode::<Claims>(
&encrypted,
&DecodingKey::from_jwk(&jwk).unwrap(),
&Validation::new(Algorithm::ES256),
);
assert!(res.is_ok());
}
// https://jwt.io/ is often used for examples so ensure their example works with jsonwebtoken
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn roundtrip_with_jwtio_example() {
// We currently do not support SEC1 so we use the converted PKCS8 formatted
let privkey_pem = include_bytes!("private_jwtio_pkcs8.pem");
let pubkey_pem = include_bytes!("public_jwtio.pem");
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let token = encode(
&Header::new(Algorithm::ES384),
&my_claims,
&EncodingKey::from_ec_pem(privkey_pem).unwrap(),
)
.unwrap();
let token_data = decode::<Claims>(
&token,
&DecodingKey::from_ec_pem(pubkey_pem).unwrap(),
&Validation::new(Algorithm::ES384),
)
.unwrap();
assert_eq!(my_claims, token_data.claims);
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn ec_jwk_from_key() {
use jsonwebtoken::jwk::Jwk;
use serde_json::json;
let privkey = include_str!("private_ecdsa_key.pem");
let encoding_key = EncodingKey::from_ec_pem(privkey.as_ref()).unwrap();
let jwk = Jwk::from_encoding_key(&encoding_key, Algorithm::ES256).unwrap();
assert_eq!(
jwk,
serde_json::from_value(json!({
"kty": "EC",
"crv": "P-256",
"x": "w7JAoU_gJbZJvV-zCOvU9yFJq0FNC_edCMRM78P8eQQ",
"y": "wQg1EytcsEmGrM70Gb53oluoDbVhCZ3Uq3hHMslHVb4",
"alg": "ES256",
}))
.unwrap()
);
}
@@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWTFfCGljY6aw3Hrt
kHmPRiazukxPLb6ilpRAewjW8nihRANCAATDskChT+Altkm9X7MI69T3IUmrQU0L
950IxEzvw/x5BMEINRMrXLBJhqzO9Bm+d6JbqA21YQmd1Kt4RzLJR1W+
-----END PRIVATE KEY-----
@@ -0,0 +1,6 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDCAHpFQ62QnGCEvYh/pE9QmR1C9aLcDItRbslbmhen/h1tt8AyMhske
enT+rAyyPhGgBwYFK4EEACKhZANiAAQLW5ZJePZzMIPAxMtZXkEWbDF0zo9f2n4+
T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw8lE5IPUWpgu553SteKigiKLU
PeNpbqmYZUkWGh3MLfVzLmx85ii2vMU=
-----END EC PRIVATE KEY-----
@@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCAHpFQ62QnGCEvYh/p
E9QmR1C9aLcDItRbslbmhen/h1tt8AyMhskeenT+rAyyPhGhZANiAAQLW5ZJePZz
MIPAxMtZXkEWbDF0zo9f2n4+T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw
8lE5IPUWpgu553SteKigiKLUPeNpbqmYZUkWGh3MLfVzLmx85ii2vMU=
-----END PRIVATE KEY-----
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEw7JAoU/gJbZJvV+zCOvU9yFJq0FN
C/edCMRM78P8eQTBCDUTK1ywSYaszvQZvneiW6gNtWEJndSreEcyyUdVvg==
-----END PUBLIC KEY-----
@@ -0,0 +1 @@
ò@¡Oà%¶I½_³ëÔ÷!I«AM ÷ÄLïÃüyÁ5+\°I†¬Îô¾w¢[¨
@@ -0,0 +1,5 @@
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEC1uWSXj2czCDwMTLWV5BFmwxdM6PX9p+
Pk9Yf9rIf374m5XP1U8q79dBhLSIuaojsvOT39UUcPJROSD1FqYLued0rXiooIii
1D3jaW6pmGVJFhodzC31cy5sfOYotrzF
-----END PUBLIC KEY-----
+140
View File
@@ -0,0 +1,140 @@
use serde::{Deserialize, Serialize};
#[cfg(feature = "use_pem")]
use time::OffsetDateTime;
use wasm_bindgen_test::wasm_bindgen_test;
use jsonwebtoken::{
Algorithm, DecodingKey, EncodingKey,
crypto::{sign, verify},
};
#[cfg(feature = "use_pem")]
use jsonwebtoken::{Header, Validation, decode, encode};
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Claims {
sub: String,
company: String,
exp: i64,
}
#[test]
#[wasm_bindgen_test]
fn round_trip_sign_verification_pk8() {
let privkey = include_bytes!("private_ed25519_key.pk8");
let pubkey = include_bytes!("public_ed25519_key.pk8");
let encrypted =
sign(b"hello world", &EncodingKey::from_ed_der(privkey), Algorithm::EdDSA).unwrap();
let is_valid =
verify(&encrypted, b"hello world", &DecodingKey::from_ed_der(pubkey), Algorithm::EdDSA)
.unwrap();
assert!(is_valid);
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn round_trip_sign_verification_pem() {
let privkey_pem = include_bytes!("private_ed25519_key.pem");
let pubkey_pem = include_bytes!("public_ed25519_key.pem");
let encrypted =
sign(b"hello world", &EncodingKey::from_ed_pem(privkey_pem).unwrap(), Algorithm::EdDSA)
.unwrap();
let is_valid = verify(
&encrypted,
b"hello world",
&DecodingKey::from_ed_pem(pubkey_pem).unwrap(),
Algorithm::EdDSA,
)
.unwrap();
assert!(is_valid);
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn round_trip_claim() {
let privkey_pem = include_bytes!("private_ed25519_key.pem");
let pubkey_pem = include_bytes!("public_ed25519_key.pem");
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let token = encode(
&Header::new(Algorithm::EdDSA),
&my_claims,
&EncodingKey::from_ed_pem(privkey_pem).unwrap(),
)
.unwrap();
let token_data = decode::<Claims>(
&token,
&DecodingKey::from_ed_pem(pubkey_pem).unwrap(),
&Validation::new(Algorithm::EdDSA),
)
.unwrap();
assert_eq!(my_claims, token_data.claims);
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn ed_x() {
let privkey = include_str!("private_ed25519_key.pem");
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let x = "2-Jj2UvNCvQiUPNYRgSi0cJSPiJI6Rs6D0UTeEpQVj8";
let encrypted = encode(
&Header::new(Algorithm::EdDSA),
&my_claims,
&EncodingKey::from_ed_pem(privkey.as_ref()).unwrap(),
)
.unwrap();
let res = decode::<Claims>(
&encrypted,
&DecodingKey::from_ed_components(x).unwrap(),
&Validation::new(Algorithm::EdDSA),
);
assert!(res.is_ok());
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn ed_jwk() {
use jsonwebtoken::jwk::Jwk;
use serde_json::json;
let privkey = include_str!("private_ed25519_key.pem");
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let jwk: Jwk = serde_json::from_value(json!({
"kty": "OKP",
"use": "sig",
"crv": "Ed25519",
"x": "2-Jj2UvNCvQiUPNYRgSi0cJSPiJI6Rs6D0UTeEpQVj8",
"kid": "ed01",
"alg": "EdDSA"
}))
.unwrap();
let encrypted = encode(
&Header::new(Algorithm::EdDSA),
&my_claims,
&EncodingKey::from_ed_pem(privkey.as_ref()).unwrap(),
)
.unwrap();
let res = decode::<Claims>(
&encrypted,
&DecodingKey::from_jwk(&jwk).unwrap(),
&Validation::new(Algorithm::EdDSA),
);
assert!(res.is_ok());
}
@@ -0,0 +1,3 @@
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIGrD/e7uKYqSY4twDEsRfMMuLSrODf14dpTiTK6K1YI0
-----END PRIVATE KEY-----
@@ -0,0 +1,3 @@
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA2+Jj2UvNCvQiUPNYRgSi0cJSPiJI6Rs6D0UTeEpQVj8=
-----END PUBLIC KEY-----
@@ -0,0 +1,2 @@
ÛâcÙKÍ
ô"PóXF¢ÑÂR>"Hé:ExJPV?
@@ -0,0 +1 @@
["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"]
@@ -0,0 +1,77 @@
-----BEGIN CERTIFICATE-----
MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVM
xITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR2
8gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExM
TYwMTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UE
CBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWR
keS5jb20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYW
RkeS5jb20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlc
nRpZmljYXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTt
wY6vj3D3HKrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqV
Tr9vcyOdQmVZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aL
GbqGmu75RpRSgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo
7RJlbmr2EkRTcDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgW
JCJjPOq8lh8BJ6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAw
EAAaOCATIwggEuMB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVH
SMEGDAWgBTSxLDSkdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEA
MDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWR
keS5jb20wRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2
RhZGR5LmNvbS9yZXBvc2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVH
SAAMDgwNgYIKwYBBQUHAgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j
b20vcmVwb3NpdG9yeTAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggE
BANKGwOy9+aG2Z+5mC6IGOgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPI
UyIXvJxwqoJKSQ3kbTJSMUA2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL
5CkKSkB2XIsKd83ASe8T+5o0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9
p0iRFEUOOjZv2kWzRaJBydTXRE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsx
uxN89txJx9OjxUUAiKEngHUuHqDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZ
EjYx8WnM25sgVjOuH0aBsXBTWVU+4=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Z
hbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIE
luYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb
24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x
IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDY
yMFoXDTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZS
BHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgM
iBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XC
APVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux
6wwdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLO
tXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWo
riMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZ
Eewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ
4EFgQU0sSw0pHUTBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBu
zEkMCIGA1UEBxMbVmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQK
Ew5WYWxpQ2VydCwgSW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2x
pY3kgVmFsaWRhdGlvbiBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudm
FsaWNlcnQuY29tLzEgMB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CA
QEwDwYDVR0TAQH/BAUwAwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGG
F2h0dHA6Ly9vY3NwLmdvZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA
6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybD
BLBgNVHSAERDBCMEAGBFUdIAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZ
mljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjAN
BgkqhkiG9w0BAQUFAAOBgQC1QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+
Sn1eocSxI0YGyeR+sBjUZsE4OWBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgM
QLARzLrUc+cb53S8wGd9D0VmsfSxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j
09VZw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ
0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNT
AzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0a
G9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkq
hkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE
5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTm
V0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZ
XJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQD
ExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9
AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5a
vIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zf
N1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwb
P7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQU
AA4GBADt/UG9vUJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQ
C1u+mNr0HZDzTuIYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMM
j4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
-----END CERTIFICATE-----
+40
View File
@@ -0,0 +1,40 @@
use base64::{Engine, engine::general_purpose::STANDARD};
use wasm_bindgen_test::wasm_bindgen_test;
use jsonwebtoken::Header;
static CERT_CHAIN: [&str; 3] = include!("cert_chain.json");
#[test]
#[wasm_bindgen_test]
fn x5c_der_empty_chain() {
let header = Header { x5c: None, ..Default::default() };
assert_eq!(header.x5c_der().unwrap(), None);
let header = Header { x5c: Some(Vec::new()), ..Default::default() };
assert_eq!(header.x5c_der().unwrap(), Some(Vec::new()));
}
#[test]
#[wasm_bindgen_test]
fn x5c_der_valid_chain() {
let der_chain: Vec<Vec<u8>> =
CERT_CHAIN.iter().map(|x| STANDARD.decode(x)).collect::<Result<_, _>>().unwrap();
let x5c = Some(CERT_CHAIN.iter().map(ToString::to_string).collect());
let header = Header { x5c, ..Default::default() };
assert_eq!(header.x5c_der().unwrap(), Some(der_chain));
}
#[test]
#[wasm_bindgen_test]
fn x5c_der_invalid_chain() {
let mut x5c: Vec<_> = CERT_CHAIN.iter().map(ToString::to_string).collect();
x5c.push("invalid base64 data".to_string());
let x5c = Some(x5c);
let header = Header { x5c, ..Default::default() };
assert!(header.x5c_der().is_err());
}
+348
View File
@@ -0,0 +1,348 @@
#![allow(deprecated)]
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use time::OffsetDateTime;
use wasm_bindgen_test::wasm_bindgen_test;
use jsonwebtoken::errors::ErrorKind;
use jsonwebtoken::jwk::Jwk;
use jsonwebtoken::{
Algorithm, DecodingKey, EncodingKey, Header, Validation,
crypto::{sign, verify},
decode, decode_header, encode,
};
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Claims {
sub: String,
company: String,
exp: i64,
}
#[test]
#[wasm_bindgen_test]
fn sign_hs256() {
let result =
sign(b"hello world", &EncodingKey::from_secret(b"secret"), Algorithm::HS256).unwrap();
let expected = "c0zGLzKEFWj0VxWuufTXiRMk5tlI5MbGDAYhzaxIYjo";
assert_eq!(result, expected);
}
#[test]
#[wasm_bindgen_test]
fn verify_hs256() {
let sig = "c0zGLzKEFWj0VxWuufTXiRMk5tlI5MbGDAYhzaxIYjo";
let valid = verify(sig, b"hello world", &DecodingKey::from_secret(b"secret"), Algorithm::HS256)
.unwrap();
assert!(valid);
}
#[test]
#[wasm_bindgen_test]
fn encode_with_custom_header() {
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let header = Header { kid: Some("kid".to_string()), ..Default::default() };
let token = encode(&header, &my_claims, &EncodingKey::from_secret(b"secret")).unwrap();
let token_data = decode::<Claims>(
&token,
&DecodingKey::from_secret(b"secret"),
&Validation::new(Algorithm::HS256),
)
.unwrap();
assert_eq!(my_claims, token_data.claims);
assert_eq!("kid", token_data.header.kid.unwrap());
assert!(token_data.header.extras.is_empty());
}
#[test]
#[wasm_bindgen_test]
fn encode_with_extra_custom_header() {
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let mut extras = HashMap::with_capacity(1);
extras.insert("custom".to_string(), "header".to_string());
let header = Header { kid: Some("kid".to_string()), extras, ..Default::default() };
let token = encode(&header, &my_claims, &EncodingKey::from_secret(b"secret")).unwrap();
let token_data = decode::<Claims>(
&token,
&DecodingKey::from_secret(b"secret"),
&Validation::new(Algorithm::HS256),
)
.unwrap();
assert_eq!(my_claims, token_data.claims);
assert_eq!("kid", token_data.header.kid.unwrap());
assert_eq!("header", token_data.header.extras.get("custom").unwrap().as_str());
}
#[test]
#[wasm_bindgen_test]
fn encode_with_multiple_extra_custom_headers() {
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let mut extras = HashMap::with_capacity(2);
extras.insert("custom1".to_string(), "header1".to_string());
extras.insert("custom2".to_string(), "header2".to_string());
let header = Header { kid: Some("kid".to_string()), extras, ..Default::default() };
let token = encode(&header, &my_claims, &EncodingKey::from_secret(b"secret")).unwrap();
let token_data = decode::<Claims>(
&token,
&DecodingKey::from_secret(b"secret"),
&Validation::new(Algorithm::HS256),
)
.unwrap();
assert_eq!(my_claims, token_data.claims);
assert_eq!("kid", token_data.header.kid.unwrap());
let extras = token_data.header.extras;
assert_eq!("header1", extras.get("custom1").unwrap().as_str());
assert_eq!("header2", extras.get("custom2").unwrap().as_str());
}
#[test]
#[wasm_bindgen_test]
fn round_trip_claim() {
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let token =
encode(&Header::default(), &my_claims, &EncodingKey::from_secret(b"secret")).unwrap();
let token_data = decode::<Claims>(
&token,
&DecodingKey::from_secret(b"secret"),
&Validation::new(Algorithm::HS256),
)
.unwrap();
assert_eq!(my_claims, token_data.claims);
assert!(token_data.header.kid.is_none());
}
#[test]
#[wasm_bindgen_test]
fn decode_token() {
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.9r56oF7ZliOBlOAyiOFperTGxBtPykRQiWNFxhDCW98";
let claims = decode::<Claims>(
token,
&DecodingKey::from_secret(b"secret"),
&Validation::new(Algorithm::HS256),
);
println!("{:?}", claims);
claims.unwrap();
}
#[test]
#[wasm_bindgen_test]
fn decode_token_custom_headers() {
let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsImN1c3RvbTEiOiJoZWFkZXIxIiwiY3VzdG9tMiI6ImhlYWRlcjIifQ.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.FtOHsoKcNH3SriK3tnR-uWJg4UV4FkOzvq_JCfLngfU";
let claims = decode::<Claims>(
token,
&DecodingKey::from_secret(b"secret"),
&Validation::new(Algorithm::HS256),
)
.unwrap();
let my_claims =
Claims { sub: "b@b.com".to_string(), company: "ACME".to_string(), exp: 2532524891 };
assert_eq!(my_claims, claims.claims);
assert_eq!("kid", claims.header.kid.unwrap());
let extras = claims.header.extras;
assert_eq!("header1", extras.get("custom1").unwrap().as_str());
assert_eq!("header2", extras.get("custom2").unwrap().as_str());
}
#[test]
#[wasm_bindgen_test]
#[should_panic(expected = "InvalidToken")]
fn decode_token_missing_parts() {
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
let claims = decode::<Claims>(
token,
&DecodingKey::from_secret(b"secret"),
&Validation::new(Algorithm::HS256),
);
claims.unwrap();
}
#[test]
#[wasm_bindgen_test]
fn decode_token_invalid_signature() {
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUifQ.Hm0yvKH25TavFPz7J_coST9lZFYH1hQo0tvhvImmaks";
let claims = decode::<Claims>(
token,
&DecodingKey::from_secret(b"secret"),
&Validation::new(Algorithm::HS256),
);
assert_eq!(claims.unwrap_err().into_kind(), ErrorKind::InvalidSignature);
}
#[test]
#[wasm_bindgen_test]
fn decode_token_wrong_algorithm() {
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUifQ.I1BvFoHe94AFf09O6tDbcSB8-jp8w6xZqmyHIwPeSdY";
let claims = decode::<Claims>(
token,
&DecodingKey::from_secret(b"secret"),
&Validation::new(Algorithm::RS512),
);
assert_eq!(claims.unwrap_err().into_kind(), ErrorKind::InvalidAlgorithm);
}
#[test]
#[wasm_bindgen_test]
fn encode_wrong_alg_family() {
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let claims = encode(&Header::default(), &my_claims, &EncodingKey::from_rsa_der(b"secret"));
assert_eq!(claims.unwrap_err().into_kind(), ErrorKind::InvalidAlgorithm);
}
#[test]
#[wasm_bindgen_test]
fn decode_token_with_bytes_secret() {
let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.Hm0yvKH25TavFPz7J_coST9lZFYH1hQo0tvhvImmaks";
let claims = decode::<Claims>(
token,
&DecodingKey::from_secret(b"\x01\x02\x03"),
&Validation::new(Algorithm::HS256),
);
assert!(claims.is_ok());
}
#[test]
#[wasm_bindgen_test]
fn decode_header_only() {
let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjb21wYW55IjoiMTIzNDU2Nzg5MCIsInN1YiI6IkpvaG4gRG9lIn0.S";
let header = decode_header(token).unwrap();
assert_eq!(header.alg, Algorithm::HS256);
assert_eq!(header.typ, Some("JWT".to_string()));
}
#[test]
#[wasm_bindgen_test]
fn dangerous_insecure_decode_valid_token() {
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.9r56oF7ZliOBlOAyiOFperTGxBtPykRQiWNFxhDCW98";
let mut validation = Validation::new(Algorithm::HS256);
validation.insecure_disable_signature_validation();
let claims = decode::<Claims>(token, &DecodingKey::from_secret(&[]), &validation);
claims.unwrap();
}
#[test]
#[wasm_bindgen_test]
fn dangerous_insecure_decode_token_invalid_signature() {
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.wrong";
let mut validation = Validation::new(Algorithm::HS256);
validation.insecure_disable_signature_validation();
let claims = decode::<Claims>(token, &DecodingKey::from_secret(&[]), &validation);
claims.unwrap();
}
#[test]
#[wasm_bindgen_test]
fn dangerous_insecure_decode_token_wrong_algorithm() {
let token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.fLxey-hxAKX5rNHHIx1_Ch0KmrbiuoakDVbsJjLWrx8fbjKjrPuWMYEJzTU3SBnYgnZokC-wqSdqckXUOunC-g";
let mut validation = Validation::new(Algorithm::HS256);
validation.insecure_disable_signature_validation();
let claims = decode::<Claims>(token, &DecodingKey::from_secret(&[]), &validation);
claims.unwrap();
}
#[test]
#[wasm_bindgen_test]
fn dangerous_insecure_decode_token_with_validation_wrong_algorithm() {
let token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjk1MzI1MjQ4OX0.ONtEUTtP1QmyksYH9ijtPCaXoHjZVHcHKZGX1DuJyPiSyKlT93Y-oKgrp_OSkHSu4huxCcVObLzwsdwF-xwiAQ";
let mut validation = Validation::new(Algorithm::HS256);
validation.insecure_disable_signature_validation();
let claims = decode::<Claims>(token, &DecodingKey::from_secret(&[]), &validation);
let err = claims.unwrap_err();
assert_eq!(err.kind(), &ErrorKind::ExpiredSignature);
}
#[test]
#[wasm_bindgen_test]
fn verify_hs256_rfc7517_appendix_a1() {
#[derive(Debug, PartialEq, Eq, Clone, Deserialize)]
struct C {
iss: String,
}
let token = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
let jwk = r#"{"kty":"oct",
"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
}"#;
let jwk: Jwk = serde_json::from_str(jwk).unwrap();
let key = DecodingKey::from_jwk(&jwk).unwrap();
let mut validation = Validation::new(Algorithm::HS256);
// The RFC example signed jwt has expired
validation.validate_exp = false;
let c = decode::<C>(token, &key, &validation).unwrap();
assert_eq!(c.claims.iss, "joe");
}
// Regression tests for type confusion vulnerability where malformed claims
// (eg nbf or exp as strings) were silently treated as "not present" when not required
#[derive(Debug, Serialize)]
struct ClaimsWithStringNbf {
sub: String,
nbf: String, // should be a number
}
#[derive(Debug, Serialize)]
struct ClaimsWithStringExp {
sub: String,
exp: String, // should be a number
}
#[test]
#[wasm_bindgen_test]
fn test_string_nbf_rejected_when_validate_nbf_enabled() {
// Create token with nbf as string (malformed)
let claims = ClaimsWithStringNbf {
sub: "test".to_string(),
nbf: "99999999999".to_string(), // Far future as string
};
let token = encode(&Header::default(), &claims, &EncodingKey::from_secret(b"secret")).unwrap();
let mut validation = Validation::new(Algorithm::HS256);
validation.validate_nbf = true;
validation.required_spec_claims = std::collections::HashSet::new();
let result =
decode::<serde_json::Value>(&token, &DecodingKey::from_secret(b"secret"), &validation);
assert!(result.is_err());
assert_eq!(result.unwrap_err().into_kind(), ErrorKind::InvalidClaimFormat("nbf".to_string()));
}
#[test]
#[wasm_bindgen_test]
fn test_string_exp_rejected_when_validate_exp_enabled() {
// Create token with exp as string (malformed)
let claims = ClaimsWithStringExp {
sub: "test".to_string(),
exp: "99999999999".to_string(), // Far future as string
};
let token = encode(&Header::default(), &claims, &EncodingKey::from_secret(b"secret")).unwrap();
let mut validation = Validation::new(Algorithm::HS256);
validation.validate_exp = true;
validation.required_spec_claims = std::collections::HashSet::new();
let result =
decode::<serde_json::Value>(&token, &DecodingKey::from_secret(b"secret"), &validation);
assert!(result.is_err());
assert_eq!(result.unwrap_err().into_kind(), ErrorKind::InvalidClaimFormat("exp".to_string()));
}
+5
View File
@@ -0,0 +1,5 @@
mod dangerous;
mod ecdsa;
mod eddsa;
mod header;
mod rsa;
+27
View File
@@ -0,0 +1,27 @@
# RSA Tests
## How to generate keys and certificates
### RSA PKCS1
```
openssl genrsa -out private_rsa_pkcs1.pem
openssl rsa -in private_rsa_pkcs1.pem -RSAPublicKey_out -out public_rsa_pkcs1.pem
openssl req -new -key private_rsa_pkcs1.pem -out certificate_rsa_pkcs1.csr
openssl x509 -req -sha256 -days 358000 -in certificate_rsa_pkcs1.csr -signkey private_rsa_pkcs1.pem -out certificate_rsa_pkcs1.crt
```
### RSA PKCS8
```
openssl genpkey -algorithm RSA -out private_rsa_pkcs8.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in private_rsa_pkcs8.pem -out public_rsa_pkcs.pem
openssl req -new -key private_rsa_pkcs8.key -out certificate_rsa_pkcs8.csr
openssl x509 -req -sha256 -days 358000 -in certificate_rsa_pkcs8.csr -signkey private_rsa_pkcs8.key -out certificate_rsa_pkcs8.crt
```
### Convert to DER format
```
openssl rsa -inform PEM -in private.pem -outform DER -out private.der
```
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDEzCCAfsCFC36imR60P89zge2Gw14moyfJE+hMA0GCSqGSIb3DQEBCwUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwIBcNMjIxMjAxMDgzNzM2WhgPMzAwMzAyMDIw
ODM3MzZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQCfPKKzVmN80HRsGAoUxK++RO3CW8GxomrtLnAD6TN5U5Wl
VbCRZ1WFrizfxcz+lr/Kvjtq/v7PdVOa8NHIAdxpP3bCFEQWku/1yPmVN4lKJvKv
8yub9i2MJlVaBo5giHCtfAouo+v/XWKdawCR8jK28dZPFlgRxcuABcW5S5pLe4X2
ASI1DDMZNTW/QWqSpMGvgHydbccI3jtdS7S3xjR76V/izg7FBrBYPv0n3/l3dHLS
9tXcCbUW0YmIm87BGwh9UKEOlhK1NwdMIyq29ZtXovXUFaSnMZdJbge/jepr4ZJg
4PZBTrwxvn2hKTY4H4G04ukmh+ZsYQaC+bDIIj0zAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBACPyDJXCWluYWIZZGeCandW9Sp51kPVPEAcDWJjz6wlSsoR38ZyQk4so
PcOrBc8tNxG7BYbzaSC31df4qvOeUM6j8A+WemtCUbB99TPBa26VyUNhkQGlqF0G
3dd6h0mCIu0aftD2aci4mDBll5D4Sl99eLq1w83yfYh2KTb8lgwsmckdU1XnWHjZ
Vg/N8FaqhIN1mqFY5LozPJUyX9G2vIZFA2D8jxc9S9lfosXG7j1VRJ0UIm60A7Kb
6y25m81IF1QVhDub7AVg7svyoV6tFBefuTdZzJG/gOx75eMdkI3BEBSEaw0I87Bx
Z5Qp99Qv3cs6tjUr8K0kwCbqeme5UxY=
-----END CERTIFICATE-----
@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAJ88orNWY3zQdGwYChTEr75E7cJbwbGiau0ucAPp
M3lTlaVVsJFnVYWuLN/FzP6Wv8q+O2r+/s91U5rw0cgB3Gk/dsIURBaS7/XI+ZU3
iUom8q/zK5v2LYwmVVoGjmCIcK18Ci6j6/9dYp1rAJHyMrbx1k8WWBHFy4AFxblL
mkt7hfYBIjUMMxk1Nb9BapKkwa+AfJ1txwjeO11LtLfGNHvpX+LODsUGsFg+/Sff
+Xd0ctL21dwJtRbRiYibzsEbCH1QoQ6WErU3B0wjKrb1m1ei9dQVpKcxl0luB7+N
6mvhkmDg9kFOvDG+faEpNjgfgbTi6SaH5mxhBoL5sMgiPTMCAwEAAaAAMA0GCSqG
SIb3DQEBCwUAA4IBAQCBHiYk5HH/5G/Nw49242mb4YAS7B3gBiNvop0/Jw62u/Ys
QFgaiKqPXg5un/dCvU3eoaBDKaQUhslzvya3ziKceEClJfk2w6kXSh8OU9l/39Cj
NEtNcpjlj427QWI7dQA83TrTNMokk5gUkgqnY6JDDzGfctlxN9J4iQC1E5hoTpos
rEjzBsVHg1h4iX7QoKO36O7S1jE/hCeFnWUPC9svqx22fyterA1Jl5W3LO7kQ8pf
SYZhjZqjfM7Bm+HcVotYNFcWkoqMQ60dOCA9QB38oPXHFlweD7oWRQX1P3y8W9pP
kXAuYCmWDze2K1ezWImKi9Atga+ByBf/JNBVVn/G
-----END CERTIFICATE REQUEST-----
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDEzCCAfsCFGRy3pRvxgdoKPiWJfvmDcJhcaYOMA0GCSqGSIb3DQEBCwUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwIBcNMjIxMjAxMDgzOTA3WhgPMzAwMzAyMDIw
ODM5MDdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDJETqse41HRBsc7cfcq3ak4oZWFCoZlcic525A3FfO4qW9
BMtRO/iXiyCCHn8JhiL9y8j5JdVP2Q9ZIpfElcFd3/guS9w+5RqQGgCR+H56IVUy
HZWtTJbKPcwWXQdNUX0rBFcsBzCRESJLeelOEdHIjG7LRkx5l/FUvlqsyHDVJEQs
HwegZ8b8C0fz0EgT2MMEdn10t6Ur1rXzjMB/wvCg8vG8lvciXmedyo9xJ8oMOh0w
UEgxziVDMMovmC+aJctcHUAYubwoGN8TyzcvnGqL7JSh36Pwy28iPzXZ2RLhAyJF
U39vLaHdljwthUaupldlNyCfa6Ofy4qNctlUPlN1AgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAE4/4DeDd+xNH5zdyBAve4w7x5YQ1NiSKtiV5KRUG1+mndr5MubTI1SC
rezrtE9D4zEqz0u2Glg9wZK9YvbshNSo0pXUEpgnJ30wKYbB9y7JlU8/G/+17da/
KIX5pytMUw5JIcj0GGrkPoVDdyU6AYd9j+dOiMyoExcYyvOstgslEDn0MXtxi58j
IykQuuwe1LDWgm58mns1yCPuVr23/r2bj1iTodS2RFeSDk7oK3Kvy+b6nsxJjdyg
nQ5Jwb4Seg3+7Sa/pybG5/vNX5OYHA6laEV+dMyiEBJ+XSX55KQYc4FHu2Xd0O0A
OBZ2fovx2HMaiFs8tJroFU6IAYLiQCg=
-----END CERTIFICATE-----
@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAMkROqx7jUdEGxztx9yrdqTihlYUKhmVyJznbkDc
V87ipb0Ey1E7+JeLIIIefwmGIv3LyPkl1U/ZD1kil8SVwV3f+C5L3D7lGpAaAJH4
fnohVTIdla1Mlso9zBZdB01RfSsEVywHMJERIkt56U4R0ciMbstGTHmX8VS+WqzI
cNUkRCwfB6BnxvwLR/PQSBPYwwR2fXS3pSvWtfOMwH/C8KDy8byW9yJeZ53Kj3En
ygw6HTBQSDHOJUMwyi+YL5oly1wdQBi5vCgY3xPLNy+caovslKHfo/DLbyI/NdnZ
EuEDIkVTf28tod2WPC2FRq6mV2U3IJ9ro5/Lio1y2VQ+U3UCAwEAAaAAMA0GCSqG
SIb3DQEBCwUAA4IBAQAhhe1K0osJIZLOalQYWU2fmStHrTC6Hkakf6E5rjIAkQqZ
G38LnrC/wrPurSKceS8Rb9jmpqODmVdeMnqzag0/t428pgesiO2mdpSg62b/9tEc
xQmnhGkXce54AAnA27VcLpIrJPe/adX1yEIT3EZce26RMIjB1wN/Y1bSjMSvFjHo
HDIDQi7ZSC/U4xXfjn+TSfBKkKg8Am9hxZNGUCt7PhMJ13i+nXdF2JzhjCisTCTu
C2R+ccN3BtAKIs2BdYvYze55LBCbhb1Zo2jYDPi86CRPcozp6wzOxvKzzqxZRbcA
HnyTfnHMPkQzAWMJXoDawPg5imwhM3kN2Qo5CzSA
-----END CERTIFICATE REQUEST-----
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDEzCCAfsCFFkk9C6Hjy5OekqYnYg4D54caVHwMA0GCSqGSIb3DQEBCwUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwIBcNMjIxMjAxMDgzOTAxWhgPMzAwMzAyMDIw
ODM5MDFaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDJETqse41HRBsc7cfcq3ak4oZWFCoZlcic525A3FfO4qW9
BMtRO/iXiyCCHn8JhiL9y8j5JdVP2Q9ZIpfElcFd3/guS9w+5RqQGgCR+H56IVUy
HZWtTJbKPcwWXQdNUX0rBFcsBzCRESJLeelOEdHIjG7LRkx5l/FUvlqsyHDVJEQs
HwegZ8b8C0fz0EgT2MMEdn10t6Ur1rXzjMB/wvCg8vG8lvciXmedyo9xJ8oMOh0w
UEgxziVDMMovmC+aJctcHUAYubwoGN8TyzcvnGqL7JSh36Pwy28iPzXZ2RLhAyJF
U39vLaHdljwthUaupldlNyCfa6Ofy4qNctlUPlN1AgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBAIOPwsrHPCl2F4VYXXUWjBGHlupJ9GbDk+UgjR+87eEhwuXzxiE/Yv1S
3SvWkkzUQ0zu2o5Z4B6zf5V4HnpFiy4JikWdhY5jmS30pToGQ9mhaMHa3WMqLh39
vCLqvccK+PfOmS13iaMKjZQRrn6yX1fRE7zc3bIBQou1rkP0utt3kdp0lyvnK24k
6F2I7MGMLWtjdTxIHuJks7kZ2JQyrkHXBtP0PBKhINhaBY3PQovrF5RM2fCzT87x
F7ZHKJu5HVRJUKcK8nRgC2J2iOHUqYSeyGid0XZZN1g8ux1ZoCaYyqZQhalwSZmD
0D2NJhnz1Eo+gAWAbjsNPBGOGsMeyHI=
-----END CERTIFICATE-----
@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAMkROqx7jUdEGxztx9yrdqTihlYUKhmVyJznbkDc
V87ipb0Ey1E7+JeLIIIefwmGIv3LyPkl1U/ZD1kil8SVwV3f+C5L3D7lGpAaAJH4
fnohVTIdla1Mlso9zBZdB01RfSsEVywHMJERIkt56U4R0ciMbstGTHmX8VS+WqzI
cNUkRCwfB6BnxvwLR/PQSBPYwwR2fXS3pSvWtfOMwH/C8KDy8byW9yJeZ53Kj3En
ygw6HTBQSDHOJUMwyi+YL5oly1wdQBi5vCgY3xPLNy+caovslKHfo/DLbyI/NdnZ
EuEDIkVTf28tod2WPC2FRq6mV2U3IJ9ro5/Lio1y2VQ+U3UCAwEAAaAAMA0GCSqG
SIb3DQEBCwUAA4IBAQAhhe1K0osJIZLOalQYWU2fmStHrTC6Hkakf6E5rjIAkQqZ
G38LnrC/wrPurSKceS8Rb9jmpqODmVdeMnqzag0/t428pgesiO2mdpSg62b/9tEc
xQmnhGkXce54AAnA27VcLpIrJPe/adX1yEIT3EZce26RMIjB1wN/Y1bSjMSvFjHo
HDIDQi7ZSC/U4xXfjn+TSfBKkKg8Am9hxZNGUCt7PhMJ13i+nXdF2JzhjCisTCTu
C2R+ccN3BtAKIs2BdYvYze55LBCbhb1Zo2jYDPi86CRPcozp6wzOxvKzzqxZRbcA
HnyTfnHMPkQzAWMJXoDawPg5imwhM3kN2Qo5CzSA
-----END CERTIFICATE REQUEST-----
+262
View File
@@ -0,0 +1,262 @@
use serde::{Deserialize, Serialize};
#[cfg(feature = "use_pem")]
use time::OffsetDateTime;
use wasm_bindgen_test::wasm_bindgen_test;
use jsonwebtoken::{
Algorithm, DecodingKey, EncodingKey,
crypto::{sign, verify},
};
#[cfg(feature = "use_pem")]
use jsonwebtoken::{Header, Validation, decode, encode};
const RSA_ALGORITHMS: &[Algorithm] = &[
Algorithm::RS256,
Algorithm::RS384,
Algorithm::RS512,
Algorithm::PS256,
Algorithm::PS384,
Algorithm::PS512,
];
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Claims {
sub: String,
company: String,
exp: i64,
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn round_trip_sign_verification_pem_pkcs1() {
let privkey_pem = include_bytes!("private_rsa_key_pkcs1.pem");
let pubkey_pem = include_bytes!("public_rsa_key_pkcs1.pem");
let certificate_pem = include_bytes!("certificate_rsa_key_pkcs1.crt");
for &alg in RSA_ALGORITHMS {
let encrypted =
sign(b"hello world", &EncodingKey::from_rsa_pem(privkey_pem).unwrap(), alg).unwrap();
let is_valid = verify(
&encrypted,
b"hello world",
&DecodingKey::from_rsa_pem(pubkey_pem).unwrap(),
alg,
)
.unwrap();
assert!(is_valid);
let cert_is_valid = verify(
&encrypted,
b"hello world",
&DecodingKey::from_rsa_pem(certificate_pem).unwrap(),
alg,
)
.unwrap();
assert!(cert_is_valid);
}
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn round_trip_sign_verification_pem_pkcs8() {
let privkey_pem = include_bytes!("private_rsa_key_pkcs8.pem");
let pubkey_pem = include_bytes!("public_rsa_key_pkcs8.pem");
let certificate_pem = include_bytes!("certificate_rsa_key_pkcs8.crt");
for &alg in RSA_ALGORITHMS {
let encrypted =
sign(b"hello world", &EncodingKey::from_rsa_pem(privkey_pem).unwrap(), alg).unwrap();
let is_valid = verify(
&encrypted,
b"hello world",
&DecodingKey::from_rsa_pem(pubkey_pem).unwrap(),
alg,
)
.unwrap();
assert!(is_valid);
let cert_is_valid = verify(
&encrypted,
b"hello world",
&DecodingKey::from_rsa_pem(certificate_pem).unwrap(),
alg,
)
.unwrap();
assert!(cert_is_valid);
}
}
#[test]
#[wasm_bindgen_test]
fn round_trip_sign_verification_der() {
let privkey_der = include_bytes!("private_rsa_key.der");
let pubkey_der = include_bytes!("public_rsa_key.der");
for &alg in RSA_ALGORITHMS {
let encrypted = sign(b"hello world", &EncodingKey::from_rsa_der(privkey_der), alg).unwrap();
let is_valid =
verify(&encrypted, b"hello world", &DecodingKey::from_rsa_der(pubkey_der), alg)
.unwrap();
assert!(is_valid);
}
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn round_trip_claim() {
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let privkey_pem = include_bytes!("private_rsa_key_pkcs1.pem");
let pubkey_pem = include_bytes!("public_rsa_key_pkcs1.pem");
let certificate_pem = include_bytes!("certificate_rsa_key_pkcs1.crt");
for &alg in RSA_ALGORITHMS {
let token =
encode(&Header::new(alg), &my_claims, &EncodingKey::from_rsa_pem(privkey_pem).unwrap())
.unwrap();
let token_data = decode::<Claims>(
&token,
&DecodingKey::from_rsa_pem(pubkey_pem).unwrap(),
&Validation::new(alg),
)
.unwrap();
assert_eq!(my_claims, token_data.claims);
assert!(token_data.header.kid.is_none());
let cert_token_data = decode::<Claims>(
&token,
&DecodingKey::from_rsa_pem(certificate_pem).unwrap(),
&Validation::new(alg),
)
.unwrap();
assert_eq!(my_claims, cert_token_data.claims);
assert!(cert_token_data.header.kid.is_none());
}
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn rsa_modulus_exponent() {
let privkey = include_str!("private_rsa_key_pkcs1.pem");
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let n = "yRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4l4sggh5_CYYi_cvI-SXVT9kPWSKXxJXBXd_4LkvcPuUakBoAkfh-eiFVMh2VrUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG_AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBIMc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi-yUod-j8MtvIj812dkS4QMiRVN_by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQ";
let e = "AQAB";
let encrypted = encode(
&Header::new(Algorithm::RS256),
&my_claims,
&EncodingKey::from_rsa_pem(privkey.as_ref()).unwrap(),
)
.unwrap();
let res = decode::<Claims>(
&encrypted,
&DecodingKey::from_rsa_components(n, e).unwrap(),
&Validation::new(Algorithm::RS256),
);
assert!(res.is_ok());
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn rsa_jwk() {
use jsonwebtoken::jwk::Jwk;
use serde_json::json;
let privkey = include_str!("private_rsa_key_pkcs8.pem");
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let jwk:Jwk = serde_json::from_value(json!({
"kty": "RSA",
"n": "yRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4l4sggh5_CYYi_cvI-SXVT9kPWSKXxJXBXd_4LkvcPuUakBoAkfh-eiFVMh2VrUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG_AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBIMc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi-yUod-j8MtvIj812dkS4QMiRVN_by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQ",
"e": "AQAB",
"kid": "rsa01",
"alg": "RS256",
"use": "sig"
})).unwrap();
let encrypted = encode(
&Header::new(Algorithm::RS256),
&my_claims,
&EncodingKey::from_rsa_pem(privkey.as_ref()).unwrap(),
)
.unwrap();
let res = decode::<Claims>(
&encrypted,
&DecodingKey::from_jwk(&jwk).unwrap(),
&Validation::new(Algorithm::RS256),
);
assert!(res.is_ok());
}
// https://jwt.io/ is often used for examples so ensure their example works with jsonwebtoken
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn roundtrip_with_jwtio_example_jey() {
let privkey_pem = include_bytes!("private_jwtio.pem");
let pubkey_pem = include_bytes!("public_jwtio.pem");
let certificate_pem = include_bytes!("certificate_jwtio.crt");
let my_claims = Claims {
sub: "b@b.com".to_string(),
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
for &alg in RSA_ALGORITHMS {
let token =
encode(&Header::new(alg), &my_claims, &EncodingKey::from_rsa_pem(privkey_pem).unwrap())
.unwrap();
let token_data = decode::<Claims>(
&token,
&DecodingKey::from_rsa_pem(pubkey_pem).unwrap(),
&Validation::new(alg),
)
.unwrap();
assert_eq!(my_claims, token_data.claims);
let cert_token_data = decode::<Claims>(
&token,
&DecodingKey::from_rsa_pem(certificate_pem).unwrap(),
&Validation::new(alg),
)
.unwrap();
assert_eq!(my_claims, cert_token_data.claims);
}
}
#[cfg(feature = "use_pem")]
#[test]
#[wasm_bindgen_test]
fn rsa_jwk_from_key() {
use jsonwebtoken::jwk::Jwk;
use serde_json::json;
let privkey = include_str!("private_rsa_key_pkcs8.pem");
let encoding_key = EncodingKey::from_rsa_pem(privkey.as_ref()).unwrap();
let jwk = Jwk::from_encoding_key(&encoding_key, Algorithm::RS256).unwrap();
assert_eq!(jwk, serde_json::from_value(json!({
"kty": "RSA",
"n": "yRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4l4sggh5_CYYi_cvI-SXVT9kPWSKXxJXBXd_4LkvcPuUakBoAkfh-eiFVMh2VrUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG_AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBIMc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi-yUod-j8MtvIj812dkS4QMiRVN_by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQ",
"e": "AQAB",
"alg": "RS256",
})).unwrap());
}
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWw
kWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mr
m/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEi
NQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV
3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2
QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQABAoIBACiARq2wkltjtcjs
kFvZ7w1JAORHbEufEO1Eu27zOIlqbgyAcAl7q+/1bip4Z/x1IVES84/yTaM8p0go
amMhvgry/mS8vNi1BN2SAZEnb/7xSxbflb70bX9RHLJqKnp5GZe2jexw+wyXlwaM
+bclUCrh9e1ltH7IvUrRrQnFJfh+is1fRon9Co9Li0GwoN0x0byrrngU8Ak3Y6D9
D8GjQA4Elm94ST3izJv8iCOLSDBmzsPsXfcCUZfmTfZ5DbUDMbMxRnSo3nQeoKGC
0Lj9FkWcfmLcpGlSXTO+Ww1L7EGq+PT3NtRae1FZPwjddQ1/4V905kyQFLamAA5Y
lSpE2wkCgYEAy1OPLQcZt4NQnQzPz2SBJqQN2P5u3vXl+zNVKP8w4eBv0vWuJJF+
hkGNnSxXQrTkvDOIUddSKOzHHgSg4nY6K02ecyT0PPm/UZvtRpWrnBjcEVtHEJNp
bU9pLD5iZ0J9sbzPU/LxPmuAP2Bs8JmTn6aFRspFrP7W0s1Nmk2jsm0CgYEAyH0X
+jpoqxj4efZfkUrg5GbSEhf+dZglf0tTOA5bVg8IYwtmNk/pniLG/zI7c+GlTc9B
BwfMr59EzBq/eFMI7+LgXaVUsM/sS4Ry+yeK6SJx/otIMWtDfqxsLD8CPMCRvecC
2Pip4uSgrl0MOebl9XKp57GoaUWRWRHqwV4Y6h8CgYAZhI4mh4qZtnhKjY4TKDjx
QYufXSdLAi9v3FxmvchDwOgn4L+PRVdMwDNms2bsL0m5uPn104EzM6w1vzz1zwKz
5pTpPI0OjgWN13Tq8+PKvm/4Ga2MjgOgPWQkslulO/oMcXbPwWC3hcRdr9tcQtn9
Imf9n2spL/6EDFId+Hp/7QKBgAqlWdiXsWckdE1Fn91/NGHsc8syKvjjk1onDcw0
NvVi5vcba9oGdElJX3e9mxqUKMrw7msJJv1MX8LWyMQC5L6YNYHDfbPF1q5L4i8j
8mRex97UVokJQRRA452V2vCO6S5ETgpnad36de3MUxHgCOX3qL382Qx9/THVmbma
3YfRAoGAUxL/Eu5yvMK8SAt/dJK6FedngcM3JEFNplmtLYVLWhkIlNRGDwkg3I5K
y18Ae9n7dHVueyslrb6weq7dTkYDi3iOYRW8HRkIQh06wEdbxt0shTzAJvvCQfrB
jg/3747WSsf/zBTcHihTRBdAv6OmdhV4/dD5YBfLAkLrd+mX7iE=
-----END RSA PRIVATE KEY-----
Binary file not shown.
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAyRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTL
UTv4l4sggh5/CYYi/cvI+SXVT9kPWSKXxJXBXd/4LkvcPuUakBoAkfh+eiFVMh2V
rUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8H
oGfG/AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBI
Mc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi+yUod+j8MtvIj812dkS4QMiRVN/
by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQIDAQABAoIBAHREk0I0O9DvECKd
WUpAmF3mY7oY9PNQiu44Yaf+AoSuyRpRUGTMIgc3u3eivOE8ALX0BmYUO5JtuRNZ
Dpvt4SAwqCnVUinIf6C+eH/wSurCpapSM0BAHp4aOA7igptyOMgMPYBHNA1e9A7j
E0dCxKWMl3DSWNyjQTk4zeRGEAEfbNjHrq6YCtjHSZSLmWiG80hnfnYos9hOr5Jn
LnyS7ZmFE/5P3XVrxLc/tQ5zum0R4cbrgzHiQP5RgfxGJaEi7XcgherCCOgurJSS
bYH29Gz8u5fFbS+Yg8s+OiCss3cs1rSgJ9/eHZuzGEdUZVARH6hVMjSuwvqVTFaE
8AgtleECgYEA+uLMn4kNqHlJS2A5uAnCkj90ZxEtNm3E8hAxUrhssktY5XSOAPBl
xyf5RuRGIImGtUVIr4HuJSa5TX48n3Vdt9MYCprO/iYl6moNRSPt5qowIIOJmIjY
2mqPDfDt/zw+fcDD3lmCJrFlzcnh0uea1CohxEbQnL3cypeLt+WbU6kCgYEAzSp1
9m1ajieFkqgoB0YTpt/OroDx38vvI5unInJlEeOjQ+oIAQdN2wpxBvTrRorMU6P0
7mFUbt1j+Co6CbNiw+X8HcCaqYLR5clbJOOWNR36PuzOpQLkfK8woupBxzW9B8gZ
mY8rB1mbJ+/WTPrEJy6YGmIEBkWylQ2VpW8O4O0CgYEApdbvvfFBlwD9YxbrcGz7
MeNCFbMz+MucqQntIKoKJ91ImPxvtc0y6e/Rhnv0oyNlaUOwJVu0yNgNG117w0g4
t/+Q38mvVC5xV7/cn7x9UMFk6MkqVir3dYGEqIl/OP1grY2Tq9HtB5iyG9L8NIam
QOLMyUqqMUILxdthHyFmiGkCgYEAn9+PjpjGMPHxL0gj8Q8VbzsFtou6b1deIRRA
2CHmSltltR1gYVTMwXxQeUhPMmgkMqUXzs4/WijgpthY44hK1TaZEKIuoxrS70nJ
4WQLf5a9k1065fDsFZD6yGjdGxvwEmlGMZgTwqV7t1I4X0Ilqhav5hcs5apYL7gn
PYPeRz0CgYALHCj/Ji8XSsDoF/MhVhnGdIs2P99NNdmo3R2Pv0CuZbDKMU559LJH
UvrKS8WkuWRDuKrz1W/EQKApFjDGpdqToZqriUFQzwy7mR3ayIiogzNtHcvbDHx8
oFnGY0OFksX/ye0/XGpy2SFxYRwGU98HPYeBvAQQrVjdkzfy7BmXQQ==
-----END RSA PRIVATE KEY-----
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJETqse41HRBsc
7cfcq3ak4oZWFCoZlcic525A3FfO4qW9BMtRO/iXiyCCHn8JhiL9y8j5JdVP2Q9Z
IpfElcFd3/guS9w+5RqQGgCR+H56IVUyHZWtTJbKPcwWXQdNUX0rBFcsBzCRESJL
eelOEdHIjG7LRkx5l/FUvlqsyHDVJEQsHwegZ8b8C0fz0EgT2MMEdn10t6Ur1rXz
jMB/wvCg8vG8lvciXmedyo9xJ8oMOh0wUEgxziVDMMovmC+aJctcHUAYubwoGN8T
yzcvnGqL7JSh36Pwy28iPzXZ2RLhAyJFU39vLaHdljwthUaupldlNyCfa6Ofy4qN
ctlUPlN1AgMBAAECggEAdESTQjQ70O8QIp1ZSkCYXeZjuhj081CK7jhhp/4ChK7J
GlFQZMwiBze7d6K84TwAtfQGZhQ7km25E1kOm+3hIDCoKdVSKch/oL54f/BK6sKl
qlIzQEAenho4DuKCm3I4yAw9gEc0DV70DuMTR0LEpYyXcNJY3KNBOTjN5EYQAR9s
2MeurpgK2MdJlIuZaIbzSGd+diiz2E6vkmcufJLtmYUT/k/ddWvEtz+1DnO6bRHh
xuuDMeJA/lGB/EYloSLtdyCF6sII6C6slJJtgfb0bPy7l8VtL5iDyz46IKyzdyzW
tKAn394dm7MYR1RlUBEfqFUyNK7C+pVMVoTwCC2V4QKBgQD64syfiQ2oeUlLYDm4
CcKSP3RnES02bcTyEDFSuGyyS1jldI4A8GXHJ/lG5EYgiYa1RUivge4lJrlNfjyf
dV230xgKms7+JiXqag1FI+3mqjAgg4mYiNjaao8N8O3/PD59wMPeWYImsWXNyeHS
55rUKiHERtCcvdzKl4u35ZtTqQKBgQDNKnX2bVqOJ4WSqCgHRhOm386ugPHfy+8j
m6cicmUR46ND6ggBB03bCnEG9OtGisxTo/TuYVRu3WP4KjoJs2LD5fwdwJqpgtHl
yVsk45Y1Hfo+7M6lAuR8rzCi6kHHNb0HyBmZjysHWZsn79ZM+sQnLpgaYgQGRbKV
DZWlbw7g7QKBgQCl1u+98UGXAP1jFutwbPsx40IVszP4y5ypCe0gqgon3UiY/G+1
zTLp79GGe/SjI2VpQ7AlW7TI2A0bXXvDSDi3/5Dfya9ULnFXv9yfvH1QwWToySpW
Kvd1gYSoiX84/WCtjZOr0e0HmLIb0vw0hqZA4szJSqoxQgvF22EfIWaIaQKBgQCf
34+OmMYw8fEvSCPxDxVvOwW2i7pvV14hFEDYIeZKW2W1HWBhVMzBfFB5SE8yaCQy
pRfOzj9aKOCm2FjjiErVNpkQoi6jGtLvScnhZAt/lr2TXTrl8OwVkPrIaN0bG/AS
aUYxmBPCpXu3UjhfQiWqFq/mFyzlqlgvuCc9g95HPQKBgAscKP8mLxdKwOgX8yFW
GcZ0izY/30012ajdHY+/QK5lsMoxTnn0skdS+spLxaS5ZEO4qvPVb8RAoCkWMMal
2pOhmquJQVDPDLuZHdrIiKiDM20dy9sMfHygWcZjQ4WSxf/J7T9canLZIXFhHAZT
3wc9h4G8BBCtWN2TN/LsGZdB
-----END PRIVATE KEY-----
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv
vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc
aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy
tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0
e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb
V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9
MwIDAQAB
-----END PUBLIC KEY-----
Binary file not shown.
@@ -0,0 +1,8 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAyRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4
l4sggh5/CYYi/cvI+SXVT9kPWSKXxJXBXd/4LkvcPuUakBoAkfh+eiFVMh2VrUyW
yj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG
/AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBIMc4l
QzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi+yUod+j8MtvIj812dkS4QMiRVN/by2h
3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQIDAQAB
-----END RSA PUBLIC KEY-----
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyRE6rHuNR0QbHO3H3Kt2
pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4l4sggh5/CYYi/cvI+SXVT9kPWSKXxJXB
Xd/4LkvcPuUakBoAkfh+eiFVMh2VrUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHR
yIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG/AtH89BIE9jDBHZ9dLelK9a184zAf8Lw
oPLxvJb3Il5nncqPcSfKDDodMFBIMc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xq
i+yUod+j8MtvIj812dkS4QMiRVN/by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5T
dQIDAQAB
-----END PUBLIC KEY-----