1#![cfg_attr(fuzzing, allow(dead_code))]
2#![cfg_attr(fuzzing, allow(unreachable_code))]
3#![cfg_attr(fuzzing, allow(unused_variables))]
4
5#[allow(unused_imports)]
6use {
7 crate::error::*,
8 log::{debug, error, info, log, trace, warn},
9};
10
11use core::ops::Deref;
12
13use ed25519_dalek as dalek;
14use ed25519_dalek::{Signer, Verifier};
15use zeroize::ZeroizeOnDrop;
16
17use crate::*;
18use packets::{Ed25519PubKey, Ed25519Sig, PubKey, Signature};
19use sshnames::*;
20use sshwire::{BinString, Blob, SSHEncode};
21
22use pretty_hex::PrettyHex;
23
24use core::mem::discriminant;
25
26use digest::Digest;
27
28const MAX_SIG_MSG: usize = 1
32 + 4
33 + 40
34 + 4
35 + 14
36 + 4
37 + 9
38 + 1
39 + 4
40 + SSH_NAME_CURVE25519_LIBSSH.len()
41 + 4
42 + 32
43 + 32;
44
45#[cfg(feature = "rsa")]
47use packets::RSAPubKey;
48#[cfg(feature = "rsa")]
49use rsa::signature::{DigestSigner, DigestVerifier};
50
51#[derive(Debug, Clone, Copy)]
52pub enum SigType {
53 Ed25519,
54 #[cfg(feature = "rsa")]
55 RSA,
56 }
58
59impl SigType {
60 pub fn from_name(name: &'static str) -> Result<Self> {
62 match name {
63 SSH_NAME_ED25519 => Ok(SigType::Ed25519),
64 #[cfg(feature = "rsa")]
65 SSH_NAME_RSA_SHA256 => Ok(SigType::RSA),
66 _ => Err(Error::bug()),
67 }
68 }
69
70 pub fn algorithm_name(&self) -> &'static str {
72 match self {
73 SigType::Ed25519 => SSH_NAME_ED25519,
74 #[cfg(feature = "rsa")]
75 SigType::RSA => SSH_NAME_RSA_SHA256,
76 }
77 }
78
79 #[cfg(fuzzing)]
80 fn fuzz_fake_verify(&self, sig: &Signature) -> Result<()> {
81 let b = match &sig {
82 Signature::Ed25519(e) => e.sig.0,
83 #[cfg(feature = "rsa")]
84 Signature::RSA(e) => e.sig.0,
85 Signature::Unknown(_) => panic!(),
86 };
87
88 if b.get(..3) == Some(b"bad") {
89 Err(Error::BadSig)
90 } else {
91 Ok(())
92 }
93 }
94
95 pub fn verify(
97 &self,
98 pubkey: &PubKey,
99 msg: &dyn SSHEncode,
100 sig: &Signature,
101 ) -> Result<()> {
102 let sig_type = sig.sig_type().map_err(|_| Error::BadSig)?;
104
105 if discriminant(&sig_type) != discriminant(self) {
109 warn!(
110 "Received {:?} signature, expecting {}",
111 sig.algorithm_name(),
112 self.algorithm_name()
113 );
114 return Err(Error::BadSig);
115 }
116
117 let ret = match (self, pubkey, sig) {
118 (SigType::Ed25519, PubKey::Ed25519(k), Signature::Ed25519(s)) => {
119 Self::verify_ed25519(k, msg, s)
120 }
121
122 #[cfg(feature = "rsa")]
123 (SigType::RSA, PubKey::RSA(k), Signature::RSA(s)) => {
124 Self::verify_rsa(k, msg, s)
125 }
126
127 _ => {
128 warn!(
129 "Signature \"{:?}\" doesn't match key type \"{:?}\"",
130 sig.algorithm_name(),
131 pubkey.algorithm_name(),
132 );
133 Err(Error::BadSig)
134 }
135 };
136
137 #[cfg(fuzzing)]
138 return self.fuzz_fake_verify(sig);
139
140 ret
141 }
142
143 fn verify_ed25519(
144 k: &Ed25519PubKey,
145 msg: &dyn SSHEncode,
146 s: &Ed25519Sig,
147 ) -> Result<()> {
148 let k: &[u8; 32] = &k.key.0;
149 let k = dalek::VerifyingKey::from_bytes(k).map_err(|_| Error::BadKey)?;
150
151 let s: &[u8; 64] = s.sig.0.try_into().map_err(|_| Error::BadSig)?;
152 let s: dalek::Signature = s.into();
153 let mut buf = [0; MAX_SIG_MSG];
164 let l = sshwire::write_ssh(&mut buf, msg)?;
165 let buf = &buf[..l];
166 k.verify(buf, &s).map_err(|_| Error::BadSig)
167 }
168
169 #[cfg(feature = "rsa")]
170 fn verify_rsa(
171 k: &packets::RSAPubKey,
172 msg: &dyn SSHEncode,
173 s: &packets::RSASig,
174 ) -> Result<()> {
175 let verifying_key =
176 rsa::pkcs1v15::VerifyingKey::<sha2::Sha256>::new(k.key.clone());
177 let signature = s.sig.0.try_into().map_err(|e| {
178 trace!("RSA bad signature: {e}");
179 Error::BadSig
180 })?;
181
182 let mut h = sha2::Sha256::new();
183 sshwire::hash_ser(&mut h, msg)?;
184 verifying_key.verify_digest(h, &signature).map_err(|e| {
185 trace!("RSA verify failed: {e}");
186 Error::BadSig
187 })
188 }
189}
190
191pub enum OwnedSig {
192 Ed25519([u8; 64]),
194 #[cfg(feature = "rsa")]
195 RSA(Box<[u8]>),
196}
197
198#[cfg(feature = "rsa")]
199impl From<rsa::pkcs1v15::Signature> for OwnedSig {
200 fn from(s: rsa::pkcs1v15::Signature) -> Self {
201 OwnedSig::RSA(s.into())
202 }
203}
204
205impl TryFrom<Signature<'_>> for OwnedSig {
206 type Error = Error;
207 fn try_from(s: Signature) -> Result<Self> {
208 match s {
209 Signature::Ed25519(s) => {
210 let s: [u8; 64] = s.sig.0.try_into().map_err(|_| Error::BadSig)?;
211 Ok(OwnedSig::Ed25519(s))
212 }
213 #[cfg(feature = "rsa")]
214 Signature::RSA(s) => {
215 let s = s.sig.0.try_into().map_err(|_| Error::BadSig)?;
216 Ok(OwnedSig::RSA(s))
217 }
218 Signature::Unknown(u) => {
219 debug!("Unknown {u} signature");
220 Err(Error::UnknownMethod { kind: "signature" })
221 }
222 }
223 }
224}
225#[derive(Debug, Clone, Copy)]
227pub enum KeyType {
228 Ed25519,
229 #[cfg(feature = "rsa")]
230 RSA,
231}
232
233#[derive(ZeroizeOnDrop, Clone, PartialEq, Eq)]
239pub enum SignKey {
240 #[zeroize(skip)]
243 Ed25519(dalek::SigningKey),
244
245 #[zeroize(skip)]
246 AgentEd25519(dalek::VerifyingKey),
247
248 #[cfg(feature = "rsa")]
249 #[zeroize(skip)]
251 RSA(rsa::RsaPrivateKey),
252
253 #[cfg(feature = "rsa")]
254 #[zeroize(skip)]
255 AgentRSA(rsa::RsaPublicKey),
256}
257
258impl SignKey {
259 pub fn generate(ty: KeyType, bits: Option<usize>) -> Result<Self> {
260 match ty {
261 KeyType::Ed25519 => {
262 if bits.unwrap_or(256) != 256 {
263 return Err(Error::msg("Bad key size"));
264 }
265 let k = dalek::SigningKey::generate(&mut rand_core::OsRng);
266 Ok(Self::Ed25519(k))
267 }
268
269 #[cfg(feature = "rsa")]
270 KeyType::RSA => {
271 let bits = bits.unwrap_or(config::RSA_DEFAULT_KEYSIZE);
272 if bits < config::RSA_MIN_KEYSIZE
273 || bits > rsa::RsaPublicKey::MAX_SIZE
274 || (bits % 8 != 0)
275 {
276 return Err(Error::msg("Bad key size"));
277 }
278
279 let k = rsa::RsaPrivateKey::new(&mut rand_core::OsRng, bits)
280 .map_err(|e| {
281 debug!("RSA key generation error {e}");
282 Error::bug()
284 })?;
285 Ok(Self::RSA(k))
286 }
287 }
288 }
289
290 pub fn pubkey(&self) -> PubKey<'_> {
291 match self {
292 SignKey::Ed25519(k) => {
293 let pubk = k.verifying_key().to_bytes();
294 PubKey::Ed25519(Ed25519PubKey { key: Blob(pubk) })
295 }
296
297 SignKey::AgentEd25519(pk) => {
298 PubKey::Ed25519(Ed25519PubKey { key: Blob(pk.to_bytes()) })
299 }
300
301 #[cfg(feature = "rsa")]
302 SignKey::RSA(k) => PubKey::RSA(RSAPubKey { key: k.into() }),
303
304 #[cfg(feature = "rsa")]
305 SignKey::AgentRSA(pk) => PubKey::RSA(RSAPubKey { key: pk.clone() }),
306 }
307 }
308
309 #[cfg(feature = "openssh-key")]
310 pub fn from_openssh(k: impl AsRef<[u8]>) -> Result<Self> {
311 let k = ssh_key::PrivateKey::from_openssh(k)
312 .map_err(|_| Error::msg("Unsupported OpenSSH key"))?;
313
314 k.try_into()
315 }
316
317 pub fn from_agent_pubkey(pk: &PubKey) -> Result<Self> {
318 match pk {
319 PubKey::Ed25519(k) => {
320 let k: dalek::VerifyingKey =
321 k.key.0.as_slice().try_into().map_err(|_| Error::BadKey)?;
322 Ok(Self::AgentEd25519(k))
323 }
324
325 #[cfg(feature = "rsa")]
326 PubKey::RSA(k) => Ok(Self::AgentRSA(k.key.clone())),
327
328 PubKey::Unknown(_) => Err(Error::msg("Unsupported agent key")),
329 }
330 }
331
332 pub(crate) fn can_sign(&self, sig_type: SigType) -> bool {
334 match self {
335 SignKey::Ed25519(_) | SignKey::AgentEd25519(_) => {
336 matches!(sig_type, SigType::Ed25519)
337 }
338
339 #[cfg(feature = "rsa")]
340 SignKey::RSA(_) | SignKey::AgentRSA(_) => {
341 matches!(sig_type, SigType::RSA)
342 }
343 }
344 }
345
346 pub(crate) fn sign(&self, msg: &impl SSHEncode) -> Result<OwnedSig> {
347 let sig: OwnedSig = match self {
348 SignKey::Ed25519(k) => {
349 let mut buf = [0; MAX_SIG_MSG];
361 let l = sshwire::write_ssh(&mut buf, msg)?;
362 let buf = &buf[..l];
363 let sig = k.sign(buf);
364
365 OwnedSig::Ed25519(sig.to_bytes())
366 }
367
368 #[cfg(feature = "rsa")]
369 SignKey::RSA(k) => {
370 let signing_key =
371 rsa::pkcs1v15::SigningKey::<sha2::Sha256>::new(k.clone());
372 let mut h = sha2::Sha256::new();
373 sshwire::hash_ser(&mut h, msg)?;
374 let sig = signing_key.try_sign_digest(h).map_err(|e| {
375 trace!("RSA signing failed: {e:?}");
376 Error::bug()
377 })?;
378 OwnedSig::RSA(sig.into())
379 }
380
381 SignKey::AgentEd25519(_) => return Error::bug_msg("agent sign"),
383 #[cfg(feature = "rsa")]
384 SignKey::AgentRSA(_) => return Error::bug_msg("agent sign"),
385 };
386
387 Ok(sig)
397 }
398
399 pub(crate) fn is_agent(&self) -> bool {
400 match self {
401 SignKey::Ed25519(_) => false,
402 #[cfg(feature = "rsa")]
403 SignKey::RSA(_) => false,
404
405 SignKey::AgentEd25519(_) => true,
406 #[cfg(feature = "rsa")]
407 SignKey::AgentRSA(_) => true,
408 }
409 }
410}
411
412impl core::fmt::Debug for SignKey {
413 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
414 let s = match self {
415 Self::Ed25519(_) => "Ed25519",
416 Self::AgentEd25519(_) => "AgentEd25519",
417 #[cfg(feature = "rsa")]
418 Self::RSA(_) => "RSA",
419 #[cfg(feature = "rsa")]
420 Self::AgentRSA(_) => "AgentRSA",
421 };
422 write!(f, "SignKey::{s}")
423 }
424}
425
426#[cfg(feature = "openssh-key")]
427impl TryFrom<ssh_key::PrivateKey> for SignKey {
428 type Error = Error;
429 fn try_from(k: ssh_key::PrivateKey) -> Result<Self> {
430 match k.key_data() {
431 ssh_key::private::KeypairData::Ed25519(k) => {
432 Ok(SignKey::Ed25519(k.private.to_bytes().into()))
433 }
434
435 #[cfg(feature = "rsa")]
436 ssh_key::private::KeypairData::Rsa(k) => {
437 let primes = vec![
438 (&k.private.p).try_into().map_err(|_| Error::BadKey)?,
439 (&k.private.q).try_into().map_err(|_| Error::BadKey)?,
440 ];
441 let key = rsa::RsaPrivateKey::from_components(
442 (&k.public.n).try_into().map_err(|_| Error::BadKey)?,
443 (&k.public.e).try_into().map_err(|_| Error::BadKey)?,
444 (&k.private.d).try_into().map_err(|_| Error::BadKey)?,
445 primes,
446 )
447 .map_err(|_| Error::BadKey)?;
448 Ok(SignKey::RSA(key))
449 }
450 _ => {
451 debug!("Unknown ssh-key algorithm {}", k.algorithm().as_str());
452 Err(Error::NotAvailable { what: "ssh key algorithm" })
453 }
454 }
455 }
456}
457
458#[cfg(test)]
459pub(crate) mod tests {
460
461 use crate::*;
462 use packets;
463 use sign::*;
464 use sshnames::SSH_NAME_ED25519;
465 use sunsetlog::init_test_log;
466
467 }