1use super::{pkcs1v15_generate_prefix, sign, Signature, VerifyingKey};
2use crate::{dummy_rng::DummyRng, Result, RsaPrivateKey};
3use alloc::vec::Vec;
4use const_oid::AssociatedOid;
5use core::marker::PhantomData;
6use digest::{Digest, FixedOutput, HashMarker, Update};
7use rand_core::{CryptoRng, TryCryptoRng};
8use signature::{
9 hazmat::PrehashSigner, DigestSigner, Keypair, MultipartSigner, RandomizedDigestSigner,
10 RandomizedMultipartSigner, RandomizedSigner, Signer,
11};
12use zeroize::ZeroizeOnDrop;
13
14#[cfg(feature = "encoding")]
15use {
16 super::oid,
17 pkcs8::{EncodePrivateKey, SecretDocument},
18 spki::{
19 der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
20 SignatureAlgorithmIdentifier,
21 },
22};
23#[cfg(feature = "serde")]
24use {
25 pkcs8::DecodePrivateKey,
26 serdect::serde::{de, ser, Deserialize, Serialize},
27};
28
29#[derive(Debug, Clone)]
33pub struct SigningKey<D>
34where
35 D: Digest,
36{
37 inner: RsaPrivateKey,
38 prefix: Vec<u8>,
39 phantom: PhantomData<D>,
40}
41
42impl<D> SigningKey<D>
43where
44 D: Digest + AssociatedOid,
45{
46 pub fn new(key: RsaPrivateKey) -> Self {
48 Self {
49 inner: key,
50 prefix: pkcs1v15_generate_prefix::<D>(),
51 phantom: Default::default(),
52 }
53 }
54
55 pub fn random<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
57 Ok(Self {
58 inner: RsaPrivateKey::new(rng, bit_size)?,
59 prefix: pkcs1v15_generate_prefix::<D>(),
60 phantom: Default::default(),
61 })
62 }
63}
64
65impl<D> SigningKey<D>
66where
67 D: Digest,
68{
69 pub fn new_unprefixed(key: RsaPrivateKey) -> Self {
75 Self {
76 inner: key,
77 prefix: Vec::new(),
78 phantom: Default::default(),
79 }
80 }
81
82 pub fn random_unprefixed<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
84 Ok(Self {
85 inner: RsaPrivateKey::new(rng, bit_size)?,
86 prefix: Vec::new(),
87 phantom: Default::default(),
88 })
89 }
90}
91
92impl<D> DigestSigner<D, Signature> for SigningKey<D>
97where
98 D: Default + FixedOutput + HashMarker + Update,
99{
100 fn try_sign_digest<F: Fn(&mut D) -> signature::Result<()>>(
101 &self,
102 f: F,
103 ) -> signature::Result<Signature> {
104 let mut digest = D::default();
105 f(&mut digest)?;
106 sign::<DummyRng>(None, &self.inner, &self.prefix, &digest.finalize_fixed())?
107 .as_slice()
108 .try_into()
109 }
110}
111
112impl<D> PrehashSigner<Signature> for SigningKey<D>
113where
114 D: Digest,
115{
116 fn sign_prehash(&self, prehash: &[u8]) -> signature::Result<Signature> {
117 sign::<DummyRng>(None, &self.inner, &self.prefix, prehash)?
118 .as_slice()
119 .try_into()
120 }
121}
122
123impl<D> RandomizedDigestSigner<D, Signature> for SigningKey<D>
124where
125 D: Default + FixedOutput + HashMarker + Update,
126{
127 fn try_sign_digest_with_rng<
128 R: TryCryptoRng + ?Sized,
129 F: Fn(&mut D) -> signature::Result<()>,
130 >(
131 &self,
132 rng: &mut R,
133 f: F,
134 ) -> signature::Result<Signature> {
135 let mut digest = D::default();
136 f(&mut digest)?;
137 sign(
138 Some(rng),
139 &self.inner,
140 &self.prefix,
141 &digest.finalize_fixed(),
142 )?
143 .as_slice()
144 .try_into()
145 }
146}
147
148impl<D> RandomizedSigner<Signature> for SigningKey<D>
149where
150 D: Digest,
151{
152 fn try_sign_with_rng<R: TryCryptoRng + ?Sized>(
153 &self,
154 rng: &mut R,
155 msg: &[u8],
156 ) -> signature::Result<Signature> {
157 self.try_multipart_sign_with_rng(rng, &[msg])
158 }
159}
160
161impl<D> RandomizedMultipartSigner<Signature> for SigningKey<D>
162where
163 D: Digest,
164{
165 fn try_multipart_sign_with_rng<R: TryCryptoRng + ?Sized>(
166 &self,
167 rng: &mut R,
168 msg: &[&[u8]],
169 ) -> signature::Result<Signature> {
170 let mut digest = D::new();
171 msg.iter().for_each(|slice| digest.update(slice));
172 sign(Some(rng), &self.inner, &self.prefix, &digest.finalize())?
173 .as_slice()
174 .try_into()
175 }
176}
177
178impl<D> Signer<Signature> for SigningKey<D>
179where
180 D: Digest,
181{
182 fn try_sign(&self, msg: &[u8]) -> signature::Result<Signature> {
183 self.try_multipart_sign(&[msg])
184 }
185}
186
187impl<D> MultipartSigner<Signature> for SigningKey<D>
188where
189 D: Digest,
190{
191 fn try_multipart_sign(&self, msg: &[&[u8]]) -> signature::Result<Signature> {
192 let mut digest = D::new();
193 msg.iter().for_each(|slice| digest.update(slice));
194 sign::<DummyRng>(None, &self.inner, &self.prefix, &digest.finalize())?
195 .as_slice()
196 .try_into()
197 }
198}
199
200impl<D> AsRef<RsaPrivateKey> for SigningKey<D>
205where
206 D: Digest,
207{
208 fn as_ref(&self) -> &RsaPrivateKey {
209 &self.inner
210 }
211}
212
213#[cfg(feature = "encoding")]
214impl<D> AssociatedAlgorithmIdentifier for SigningKey<D>
215where
216 D: Digest,
217{
218 type Params = AnyRef<'static>;
219
220 const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
221}
222
223#[cfg(feature = "encoding")]
224impl<D> EncodePrivateKey for SigningKey<D>
225where
226 D: Digest,
227{
228 fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
229 self.inner.to_pkcs8_der()
230 }
231}
232
233impl<D> From<RsaPrivateKey> for SigningKey<D>
234where
235 D: Digest + AssociatedOid,
236{
237 fn from(key: RsaPrivateKey) -> Self {
238 Self::new(key)
239 }
240}
241
242impl<D> From<SigningKey<D>> for RsaPrivateKey
243where
244 D: Digest,
245{
246 fn from(key: SigningKey<D>) -> Self {
247 key.inner
248 }
249}
250
251impl<D> Keypair for SigningKey<D>
252where
253 D: Digest,
254{
255 type VerifyingKey = VerifyingKey<D>;
256
257 fn verifying_key(&self) -> Self::VerifyingKey {
258 VerifyingKey {
259 inner: self.inner.to_public_key(),
260 prefix: self.prefix.clone(),
261 phantom: Default::default(),
262 }
263 }
264}
265
266#[cfg(feature = "encoding")]
267impl<D> SignatureAlgorithmIdentifier for SigningKey<D>
268where
269 D: Digest + oid::RsaSignatureAssociatedOid,
270{
271 type Params = AnyRef<'static>;
272
273 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> =
274 AlgorithmIdentifierRef {
275 oid: D::OID,
276 parameters: Some(AnyRef::NULL),
277 };
278}
279
280#[cfg(feature = "encoding")]
281impl<D> TryFrom<pkcs8::PrivateKeyInfoRef<'_>> for SigningKey<D>
282where
283 D: Digest + AssociatedOid,
284{
285 type Error = pkcs8::Error;
286
287 fn try_from(private_key_info: pkcs8::PrivateKeyInfoRef<'_>) -> pkcs8::Result<Self> {
288 private_key_info
289 .algorithm
290 .assert_algorithm_oid(pkcs1::ALGORITHM_OID)?;
291 RsaPrivateKey::try_from(private_key_info).map(Self::new)
292 }
293}
294
295impl<D> ZeroizeOnDrop for SigningKey<D> where D: Digest {}
296
297impl<D> PartialEq for SigningKey<D>
298where
299 D: Digest,
300{
301 fn eq(&self, other: &Self) -> bool {
302 self.inner == other.inner && self.prefix == other.prefix
303 }
304}
305
306#[cfg(feature = "serde")]
307impl<D> Serialize for SigningKey<D>
308where
309 D: Digest,
310{
311 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
312 where
313 S: serdect::serde::Serializer,
314 {
315 let der = self.to_pkcs8_der().map_err(ser::Error::custom)?;
316 serdect::slice::serialize_hex_lower_or_bin(&der.as_bytes(), serializer)
317 }
318}
319
320#[cfg(feature = "serde")]
321impl<'de, D> Deserialize<'de> for SigningKey<D>
322where
323 D: Digest + AssociatedOid,
324{
325 fn deserialize<De>(deserializer: De) -> core::result::Result<Self, De::Error>
326 where
327 De: serdect::serde::Deserializer<'de>,
328 {
329 let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
330 Self::from_pkcs8_der(&der_bytes).map_err(de::Error::custom)
331 }
332}
333
334#[cfg(test)]
335mod tests {
336 #[test]
337 #[cfg(all(feature = "hazmat", feature = "serde"))]
338 fn test_serde() {
339 use super::*;
340 use crate::RsaPrivateKey;
341 use rand::rngs::ChaCha8Rng;
342 use rand_core::SeedableRng;
343 use serde_test::{assert_tokens, Configure, Token};
344 use sha2::Sha256;
345
346 let mut rng = ChaCha8Rng::from_seed([42; 32]);
347 let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
348 let signing_key = SigningKey::<Sha256>::new(priv_key);
349
350 let tokens = [Token::Str(concat!(
351 "3056020100300d06092a864886f70d010101050004423040020100020900ab240c",
352 "3361d02e370203010001020811e54a15259d22f9020500ceff5cf3020500d3a7aa",
353 "ad020500ccaddf17020500cb529d3d020500bb526d6f",
354 ))];
355
356 assert_tokens(&signing_key.readable(), &tokens);
357 }
358}