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