ts_token/
jwk.rs

1//! A JSON web key <https://www.iana.org/assignments/jose/jose.xhtml> used to verify signed JSON web tokens.
2
3use base64ct::{Base64UrlUnpadded, Encoding};
4use serde::{Deserialize, Serialize};
5use ts_crypto::{EdwardsVerifyingKey, EllipticVerifyingKey, VerifyingKey};
6
7/// A JSON web key <https://www.iana.org/assignments/jose/jose.xhtml> used to verify signed JSON web tokens.
8#[derive(Clone, Debug, Deserialize, Serialize)]
9pub struct JsonWebKey {
10    /// The ID of this key.
11    pub kid: String,
12    /// The usage of this key. Should be `sig`.
13    pub r#use: String,
14    /// The algorithm this key uses.
15    pub alg: String,
16    /// The curve ID for elliptic keys.
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub crv: Option<String>,
19    /// The type of the key and associated parameters.
20    #[serde(flatten)]
21    pub kty: KeyType,
22}
23
24/// The parameters for the given key type <https://www.iana.org/assignments/jose/jose.xhtml#web-key-types>
25#[derive(Clone, Debug, Deserialize, Serialize)]
26#[serde(tag = "kty")]
27pub enum KeyType {
28    /// <https://www.rfc-editor.org/rfc/rfc7518.html#section-6.2.1>
29    #[allow(missing_docs)]
30    #[serde(rename = "EC")]
31    Ec { x: String, y: String },
32
33    /// <https://www.rfc-editor.org/rfc/rfc7518.html#section-6.3>
34    #[allow(missing_docs)]
35    #[serde(rename = "RSA")]
36    Rsa { n: String, e: String },
37
38    /// <https://www.rfc-editor.org/rfc/rfc8037.html#section-2>
39    #[allow(missing_docs)]
40    #[serde(rename = "OKP")]
41    Okp { x: String },
42}
43
44impl From<&VerifyingKey> for JsonWebKey {
45    fn from(key: &VerifyingKey) -> Self {
46        let (alg, crv) = match &key {
47            VerifyingKey::Rsa(key) => match key.modulus().len() {
48                value if value >= 512 => ("PS512", None),
49                value if value >= 384 => ("PS384", None),
50                _ => ("PS256", None),
51            },
52            VerifyingKey::Elliptic(key) => match key {
53                EllipticVerifyingKey::Prime256(_) => ("ES256", Some("P-256")),
54                EllipticVerifyingKey::Prime384(_) => ("ES384", Some("P-384")),
55                EllipticVerifyingKey::Prime521(_) => ("ES512", Some("P-521")),
56            },
57            VerifyingKey::Edwards(key) => match key {
58                EdwardsVerifyingKey::Ed25519(_) => ("Ed25519", Some("Ed25519")),
59                EdwardsVerifyingKey::Ed448(_) => ("Ed448", Some("Ed448")),
60            },
61        };
62
63        let kty = match &key {
64            VerifyingKey::Rsa(key) => KeyType::Rsa {
65                n: Base64UrlUnpadded::encode_string(&key.modulus()),
66                e: Base64UrlUnpadded::encode_string(&key.exponent()),
67            },
68            VerifyingKey::Elliptic(key) => KeyType::Ec {
69                x: Base64UrlUnpadded::encode_string(&key.x()),
70                y: Base64UrlUnpadded::encode_string(&key.y()),
71            },
72            VerifyingKey::Edwards(key) => KeyType::Okp {
73                x: Base64UrlUnpadded::encode_string(&key.raw_key()),
74            },
75        };
76
77        Self {
78            kid: Base64UrlUnpadded::encode_string(&key.key_id()),
79            r#use: "sig".to_string(),
80            alg: alg.to_string(),
81            crv: crv.map(str::to_string),
82            kty,
83        }
84    }
85}