1use base64ct::{Base64UrlUnpadded, Encoding};
4use serde::{Deserialize, Serialize};
5use ts_crypto::{EdwardsVerifyingKey, EllipticVerifyingKey, VerifyingKey};
6
7#[derive(Clone, Debug, Deserialize, Serialize)]
9pub struct JsonWebKey {
10 pub kid: String,
12 pub r#use: String,
14 pub alg: String,
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub crv: Option<String>,
19 #[serde(flatten)]
21 pub kty: KeyType,
22}
23
24#[derive(Clone, Debug, Deserialize, Serialize)]
26#[serde(tag = "kty")]
27pub enum KeyType {
28 #[allow(missing_docs)]
30 #[serde(rename = "EC")]
31 Ec { x: String, y: String },
32
33 #[allow(missing_docs)]
35 #[serde(rename = "RSA")]
36 Rsa { n: String, e: String },
37
38 #[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}