jsonwebkey_convert/
lib.rs

1//! # jsonwebkey-convert
2//! Handle Json Web Key without nightly rust compiler.
3//!
4//! ## Load JSON Web Key Set
5//!
6//! ```
7//! use jsonwebkey_convert::JsonWebKeySet;
8//! # use jsonwebkey_convert::Error;
9//!
10//! # fn main() -> Result<(), Error> {
11//! # let jwks_str = include_str!("../testfiles/example-public-key.json");
12//! let jwks: JsonWebKeySet = jwks_str.parse()?;
13//! # Ok(())
14//! # }
15//! ```
16//!
17//!
18//! ## Convert PEM to JWK
19//! `pem_support` feature is required.
20//!
21//! ```
22//! use jsonwebkey_convert::*;
23//! use jsonwebkey_convert::der::FromPem;
24//!
25//! # fn main() -> Result<(), Error> {
26//! # let pem_data = include_str!("../testfiles/test1.pem");
27//! let rsa_jwk = RSAPublicKey::from_pem(pem_data)?;
28//! let jwk_byte_vec = serde_json::to_string(&rsa_jwk);
29//! # Ok(())
30//! # }
31//! ```
32//!
33//! ## Convert JWK to PEM
34//! `pem_support` feature is required.
35//!
36//! ```
37//! use jsonwebkey_convert::*;
38//! use jsonwebkey_convert::der::ToPem;
39//!
40//! # fn main() -> Result<(), Error> {
41//! # let jwk_data = include_str!("../testfiles/test1.json");
42//! let rsa_jwk: RSAPublicKey = jwk_data.parse()?;
43//! let pem_data = rsa_jwk.to_pem()?;
44//! # Ok(())
45//! # }
46//! ```
47
48/// DER and PEM format support
49#[cfg(feature = "simple_asn1")]
50pub mod der;
51
52/// Json Web Token support
53#[cfg(feature = "jsonwebtoken")]
54pub mod jwt;
55
56use num_bigint::BigUint;
57use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
58use std::str::FromStr;
59use thiserror::Error;
60
61#[derive(Error, Debug)]
62pub enum Error {
63    #[error("Public Key Parse Error: {0}")]
64    PubKeyParse(&'static str),
65    #[cfg(feature = "simple_asn1")]
66    #[error(transparent)]
67    ANS1DecodeError(#[from] simple_asn1::ASN1DecodeErr),
68    #[cfg(feature = "simple_asn1")]
69    #[error(transparent)]
70    ANS1EncodeError(#[from] simple_asn1::ASN1EncodeErr),
71    #[error(transparent)]
72    #[cfg(feature = "pem")]
73    PEMParseError(#[from] pem::PemError),
74    #[error(transparent)]
75    Base64UrlError(#[from] base64::DecodeError),
76    #[error(transparent)]
77    JSONParseError(#[from] serde_json::Error),
78}
79
80/// A set of Json Web Keys
81#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
82pub struct JsonWebKeySet {
83    pub keys: Vec<JsonWebKey>,
84}
85
86impl JsonWebKeySet {
87    pub fn from_bytes(data: &[u8]) -> Result<JsonWebKeySet, Error> {
88        Ok(serde_json::from_slice(data)?)
89    }
90}
91
92impl FromStr for JsonWebKeySet {
93    type Err = Error;
94    fn from_str(data: &str) -> Result<JsonWebKeySet, Error> {
95        Ok(serde_json::from_str(data)?)
96    }
97}
98
99/// A JSON Web Key
100#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
101#[serde(untagged)]
102pub enum JsonWebKey {
103    ECPrivateKey {
104        #[serde(flatten)]
105        value: ECPrivateKey,
106    },
107    ECPublicKey {
108        #[serde(flatten)]
109        value: ECPublicKey,
110    },
111    RSAPrivateKey {
112        #[serde(flatten)]
113        value: Box<RSAPrivateKey>,
114    },
115    RSAPublicKey {
116        #[serde(flatten)]
117        value: RSAPublicKey,
118    },
119    SymmetricKey {
120        #[serde(flatten)]
121        value: SymmetricKey,
122    },
123}
124impl FromStr for JsonWebKey {
125    type Err = Error;
126    fn from_str(data: &str) -> Result<JsonWebKey, Error> {
127        Ok(serde_json::from_str(data)?)
128    }
129}
130
131impl JsonWebKey {
132    pub fn from_bytes(data: &[u8]) -> Result<JsonWebKey, Error> {
133        Ok(serde_json::from_slice(data)?)
134    }
135
136    pub fn ec_private_key(&self) -> Option<&ECPrivateKey> {
137        match self {
138            JsonWebKey::ECPrivateKey { value } => Some(value),
139            _ => None,
140        }
141    }
142
143    pub fn ec_public_key(&self) -> Option<&ECPublicKey> {
144        match self {
145            JsonWebKey::ECPublicKey { value } => Some(value),
146            _ => None,
147        }
148    }
149
150    pub fn rsa_private_key(&self) -> Option<&RSAPrivateKey> {
151        match self {
152            JsonWebKey::RSAPrivateKey { value } => Some(value),
153            _ => None,
154        }
155    }
156
157    pub fn rsa_public_key(&self) -> Option<&RSAPublicKey> {
158        match self {
159            JsonWebKey::RSAPublicKey { value } => Some(value),
160            _ => None,
161        }
162    }
163
164    pub fn symmetric_key(&self) -> Option<&SymmetricKey> {
165        match self {
166            JsonWebKey::SymmetricKey { value } => Some(value),
167            _ => None,
168        }
169    }
170}
171
172#[derive(Debug, Clone, PartialEq, Copy, Serialize, Deserialize)]
173pub enum ECCurveParameter {
174    #[serde(rename = "P-256")]
175    P256,
176    #[serde(rename = "P-384")]
177    P384,
178    #[serde(rename = "P-521")]
179    P521,
180}
181
182/// BASE64 encoded big integer
183#[derive(Debug, Clone, PartialEq)]
184pub struct Base64BigUint {
185    big_uint: BigUint,
186    base64: String,
187}
188
189impl Base64BigUint {
190    pub fn to_base64url(&self) -> String {
191        base64::encode_config(&self.big_uint.to_bytes_be(), base64::URL_SAFE_NO_PAD)
192    }
193
194    pub fn from_base64url(value: &str) -> Result<Self, Error> {
195        Ok(Base64BigUint {
196            big_uint: BigUint::from_bytes_be(&base64::decode_config(
197                value,
198                base64::URL_SAFE_NO_PAD,
199            )?),
200            base64: value.to_string(),
201        })
202    }
203}
204
205impl Into<BigUint> for Base64BigUint {
206    fn into(self) -> BigUint {
207        self.big_uint
208    }
209}
210
211impl Into<Base64BigUint> for BigUint {
212    fn into(self) -> Base64BigUint {
213        Base64BigUint {
214            base64: base64::encode_config(self.to_bytes_be(), base64::URL_SAFE_NO_PAD),
215            big_uint: self,
216        }
217    }
218}
219
220impl Serialize for Base64BigUint {
221    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
222    where
223        S: Serializer,
224    {
225        self.to_base64url().serialize(serializer)
226    }
227}
228
229impl<'de> Deserialize<'de> for Base64BigUint {
230    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
231    where
232        D: Deserializer<'de>,
233    {
234        let value = String::deserialize(deserializer)?;
235        Ok(Base64BigUint::from_base64url(&value).map_err(|e| {
236            D::Error::custom(format!("failed to decode BASE64 URL: {} : {}", value, e))
237        })?)
238    }
239}
240
241// RFC 7518
242#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
243//#[serde(deny_unknown_fields)]
244pub struct ECPublicKey {
245    #[serde(flatten)]
246    pub generic: Generic,
247    pub crv: ECCurveParameter,
248    pub x: Base64BigUint,
249    #[serde(skip_serializing_if = "Option::is_none")]
250    pub y: Option<Base64BigUint>,
251}
252
253impl FromStr for ECPublicKey {
254    type Err = Error;
255    fn from_str(data: &str) -> Result<Self, Error> {
256        Ok(serde_json::from_str(data)?)
257    }
258}
259
260#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
261//#[serde(deny_unknown_fields)]
262pub struct ECPrivateKey {
263    #[serde(flatten)]
264    pub public_key: ECPublicKey,
265    pub d: Base64BigUint,
266}
267
268impl FromStr for ECPrivateKey {
269    type Err = Error;
270    fn from_str(data: &str) -> Result<Self, Error> {
271        Ok(serde_json::from_str(data)?)
272    }
273}
274
275#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
276//#[serde(deny_unknown_fields)]
277pub struct RSAPublicKey {
278    #[serde(flatten)]
279    pub generic: Generic,
280    pub n: Base64BigUint,
281    pub e: Base64BigUint,
282}
283
284impl FromStr for RSAPublicKey {
285    type Err = Error;
286    fn from_str(data: &str) -> Result<Self, Error> {
287        Ok(serde_json::from_str(data)?)
288    }
289}
290
291#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
292//#[serde(deny_unknown_fields)]
293pub struct RSAPrivateKey {
294    #[serde(flatten)]
295    pub public_key: RSAPublicKey,
296    pub d: Base64BigUint,
297    #[serde(flatten)]
298    pub optimizations: Option<RSAPrivateKeyOptimizations>,
299    pub oth: Option<Vec<RSAPrivateKeyOtherPrimesInfo>>,
300}
301
302impl FromStr for RSAPrivateKey {
303    type Err = Error;
304    fn from_str(data: &str) -> Result<Self, Error> {
305        Ok(serde_json::from_str(data)?)
306    }
307}
308
309#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
310//#[serde(deny_unknown_fields)]
311pub struct RSAPrivateKeyOptimizations {
312    pub p: Base64BigUint,
313    pub q: Base64BigUint,
314    pub dp: Base64BigUint,
315    pub dq: Base64BigUint,
316    pub qi: Base64BigUint,
317}
318
319#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
320//#[serde(deny_unknown_fields)]
321pub struct RSAPrivateKeyOtherPrimesInfo {
322    pub r: Base64BigUint,
323    pub d: Base64BigUint,
324    pub t: Base64BigUint,
325}
326
327#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
328#[serde(deny_unknown_fields)]
329pub struct SymmetricKey {
330    #[serde(flatten)]
331    pub generic: Generic,
332    pub k: String,
333}
334
335impl FromStr for SymmetricKey {
336    type Err = Error;
337    fn from_str(data: &str) -> Result<Self, Error> {
338        Ok(serde_json::from_str(data)?)
339    }
340}
341
342/// A type of JWK.
343/// See RFC 7518 Section 6.1.
344#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
345pub enum KeyType {
346    #[serde(rename = "EC")]
347    EllipticCurve,
348    #[serde(rename = "RSA")]
349    Rsa,
350    #[serde(rename = "oct")]
351    OctetSequence,
352}
353
354#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
355pub enum KeyUse {
356    #[serde(rename = "sig")]
357    Signature,
358    #[serde(rename = "enc")]
359    Encryption,
360}
361
362/// Generic parameters for JSON Web Key.
363/// See RFC 7517, Section 4.
364#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
365pub struct Generic {
366    // Generic parameters
367    pub kty: KeyType,
368    #[serde(skip_serializing_if = "Option::is_none", rename = "use")]
369    pub use_: Option<KeyUse>,
370    #[serde(skip_serializing_if = "Option::is_none")]
371    pub key_ops: Option<Vec<String>>,
372    #[serde(skip_serializing_if = "Option::is_none")]
373    pub alg: Option<String>,
374    #[serde(skip_serializing_if = "Option::is_none")]
375    pub kid: Option<String>,
376    #[serde(skip_serializing_if = "Option::is_none")]
377    pub x5u: Option<String>,
378    #[serde(skip_serializing_if = "Option::is_none")]
379    pub x5c: Option<Vec<String>>,
380    #[serde(skip_serializing_if = "Option::is_none")]
381    pub x5t: Option<String>,
382    #[serde(skip_serializing_if = "Option::is_none", rename = "x5t#S256")]
383    pub x5t_s256: Option<String>,
384}
385
386#[cfg(test)]
387mod test {
388    use super::*;
389
390    #[test]
391    fn load_rsa_pubkey1() -> Result<(), serde_json::Error> {
392        let pubkey_json: JsonWebKey =
393            serde_json::from_str(include_str!("../testfiles/test1.json"))?;
394        let pubkey_data = pubkey_json.rsa_public_key().unwrap();
395        assert_eq!(pubkey_data.generic.kty, KeyType::Rsa);
396        assert_eq!(pubkey_data.e.big_uint, BigUint::from(65537u64));
397        Ok(())
398    }
399
400    #[test]
401    fn load_rsa_pubkey2() -> Result<(), serde_json::Error> {
402        let pubkey_json: JsonWebKey =
403            serde_json::from_str(include_str!("../testfiles/test2.json"))?;
404        let pubkey_data = pubkey_json.rsa_public_key().unwrap();
405        assert_eq!(pubkey_data.generic.kty, KeyType::Rsa);
406        assert_eq!(pubkey_data.generic.alg.as_ref().unwrap(), "RS256");
407        assert_eq!(pubkey_data.generic.use_.unwrap(), KeyUse::Signature);
408        assert_eq!(
409            pubkey_data.generic.kid.as_ref().unwrap(),
410            "ctFNPw6mrKynlD3atDovZGBlbWRXj7IK0IBODJ_hqeI"
411        );
412        assert_eq!(
413            pubkey_data.generic.x5t.as_ref().unwrap(),
414            "ZsHe1ebgPQqmqNF8rjKqWEjh4hk"
415        );
416        assert_eq!(
417            pubkey_data.generic.x5t_s256.as_ref().unwrap(),
418            "VaYCCwkyvl8K71fldYXJtNjHAPTGom2ylqdAbedtKUI"
419        );
420        assert_eq!(pubkey_data.e.big_uint, BigUint::from(65537u64));
421        Ok(())
422    }
423
424    #[test]
425    fn load_private_keys() -> Result<(), serde_json::Error> {
426        let privkey_json: JsonWebKeySet =
427            serde_json::from_str(include_str!("../testfiles/example-private-key.json"))?;
428        assert_eq!(privkey_json.keys.len(), 2);
429
430        let ec_private_key = privkey_json.keys[0].ec_private_key().unwrap();
431        assert_eq!(
432            ec_private_key.public_key.generic.kty,
433            KeyType::EllipticCurve
434        );
435        assert_eq!(ec_private_key.public_key.crv, ECCurveParameter::P256);
436        assert_eq!(
437            ec_private_key.public_key.generic.use_.unwrap(),
438            KeyUse::Encryption
439        );
440        assert_eq!(ec_private_key.public_key.generic.kid.as_ref().unwrap(), "1");
441
442        let rsa_private_key = privkey_json.keys[1].rsa_private_key().unwrap();
443        assert_eq!(rsa_private_key.public_key.generic.kty, KeyType::Rsa);
444        assert!(rsa_private_key.optimizations.is_some());
445
446        Ok(())
447    }
448
449    #[test]
450    fn load_public_keys() -> Result<(), serde_json::Error> {
451        let pubkey_json: JsonWebKeySet =
452            serde_json::from_str(include_str!("../testfiles/example-public-key.json"))?;
453
454        let ec_public_key = pubkey_json.keys[0].ec_public_key().unwrap();
455        assert_eq!(ec_public_key.generic.kty, KeyType::EllipticCurve);
456        assert_eq!(ec_public_key.crv, ECCurveParameter::P256);
457        assert_eq!(ec_public_key.generic.use_.unwrap(), KeyUse::Encryption);
458        assert_eq!(ec_public_key.generic.kid.as_ref().unwrap(), "1");
459        assert_eq!(
460            ec_public_key.x.to_base64url(),
461            "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4"
462        );
463        assert_eq!(
464            ec_public_key.y.as_ref().unwrap().to_base64url(),
465            "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"
466        );
467
468        let rsa_public_key = pubkey_json.keys[1].rsa_public_key().unwrap();
469        assert_eq!(rsa_public_key.generic.kty, KeyType::Rsa);
470        assert_eq!(rsa_public_key.e.to_base64url(), "AQAB");
471        assert_eq!(rsa_public_key.n.to_base64url(), "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw");
472        assert_eq!(rsa_public_key.generic.alg.as_ref().unwrap(), "RS256");
473        Ok(())
474    }
475
476    #[test]
477    fn load_symmetric_keys() -> Result<(), serde_json::Error> {
478        let symmetric_json: JsonWebKeySet =
479            serde_json::from_str(include_str!("../testfiles/example-symmetric-keys.json"))?;
480
481        let symmetric_key = symmetric_json.keys[0].symmetric_key().unwrap();
482        assert_eq!(symmetric_key.generic.kty, KeyType::OctetSequence);
483        assert_eq!(symmetric_key.generic.alg.as_ref().unwrap(), "A128KW");
484        assert_eq!(symmetric_key.k, "GawgguFyGrWKav7AX4VKUg");
485
486        let symmetric_key = symmetric_json.keys[1].symmetric_key().unwrap();
487        assert_eq!(symmetric_key.generic.kty, KeyType::OctetSequence);
488        assert_eq!(symmetric_key.k, "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow");
489        assert_eq!(
490            symmetric_key.generic.kid.as_ref().unwrap(),
491            "HMAC key used in JWS spec Appendix A.1 example"
492        );
493        Ok(())
494    }
495}