Skip to main content

rsa/pss/
signature.rs

1//! `RSASSA-PSS` signatures.
2
3#[cfg(feature = "alloc")]
4use alloc::boxed::Box;
5use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex};
6#[cfg(feature = "alloc")]
7use crypto_bigint::BoxedUint;
8use signature::SignatureEncoding;
9
10use crate::traits::UnsignedModularInt;
11
12#[cfg(feature = "serde")]
13use serdect::serde::{de, Deserialize, Serialize};
14#[cfg(feature = "encoding")]
15use spki::{
16    der::{asn1::BitString, Result as DerResult},
17    SignatureBitStringEncoding,
18};
19
20/// `RSASSA-PSS` signatures as described in [RFC8017 § 8.1].
21///
22/// [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct GenericSignature<T>
25where
26    T: UnsignedModularInt,
27{
28    pub(super) inner: T,
29}
30
31/// Owned signature byte buffer sized to match the underlying integer type `T`.
32#[derive(Clone)]
33pub struct SignatureBytes<T>(T::Bytes)
34where
35    T: UnsignedModularInt;
36
37/// Boxed PSS signature alias used by the `alloc` code path.
38#[cfg(feature = "alloc")]
39pub type Signature = GenericSignature<BoxedUint>;
40
41impl<T> GenericSignature<T>
42where
43    T: UnsignedModularInt,
44{
45    /// Construct a signature from its underlying integer representation.
46    pub fn from_inner(inner: T) -> Self {
47        Self { inner }
48    }
49
50    /// Borrow the underlying integer representation.
51    pub fn inner(&self) -> &T {
52        &self.inner
53    }
54}
55
56impl<T> From<T> for GenericSignature<T>
57where
58    T: UnsignedModularInt,
59{
60    fn from(inner: T) -> Self {
61        Self { inner }
62    }
63}
64
65impl<T> SignatureBytes<T>
66where
67    T: UnsignedModularInt,
68{
69    fn new(inner: T::Bytes) -> Self {
70        Self(inner)
71    }
72}
73
74impl<T> AsRef<[u8]> for SignatureBytes<T>
75where
76    T: UnsignedModularInt,
77{
78    fn as_ref(&self) -> &[u8] {
79        self.0.as_ref()
80    }
81}
82
83impl<T> core::ops::Deref for SignatureBytes<T>
84where
85    T: UnsignedModularInt,
86{
87    type Target = [u8];
88
89    fn deref(&self) -> &[u8] {
90        self.0.as_ref()
91    }
92}
93
94impl<T> From<GenericSignature<T>> for SignatureBytes<T>
95where
96    T: UnsignedModularInt,
97{
98    fn from(signature: GenericSignature<T>) -> Self {
99        Self::new(signature.inner.to_be_bytes())
100    }
101}
102
103#[cfg(feature = "alloc")]
104impl<T> TryFrom<&[u8]> for GenericSignature<T>
105where
106    T: UnsignedModularInt,
107{
108    type Error = signature::Error;
109
110    fn try_from(bytes: &[u8]) -> signature::Result<Self> {
111        Ok(Self {
112            inner: T::try_from_be_bytes_vartime(bytes).map_err(signature::Error::from_source)?,
113        })
114    }
115}
116
117#[cfg(feature = "alloc")]
118impl<T> SignatureEncoding for GenericSignature<T>
119where
120    T: UnsignedModularInt + 'static,
121    T::Bytes: Clone + Send + Sync + 'static,
122{
123    type Repr = SignatureBytes<T>;
124}
125
126#[cfg(all(feature = "encoding", feature = "alloc"))]
127impl<T> SignatureBitStringEncoding for GenericSignature<T>
128where
129    T: UnsignedModularInt + 'static,
130    T::Bytes: Clone + Send + Sync + 'static,
131{
132    fn to_bitstring(&self) -> DerResult<BitString> {
133        BitString::new(0, self.to_vec())
134    }
135}
136
137#[cfg(feature = "alloc")]
138impl From<GenericSignature<BoxedUint>> for Box<[u8]> {
139    fn from(signature: GenericSignature<BoxedUint>) -> Box<[u8]> {
140        SignatureBytes::<BoxedUint>::from(signature).0
141    }
142}
143
144impl<T> LowerHex for GenericSignature<T>
145where
146    T: UnsignedModularInt,
147{
148    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
149        let bytes = self.inner.to_be_bytes();
150        for byte in bytes.as_ref() {
151            write!(f, "{:02x}", byte)?;
152        }
153        Ok(())
154    }
155}
156
157impl<T> UpperHex for GenericSignature<T>
158where
159    T: UnsignedModularInt,
160{
161    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
162        let bytes = self.inner.to_be_bytes();
163        for byte in bytes.as_ref() {
164            write!(f, "{:02X}", byte)?;
165        }
166        Ok(())
167    }
168}
169
170impl<T> Display for GenericSignature<T>
171where
172    T: UnsignedModularInt,
173{
174    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
175        write!(f, "{:X}", self)
176    }
177}
178
179#[cfg(feature = "serde")]
180impl<T> Serialize for GenericSignature<T>
181where
182    T: UnsignedModularInt,
183{
184    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
185    where
186        S: serdect::serde::Serializer,
187    {
188        let bytes = self.inner.to_be_bytes();
189        serdect::slice::serialize_hex_lower_or_bin(&bytes, serializer)
190    }
191}
192
193#[cfg(all(feature = "serde", feature = "alloc"))]
194impl<'de> Deserialize<'de> for GenericSignature<BoxedUint> {
195    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
196    where
197        D: serdect::serde::Deserializer<'de>,
198    {
199        serdect::slice::deserialize_hex_or_bin_vec(deserializer)?
200            .as_slice()
201            .try_into()
202            .map_err(de::Error::custom)
203    }
204}
205
206#[cfg(test)]
207mod tests {
208    #[test]
209    #[cfg(all(feature = "serde", feature = "alloc"))]
210    fn test_serde() {
211        use super::*;
212        use serde_test::{assert_tokens, Configure, Token};
213        let signature = GenericSignature::<BoxedUint> {
214            inner: BoxedUint::from(42u32),
215        };
216
217        let tokens = [Token::Str("000000000000002a")];
218        assert_tokens(&signature.readable(), &tokens);
219    }
220}