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