Skip to main content

authnz_common/types/keys/
signature.rs

1//! Signature module.
2
3use crate::{MResult, ServerError};
4
5#[derive(Clone)]
6/// Signing key (certificate).
7pub struct SignKeypair {
8  inner: InnerSignKeypair,
9}
10
11#[non_exhaustive]
12#[derive(Clone)]
13enum InnerSignKeypair {
14  #[cfg(feature = "ed25519-utils")]
15  Ed25519(Box<ed25519_dalek::SigningKey>),
16  #[cfg(feature = "pqc-utils")]
17  Dilithium5(Box<authnz_pqc_dilithium::Keypair>),
18}
19
20impl InnerSignKeypair {
21  fn pack(&self) -> String {
22    use base64::{Engine as _, engine::general_purpose::STANDARD};
23
24    #[allow(unreachable_patterns)]
25    match self {
26      #[cfg(feature = "ed25519-utils")]
27      Self::Ed25519(keypair) => STANDARD.encode(keypair.to_keypair_bytes()),
28      #[cfg(feature = "pqc-utils")]
29      Self::Dilithium5(keypair) => format!(
30        "{}::||::{}",
31        STANDARD.encode(keypair.public),
32        STANDARD.encode(keypair.expose_secret())
33      ),
34      _ => unreachable!(),
35    }
36  }
37
38  #[allow(clippy::unwrap_used)]
39  fn unpack(cert: impl AsRef<str>) -> MResult<Self> {
40    use base64::{Engine as _, engine::general_purpose::STANDARD};
41
42    #[cfg(feature = "pqc-utils")]
43    if cert.as_ref().contains("::||::") {
44      let parts = cert.as_ref().split("::||::").collect::<Vec<_>>();
45      if parts.len() != 2 {
46        return Err(
47          ServerError::from_private_str("Certificate have no part divider, this is not the certificate!")
48            .with_private_str("Invalid certificate!")
49            .with_500(),
50        );
51      }
52
53      let public = parts.first().unwrap();
54      let public = STANDARD.decode(public).map_err(|e| {
55        ServerError::from_private(e)
56          .with_private_str("Can't decode public certificate part!")
57          .with_500()
58      })?;
59
60      let private = parts.last().unwrap();
61      let private = STANDARD.decode(private).map_err(|e| {
62        ServerError::from_private(e)
63          .with_private_str("Can't decode private certificate part!")
64          .with_500()
65      })?;
66
67      return Ok(Self::Dilithium5(Box::new(
68        authnz_pqc_dilithium::Keypair::restore(&public, &private).map_err(|e| {
69          ServerError::from_private(e)
70            .with_private_str("Can't restore Dilithium5 keypair!")
71            .with_500()
72        })?,
73      )));
74    }
75
76    #[cfg(feature = "ed25519-utils")]
77    {
78      let keypair = STANDARD.decode(cert.as_ref()).map_err(|e| {
79        ServerError::from_private(e)
80          .with_private_str("Can't decode Ed25519 certificate!")
81          .with_500()
82      })?;
83      return Ok(Self::Ed25519(Box::new(
84        ed25519_dalek::SigningKey::from_keypair_bytes(keypair.as_slice().try_into().map_err(|e| {
85          ServerError::from_private(e)
86            .with_private_str("Incorrect keypair length!")
87            .with_500()
88        })?)
89        .map_err(|e| {
90          ServerError::from_private(e)
91            .with_private_str("Incorrect Ed25519 certificate!")
92            .with_500()
93        })?,
94      )));
95    }
96
97    #[allow(unreachable_code)]
98    Err(ServerError::from_private_str("Enable at least one of `ed25519-utils`, `pqc-utils` to use SignKeypair!").with_500())
99  }
100
101  fn public(&self) -> Vec<u8> {
102    #[cfg(feature = "pqc-utils")]
103    #[allow(irrefutable_let_patterns)]
104    if let Self::Dilithium5(keypair) = &self {
105      return keypair.public.to_vec();
106    }
107
108    #[cfg(feature = "ed25519-utils")]
109    #[allow(irrefutable_let_patterns)]
110    if let Self::Ed25519(keypair) = &self {
111      return keypair.verifying_key().as_bytes().to_vec();
112    }
113
114    unreachable!()
115  }
116
117  fn private(&self) -> Vec<u8> {
118    #[cfg(feature = "pqc-utils")]
119    #[allow(irrefutable_let_patterns)]
120    if let Self::Dilithium5(keypair) = &self {
121      return keypair.expose_secret().to_vec();
122    }
123
124    #[cfg(feature = "ed25519-utils")]
125    #[allow(irrefutable_let_patterns)]
126    if let Self::Ed25519(keypair) = &self {
127      return keypair.as_bytes().to_vec();
128    }
129
130    unreachable!()
131  }
132}
133
134impl SignKeypair {
135  #[cfg(feature = "ed25519-utils")]
136  /// Generates Ed25519 keypair for signing usage.
137  ///
138  /// Store your private key safely!
139  pub fn new_ed25519() -> MResult<Self> {
140    use rand::TryRngCore;
141
142    let mut csprng = rand::rngs::OsRng;
143
144    let mut secret = ed25519_dalek::SecretKey::default();
145    csprng.try_fill_bytes(&mut secret).map_err(|e| {
146      ServerError::from_private(e)
147        .with_private_str("Can't generate Ed25519 certificate!")
148        .with_500()
149    })?;
150
151    Ok(Self {
152      inner: InnerSignKeypair::Ed25519(Box::new(ed25519_dalek::SigningKey::from_bytes(&secret))),
153    })
154  }
155
156  #[cfg(feature = "pqc-utils")]
157  /// Generates Dilithium (mode 5) keypair for signing usage.
158  ///
159  /// Store your private key safely!
160  pub fn new_dilithium5() -> Self {
161    Self {
162      inner: InnerSignKeypair::Dilithium5(Box::new(authnz_pqc_dilithium::Keypair::generate())),
163    }
164  }
165
166  /// Packs keypair to string.
167  pub fn pack_keypair(&self) -> String {
168    self.inner.pack()
169  }
170
171  /// Unpacks keypair from a string.
172  pub fn unpack_keypair(keypair: impl AsRef<str>) -> MResult<Self> {
173    Ok(Self {
174      inner: InnerSignKeypair::unpack(keypair)?,
175    })
176  }
177
178  /// Signs raw bytes.
179  pub fn sign_raw(&self, data: &[u8]) -> Vec<u8> {
180    #[allow(unreachable_patterns)]
181    match &self.inner {
182      #[cfg(feature = "ed25519-utils")]
183      InnerSignKeypair::Ed25519(keypair) => ed25519_dalek::Signer::sign(keypair.as_ref(), data).to_vec(),
184      #[cfg(feature = "pqc-utils")]
185      InnerSignKeypair::Dilithium5(keypair) => keypair.sign(data).to_vec(),
186      _ => unreachable!(),
187    }
188  }
189
190  /// Verifies data by its signature and provided public key.
191  pub fn verify_raw(data: &[u8], sign: &[u8], public_key: &[u8]) -> MResult<()> {
192    #[cfg(feature = "pqc-utils")]
193    if authnz_pqc_dilithium::verify(sign, data, public_key).is_ok() {
194      return Ok(());
195    }
196    #[cfg(feature = "ed25519-utils")]
197    if let Ok(pkey) = public_key.try_into()
198      && let Ok(vkey) = ed25519_dalek::VerifyingKey::from_bytes(pkey)
199      && let Ok(sign) = ed25519_dalek::Signature::from_slice(sign)
200      && ed25519_dalek::Verifier::verify(&vkey, data, &sign).is_ok()
201    {
202      return Ok(());
203    }
204
205    Err(ServerError::from_public("Invalid signature!").with_401())
206  }
207
208  /// Packs `T` into MessagePack and signs its bytes.
209  pub fn sign<T: serde::Serialize>(&self, data: &T) -> MResult<Vec<u8>> {
210    rmp_serde::to_vec(data)
211      .map_err(|e| {
212        ServerError::from_private(e)
213          .with_private_str("Can't serialize data to sign!")
214          .with_500()
215      })
216      .map(|v| self.sign_raw(&v))
217  }
218
219  /// Verifies any serializable `T` by its MessagePack view's signature and provided public key.
220  pub fn verify<T: serde::Serialize>(data: &T, sign: &[u8], public_key: &[u8]) -> MResult<()> {
221    let data = rmp_serde::to_vec(data).map_err(|e| {
222      ServerError::from_private(e)
223        .with_private_str("Can't serialize data to validate signature!")
224        .with_500()
225    })?;
226    Self::verify_raw(&data, sign, public_key)
227  }
228
229  /// Verifies header and payload by their signature and provided public key.
230  pub fn verify_token(header: &[u8], payload: &[u8], sign: &[u8], public_key: &[u8]) -> MResult<()> {
231    let mut data = header.to_vec();
232    data.extend_from_slice(payload);
233    Self::verify_raw(&data, sign, public_key)
234  }
235
236  /// Get public key.
237  pub fn public(&self) -> Vec<u8> {
238    self.inner.public()
239  }
240
241  /// Get private key.
242  ///
243  /// # Safety
244  ///
245  /// This method is principally safe, but using `unsafe` keyword to describe the soundness of it's usage.
246  pub unsafe fn private(&self) -> Vec<u8> {
247    self.inner.private()
248  }
249}