1#[cfg(feature = "alloc")]
4use alloc::{string::String, vec::Vec};
5
6use base64::Engine;
7use sha2::Sha256;
8
9#[cfg(feature = "alloc")]
10use crate::buffer::SecretBytes;
11use crate::{
12 alg::KeyAlg,
13 buffer::{HashBuffer, WriteBuffer},
14 error::Error,
15};
16
17mod encode;
18pub use self::encode::{JwkBufferEncoder, JwkEncoder, JwkEncoderMode, JwkSerialize};
19
20mod ops;
21pub use self::ops::{KeyOps, KeyOpsSet};
22
23mod parts;
24pub use self::parts::JwkParts;
25
26pub trait ToJwk {
28 fn encode_jwk(&self, enc: &mut dyn JwkEncoder) -> Result<(), Error>;
30
31 #[cfg(feature = "alloc")]
33 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
34 fn to_jwk_thumbprint(&self, alg: Option<KeyAlg>) -> Result<String, Error> {
35 let mut v = Vec::with_capacity(43);
36 write_jwk_thumbprint(self, alg, &mut v)?;
37 Ok(String::from_utf8(v).unwrap())
38 }
39
40 #[cfg(feature = "alloc")]
42 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
43 fn to_jwk_public(&self, alg: Option<KeyAlg>) -> Result<String, Error> {
44 let mut v = Vec::with_capacity(128);
45 let mut buf = JwkBufferEncoder::new(&mut v, JwkEncoderMode::PublicKey).alg(alg);
46 self.encode_jwk(&mut buf)?;
47 buf.finalize()?;
48 Ok(String::from_utf8(v).unwrap())
49 }
50
51 #[cfg(feature = "alloc")]
53 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
54 fn to_jwk_secret(&self, alg: Option<KeyAlg>) -> Result<SecretBytes, Error> {
55 let mut v = SecretBytes::with_capacity(128);
56 let mut buf = JwkBufferEncoder::new(&mut v, JwkEncoderMode::SecretKey).alg(alg);
57 self.encode_jwk(&mut buf)?;
58 buf.finalize()?;
59 Ok(v)
60 }
61}
62
63pub fn write_jwk_thumbprint<K: ToJwk + ?Sized>(
65 key: &K,
66 alg: Option<KeyAlg>,
67 output: &mut dyn WriteBuffer,
68) -> Result<(), Error> {
69 let mut hasher = HashBuffer::<Sha256>::new();
70 let mut buf = JwkBufferEncoder::new(&mut hasher, JwkEncoderMode::Thumbprint).alg(alg);
71 key.encode_jwk(&mut buf)?;
72 buf.finalize()?;
73 let hash = hasher.finalize();
74 let mut buf = [0u8; 43];
75 let len = base64::engine::general_purpose::URL_SAFE_NO_PAD
76 .encode_slice(hash, &mut buf)
77 .map_err(|_| err_msg!(Unexpected, "Base64 encoding error"))?;
78 output.buffer_write(&buf[..len])?;
79 Ok(())
80}
81
82pub trait FromJwk: Sized {
84 fn from_jwk(jwk: &str) -> Result<Self, Error> {
86 JwkParts::try_from_str(jwk).and_then(Self::from_jwk_parts)
87 }
88
89 fn from_jwk_slice(jwk: &[u8]) -> Result<Self, Error> {
91 JwkParts::from_slice(jwk).and_then(Self::from_jwk_parts)
92 }
93
94 fn from_jwk_parts(jwk: JwkParts<'_>) -> Result<Self, Error>;
96}