askar_crypto/jwk/
mod.rs

1//! JSON Web Key (JWK) support
2
3#[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
26/// Support for converting a key into a JWK
27pub trait ToJwk {
28    /// Write the JWK representation to an encoder
29    fn encode_jwk(&self, enc: &mut dyn JwkEncoder) -> Result<(), Error>;
30
31    /// Create the JWK thumbprint of the key
32    #[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    /// Create a JWK of the public key
41    #[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    /// Create a JWK of the secret key
52    #[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
63/// Encode a key's JWK into a buffer
64pub 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
82/// Support for loading a key instance from a JWK
83pub trait FromJwk: Sized {
84    /// Import the key from a JWK string reference
85    fn from_jwk(jwk: &str) -> Result<Self, Error> {
86        JwkParts::try_from_str(jwk).and_then(Self::from_jwk_parts)
87    }
88
89    /// Import the key from a JWK byte slice
90    fn from_jwk_slice(jwk: &[u8]) -> Result<Self, Error> {
91        JwkParts::from_slice(jwk).and_then(Self::from_jwk_parts)
92    }
93
94    /// Import the key from a pre-parsed JWK
95    fn from_jwk_parts(jwk: JwkParts<'_>) -> Result<Self, Error>;
96}