1use super::{sign_digest, GenericSigningKey, Signature, VerifyingKey};
2use crate::{Result, RsaPrivateKey};
3use crypto_bigint::{modular::BoxedMontyParams, BoxedUint};
4use digest::{Digest, FixedOutputReset, Update};
5use rand_core::{CryptoRng, TryCryptoRng};
6use signature::{
7 hazmat::RandomizedPrehashSigner, Keypair, RandomizedDigestSigner, RandomizedMultipartSigner,
8 RandomizedSigner,
9};
10use zeroize::ZeroizeOnDrop;
11
12#[cfg(feature = "serde")]
13use {
14 pkcs8::DecodePrivateKey,
15 serdect::serde::{de, ser, Deserialize, Serialize},
16};
17
18#[cfg(feature = "encoding")]
19use {
20 super::get_pss_signature_algo_id,
21 crate::encoding::verify_algorithm_id,
22 const_oid::AssociatedOid,
23 pkcs8::{EncodePrivateKey, SecretDocument},
24 spki::{
25 der::AnyRef, AlgorithmIdentifierOwned, AlgorithmIdentifierRef,
26 AssociatedAlgorithmIdentifier, DynSignatureAlgorithmIdentifier,
27 },
28};
29
30#[cfg(feature = "getrandom")]
31use {
32 crypto_common::getrandom::SysRng,
33 signature::{hazmat::PrehashSigner, MultipartSigner, Signer},
34};
35
36pub type SigningKey<D> = GenericSigningKey<D, BoxedUint, BoxedMontyParams>;
41
42#[cfg(feature = "keygen")]
43impl<D> GenericSigningKey<D, BoxedUint, BoxedMontyParams>
44where
45 D: Digest,
46{
47 pub fn random<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
50 Self::random_with_salt_len(rng, bit_size, <D as Digest>::output_size())
51 }
52
53 pub fn random_with_salt_len<R: CryptoRng + ?Sized>(
55 rng: &mut R,
56 bit_size: usize,
57 salt_len: usize,
58 ) -> Result<Self> {
59 Ok(Self::new_with_salt_len(
60 RsaPrivateKey::new(rng, bit_size)?,
61 salt_len,
62 ))
63 }
64}
65
66impl<D> RandomizedDigestSigner<D, Signature> for SigningKey<D>
71where
72 D: Digest + FixedOutputReset + Update,
73{
74 fn try_sign_digest_with_rng<
75 R: TryCryptoRng + ?Sized,
76 F: Fn(&mut D) -> signature::Result<()>,
77 >(
78 &self,
79 rng: &mut R,
80 f: F,
81 ) -> signature::Result<Signature> {
82 let mut digest = D::new();
83 f(&mut digest)?;
84 sign_digest::<_, D>(rng, false, &self.inner, &digest.finalize(), self.salt_len)?
85 .as_slice()
86 .try_into()
87 }
88}
89
90impl<D> RandomizedSigner<Signature> for SigningKey<D>
91where
92 D: Digest + FixedOutputReset + Update,
93{
94 fn try_sign_with_rng<R: TryCryptoRng + ?Sized>(
95 &self,
96 rng: &mut R,
97 msg: &[u8],
98 ) -> signature::Result<Signature> {
99 self.try_sign_digest_with_rng(rng, |digest: &mut D| {
100 Update::update(digest, msg);
101 Ok(())
102 })
103 }
104}
105
106impl<D> RandomizedMultipartSigner<Signature> for SigningKey<D>
107where
108 D: Digest + FixedOutputReset + Update,
109{
110 fn try_multipart_sign_with_rng<R: TryCryptoRng + ?Sized>(
111 &self,
112 rng: &mut R,
113 msg: &[&[u8]],
114 ) -> signature::Result<Signature> {
115 self.try_sign_digest_with_rng(rng, |digest: &mut D| {
116 msg.iter().for_each(|slice| Update::update(digest, slice));
117 Ok(())
118 })
119 }
120}
121
122impl<D> RandomizedPrehashSigner<Signature> for SigningKey<D>
123where
124 D: Digest + FixedOutputReset + Update,
125{
126 fn sign_prehash_with_rng<R: TryCryptoRng + ?Sized>(
127 &self,
128 rng: &mut R,
129 prehash: &[u8],
130 ) -> signature::Result<Signature> {
131 sign_digest::<_, D>(rng, false, &self.inner, prehash, self.salt_len)?
132 .as_slice()
133 .try_into()
134 }
135}
136
137#[cfg(feature = "getrandom")]
138impl<D> PrehashSigner<Signature> for SigningKey<D>
139where
140 D: Digest + FixedOutputReset,
141{
142 fn sign_prehash(&self, prehash: &[u8]) -> signature::Result<Signature> {
143 self.sign_prehash_with_rng(&mut SysRng, prehash)
144 }
145}
146
147#[cfg(feature = "getrandom")]
148impl<D> Signer<Signature> for SigningKey<D>
149where
150 D: Digest + FixedOutputReset,
151{
152 fn try_sign(&self, msg: &[u8]) -> signature::Result<Signature> {
153 self.try_sign_with_rng(&mut SysRng, msg)
154 }
155}
156
157#[cfg(feature = "getrandom")]
158impl<D> MultipartSigner<Signature> for SigningKey<D>
159where
160 D: Digest + FixedOutputReset,
161{
162 fn try_multipart_sign(&self, msg: &[&[u8]]) -> signature::Result<Signature> {
163 self.try_multipart_sign_with_rng(&mut SysRng, msg)
164 }
165}
166
167#[cfg(feature = "encoding")]
172impl<D> AssociatedAlgorithmIdentifier for SigningKey<D>
173where
174 D: Digest,
175{
176 type Params = AnyRef<'static>;
177
178 const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
179}
180
181#[cfg(feature = "encoding")]
182impl<D> DynSignatureAlgorithmIdentifier for SigningKey<D>
183where
184 D: Digest + AssociatedOid,
185{
186 fn signature_algorithm_identifier(&self) -> spki::Result<AlgorithmIdentifierOwned> {
187 get_pss_signature_algo_id::<D>(self.salt_len as u8)
188 }
189}
190
191#[cfg(feature = "encoding")]
192impl<D> EncodePrivateKey for SigningKey<D>
193where
194 D: Digest,
195{
196 fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
197 self.inner.to_pkcs8_der()
198 }
199}
200
201impl<D> From<RsaPrivateKey> for SigningKey<D>
202where
203 D: Digest,
204{
205 fn from(key: RsaPrivateKey) -> Self {
206 Self::new(key)
207 }
208}
209
210impl<D> From<SigningKey<D>> for RsaPrivateKey
211where
212 D: Digest,
213{
214 fn from(key: SigningKey<D>) -> Self {
215 key.inner
216 }
217}
218
219impl<D> Keypair for SigningKey<D>
220where
221 D: Digest,
222{
223 type VerifyingKey = VerifyingKey<D>;
224 fn verifying_key(&self) -> Self::VerifyingKey {
225 VerifyingKey {
226 inner: self.inner.to_public_key(),
227 salt_len: Some(self.salt_len),
228 phantom: Default::default(),
229 }
230 }
231}
232
233#[cfg(feature = "encoding")]
234impl<D> TryFrom<pkcs8::PrivateKeyInfoRef<'_>> for SigningKey<D>
235where
236 D: Digest + AssociatedOid,
237{
238 type Error = pkcs8::Error;
239
240 fn try_from(private_key_info: pkcs8::PrivateKeyInfoRef<'_>) -> pkcs8::Result<Self> {
241 verify_algorithm_id(&private_key_info.algorithm)?;
242 RsaPrivateKey::try_from(private_key_info).map(Self::new)
243 }
244}
245
246impl<D> ZeroizeOnDrop for SigningKey<D> where D: Digest {}
247
248impl<D> PartialEq for SigningKey<D>
249where
250 D: Digest,
251{
252 fn eq(&self, other: &Self) -> bool {
253 self.inner == other.inner && self.salt_len == other.salt_len
254 }
255}
256
257#[cfg(feature = "serde")]
258impl<D> Serialize for SigningKey<D>
259where
260 D: Digest,
261{
262 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
263 where
264 S: serdect::serde::Serializer,
265 {
266 let der = self.to_pkcs8_der().map_err(ser::Error::custom)?;
267 serdect::slice::serialize_hex_lower_or_bin(&der.as_bytes(), serializer)
268 }
269}
270
271#[cfg(feature = "serde")]
272impl<'de, D> Deserialize<'de> for SigningKey<D>
273where
274 D: Digest + AssociatedOid,
275{
276 fn deserialize<De>(deserializer: De) -> core::result::Result<Self, De::Error>
277 where
278 De: serdect::serde::Deserializer<'de>,
279 {
280 let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
281 Self::from_pkcs8_der(&der_bytes).map_err(de::Error::custom)
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 #[test]
288 #[cfg(all(feature = "hazmat", feature = "serde", feature = "keygen"))]
289 fn test_serde() {
290 use super::*;
291 use rand::rngs::ChaCha8Rng;
292 use rand_core::SeedableRng;
293 use serde_test::{assert_tokens, Configure, Token};
294 use sha2::Sha256;
295
296 let mut rng = ChaCha8Rng::from_seed([42; 32]);
297 let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
298 let signing_key = SigningKey::<Sha256>::new(priv_key);
299
300 let tokens = [Token::Str(concat!(
301 "3056020100300d06092a864886f70d010101050004423040020100020900ab240c",
302 "3361d02e370203010001020811e54a15259d22f9020500ceff5cf3020500d3a7aa",
303 "ad020500ccaddf17020500cb529d3d020500bb526d6f"
304 ))];
305
306 assert_tokens(&signing_key.readable(), &tokens);
307 }
308}