use base64ct::{Base64UrlUnpadded, Encoding};
use serde::{Deserialize, Serialize};
use ts_crypto::{EdwardsVerifyingKey, EllipticVerifyingKey, VerifyingKey};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct JsonWebKey {
pub kid: String,
pub r#use: String,
pub alg: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub crv: Option<String>,
#[serde(flatten)]
pub kty: KeyType,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(tag = "kty")]
pub enum KeyType {
#[allow(missing_docs)]
#[serde(rename = "EC")]
Ec { x: String, y: String },
#[allow(missing_docs)]
#[serde(rename = "RSA")]
Rsa { n: String, e: String },
#[allow(missing_docs)]
#[serde(rename = "OKP")]
Okp { x: String },
}
impl From<&VerifyingKey> for JsonWebKey {
fn from(key: &VerifyingKey) -> Self {
let (alg, crv) = match &key {
VerifyingKey::Rsa(key) => match key.modulus().len() {
value if value >= 512 => ("PS512", None),
value if value >= 384 => ("PS384", None),
_ => ("PS256", None),
},
VerifyingKey::Elliptic(key) => match key {
EllipticVerifyingKey::Prime256(_) => ("ES256", Some("P-256")),
EllipticVerifyingKey::Prime384(_) => ("ES384", Some("P-384")),
EllipticVerifyingKey::Prime521(_) => ("ES512", Some("P-521")),
},
VerifyingKey::Edwards(key) => match key {
EdwardsVerifyingKey::Ed25519(_) => ("Ed25519", Some("Ed25519")),
EdwardsVerifyingKey::Ed448(_) => ("Ed448", Some("Ed448")),
},
};
let kty = match &key {
VerifyingKey::Rsa(key) => KeyType::Rsa {
n: Base64UrlUnpadded::encode_string(&key.modulus()),
e: Base64UrlUnpadded::encode_string(&key.exponent()),
},
VerifyingKey::Elliptic(key) => KeyType::Ec {
x: Base64UrlUnpadded::encode_string(&key.x()),
y: Base64UrlUnpadded::encode_string(&key.y()),
},
VerifyingKey::Edwards(key) => KeyType::Okp {
x: Base64UrlUnpadded::encode_string(&key.raw_key()),
},
};
Self {
kid: Base64UrlUnpadded::encode_string(&key.key_id()),
r#use: "sig".to_string(),
alg: alg.to_string(),
crv: crv.map(str::to_string),
kty,
}
}
}