use super::*;
#[non_exhaustive]
#[derive(Debug, Serialize, PartialEq, Clone)]
pub struct PublicJwks {
pub keys: Vec<PublicJwk>,
}
impl PublicJwks {
#[must_use]
pub fn new(keys: Vec<PublicJwk>) -> Self {
Self { keys }
}
}
#[non_exhaustive]
#[derive(Debug, Serialize, Deserialize, Builder, PartialEq, Clone)]
#[builder(derive(Into))]
pub struct PublicJwk {
#[builder(into)]
#[serde(flatten)]
pub key: PublicKey,
#[serde(rename = "use", skip_serializing_if = "Option::is_none")]
pub key_use: Option<KeyUse>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(with = <_>::from_iter)]
#[serde(rename = "key_ops")]
pub key_operations: Option<Vec<KeyOperation>>,
#[builder(into)]
#[serde(rename = "alg", skip_serializing_if = "Option::is_none")]
pub algorithm: Option<String>,
#[builder(into)]
#[serde(skip_serializing_if = "Option::is_none")]
pub kid: Option<String>,
#[builder(skip)]
#[serde(rename = "x5u", default, skip_serializing)]
pub x5u: Option<String>,
}
impl PublicJwk {
#[must_use]
pub fn thumbprint(&self) -> String {
let canonical_form = match &self.key {
PublicKey::Rsa(rsa) => rsa.canonical_form(),
PublicKey::Ec(ec) => ec.canonical_form(),
PublicKey::Okp(okp) => okp.canonical_form(),
};
let mut hasher = Sha256::new();
hasher.update(canonical_form.as_bytes());
URL_SAFE_NO_PAD.encode(hasher.finalize())
}
}
#[non_exhaustive]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
pub enum KeyUse {
#[serde(rename = "sig")]
Sign,
#[serde(rename = "enc")]
Encrypt,
#[serde(skip_serializing, other)]
Unknown,
}
#[non_exhaustive]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub enum KeyOperation {
Sign,
Verify,
Encrypt,
Decrypt,
WrapKey,
UnwrapKey,
DeriveKey,
DeriveBits,
#[serde(skip_serializing, other)]
Unknown,
}
#[non_exhaustive]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(tag = "kty")] pub enum PublicKey {
#[serde(rename = "RSA")]
Rsa(RsaPublicKey),
#[serde(rename = "EC")]
Ec(EcPublicKey),
#[serde(rename = "OKP")]
Okp(OkpPublicKey),
}
#[non_exhaustive]
#[derive(Debug, Serialize, Deserialize, Builder, PartialEq, Clone)]
#[builder(derive(Into))]
pub struct RsaPublicKey {
#[builder(with = <_>::from_iter)]
#[serde(with = "base64url_uint")]
pub n: Vec<u8>,
#[builder(with = <_>::from_iter)]
#[serde(with = "base64url_uint")]
pub e: Vec<u8>,
}
impl RsaPublicKey {
pub(super) fn canonical_form(&self) -> String {
let e = URL_SAFE_NO_PAD.encode(trim_leading_zeros(&self.e));
let n = URL_SAFE_NO_PAD.encode(trim_leading_zeros(&self.n));
format!(r#"{{"e":"{e}","kty":"RSA","n":"{n}"}}"#)
}
}
impl From<RsaPublicKey> for PublicKey {
fn from(value: RsaPublicKey) -> Self {
Self::Rsa(value)
}
}
impl<S: rsa_public_key_builder::State> From<RsaPublicKeyBuilder<S>> for PublicKey
where
S: rsa_public_key_builder::IsComplete,
{
fn from(value: RsaPublicKeyBuilder<S>) -> Self {
Self::Rsa(value.build())
}
}
#[non_exhaustive]
#[derive(Debug, Serialize, Deserialize, Builder, PartialEq, Clone)]
#[builder(derive(Into))]
pub struct EcPublicKey {
#[builder(into)]
pub crv: String,
#[builder(with = <_>::from_iter)]
#[serde(with = "base64url")]
pub x: Vec<u8>,
#[builder(with = <_>::from_iter)]
#[serde(with = "base64url")]
pub y: Vec<u8>,
}
impl EcPublicKey {
pub(super) fn canonical_form(&self) -> String {
#[allow(clippy::unwrap_used)]
let crv = serde_json::to_string(&self.crv).unwrap();
let x = URL_SAFE_NO_PAD.encode(&self.x);
let y = URL_SAFE_NO_PAD.encode(&self.y);
format!(r#"{{"crv":{crv},"kty":"EC","x":"{x}","y":"{y}"}}"#)
}
}
impl From<EcPublicKey> for PublicKey {
fn from(value: EcPublicKey) -> Self {
Self::Ec(value)
}
}
impl<S: ec_public_key_builder::State> From<EcPublicKeyBuilder<S>> for PublicKey
where
S: ec_public_key_builder::IsComplete,
{
fn from(value: EcPublicKeyBuilder<S>) -> Self {
Self::Ec(value.build())
}
}
#[non_exhaustive]
#[derive(Debug, Serialize, Deserialize, Builder, PartialEq, Clone)]
#[builder(derive(Into))]
pub struct OkpPublicKey {
#[builder(into)]
pub crv: String,
#[builder(with = <_>::from_iter)]
#[serde(with = "base64url")]
pub x: Vec<u8>,
}
impl OkpPublicKey {
pub(super) fn canonical_form(&self) -> String {
#[allow(clippy::unwrap_used)]
let crv = serde_json::to_string(&self.crv).unwrap();
let x = URL_SAFE_NO_PAD.encode(&self.x);
format!(r#"{{"crv":{crv},"kty":"OKP","x":"{x}"}}"#)
}
}
impl From<OkpPublicKey> for PublicKey {
fn from(value: OkpPublicKey) -> Self {
Self::Okp(value)
}
}
impl<S: okp_public_key_builder::State> From<OkpPublicKeyBuilder<S>> for PublicKey
where
S: okp_public_key_builder::IsComplete,
{
fn from(value: OkpPublicKeyBuilder<S>) -> Self {
Self::Okp(value.build())
}
}