1use crate::{decode::Decode, encode::Encode, reader::Reader, writer::Writer, Error, Result};
4use core::{fmt, str};
5
6const BCRYPT: &str = "bcrypt";
8
9const CERT_DSA: &str = "ssh-dss-cert-v01@openssh.com";
11
12const CERT_ECDSA_SHA2_P256: &str = "ecdsa-sha2-nistp256-cert-v01@openssh.com";
14
15const CERT_ECDSA_SHA2_P384: &str = "ecdsa-sha2-nistp384-cert-v01@openssh.com";
17
18const CERT_ECDSA_SHA2_P521: &str = "ecdsa-sha2-nistp521-cert-v01@openssh.com";
20
21const CERT_ED25519: &str = "ssh-ed25519-cert-v01@openssh.com";
23
24const CERT_RSA: &str = "ssh-rsa-cert-v01@openssh.com";
26
27const CERT_SK_ECDSA_SHA2_P256: &str = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com";
29
30const CERT_SK_SSH_ED25519: &str = "sk-ssh-ed25519-cert-v01@openssh.com";
32
33const ECDSA_SHA2_P256: &str = "ecdsa-sha2-nistp256";
35
36const ECDSA_SHA2_P384: &str = "ecdsa-sha2-nistp384";
38
39const ECDSA_SHA2_P521: &str = "ecdsa-sha2-nistp521";
41
42const NONE: &str = "none";
44
45const RSA_SHA2_256: &str = "rsa-sha2-256";
47
48const RSA_SHA2_512: &str = "rsa-sha2-512";
50
51const SHA256: &str = "SHA256";
53
54const SHA512: &str = "SHA512";
56
57const SSH_DSA: &str = "ssh-dss";
59
60const SSH_ED25519: &str = "ssh-ed25519";
62
63const SSH_RSA: &str = "ssh-rsa";
65
66const SK_ECDSA_SHA2_P256: &str = "sk-ecdsa-sha2-nistp256@openssh.com";
68
69const SK_SSH_ED25519: &str = "sk-ssh-ed25519@openssh.com";
71
72const MAX_ALG_NAME_SIZE: usize = 48;
74
75pub(crate) trait AlgString: AsRef<str> + str::FromStr<Err = Error> {}
79
80impl<T: AlgString> Decode for T {
81 fn decode(reader: &mut impl Reader) -> Result<Self> {
82 let mut buf = [0u8; MAX_ALG_NAME_SIZE];
83 reader
84 .read_string(buf.as_mut())
85 .map_err(|_| Error::Algorithm)?
86 .parse()
87 }
88}
89
90impl<T: AlgString> Encode for T {
91 fn encoded_len(&self) -> Result<usize> {
92 self.as_ref().encoded_len()
93 }
94
95 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
96 self.as_ref().encode(writer)
97 }
98}
99
100#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
105#[non_exhaustive]
106pub enum Algorithm {
107 Dsa,
109
110 Ecdsa {
112 curve: EcdsaCurve,
114 },
115
116 Ed25519,
118
119 Rsa {
121 hash: Option<HashAlg>,
129 },
130
131 SkEcdsaSha2NistP256,
133
134 SkEd25519,
136}
137
138impl Algorithm {
139 pub fn new(id: &str) -> Result<Self> {
151 match id {
152 SSH_DSA => Ok(Algorithm::Dsa),
153 ECDSA_SHA2_P256 => Ok(Algorithm::Ecdsa {
154 curve: EcdsaCurve::NistP256,
155 }),
156 ECDSA_SHA2_P384 => Ok(Algorithm::Ecdsa {
157 curve: EcdsaCurve::NistP384,
158 }),
159 ECDSA_SHA2_P521 => Ok(Algorithm::Ecdsa {
160 curve: EcdsaCurve::NistP521,
161 }),
162 RSA_SHA2_256 => Ok(Algorithm::Rsa {
163 hash: Some(HashAlg::Sha256),
164 }),
165 RSA_SHA2_512 => Ok(Algorithm::Rsa {
166 hash: Some(HashAlg::Sha512),
167 }),
168 SSH_ED25519 => Ok(Algorithm::Ed25519),
169 SSH_RSA => Ok(Algorithm::Rsa { hash: None }),
170 SK_ECDSA_SHA2_P256 => Ok(Algorithm::SkEcdsaSha2NistP256),
171 SK_SSH_ED25519 => Ok(Algorithm::SkEd25519),
172 _ => Err(Error::Algorithm),
173 }
174 }
175
176 pub fn new_certificate(id: &str) -> Result<Self> {
194 match id {
195 CERT_DSA => Ok(Algorithm::Dsa),
196 CERT_ECDSA_SHA2_P256 => Ok(Algorithm::Ecdsa {
197 curve: EcdsaCurve::NistP256,
198 }),
199 CERT_ECDSA_SHA2_P384 => Ok(Algorithm::Ecdsa {
200 curve: EcdsaCurve::NistP384,
201 }),
202 CERT_ECDSA_SHA2_P521 => Ok(Algorithm::Ecdsa {
203 curve: EcdsaCurve::NistP521,
204 }),
205 CERT_ED25519 => Ok(Algorithm::Ed25519),
206 CERT_RSA => Ok(Algorithm::Rsa { hash: None }),
207 CERT_SK_ECDSA_SHA2_P256 => Ok(Algorithm::SkEcdsaSha2NistP256),
208 CERT_SK_SSH_ED25519 => Ok(Algorithm::SkEd25519),
209 _ => Err(Error::Algorithm),
210 }
211 }
212
213 pub fn as_str(self) -> &'static str {
215 match self {
216 Algorithm::Dsa => SSH_DSA,
217 Algorithm::Ecdsa { curve } => match curve {
218 EcdsaCurve::NistP256 => ECDSA_SHA2_P256,
219 EcdsaCurve::NistP384 => ECDSA_SHA2_P384,
220 EcdsaCurve::NistP521 => ECDSA_SHA2_P521,
221 },
222 Algorithm::Ed25519 => SSH_ED25519,
223 Algorithm::Rsa { hash } => match hash {
224 None => SSH_RSA,
225 Some(HashAlg::Sha256) => RSA_SHA2_256,
226 Some(HashAlg::Sha512) => RSA_SHA2_512,
227 },
228 Algorithm::SkEcdsaSha2NistP256 => SK_ECDSA_SHA2_P256,
229 Algorithm::SkEd25519 => SK_SSH_ED25519,
230 }
231 }
232
233 pub fn as_certificate_str(self) -> &'static str {
241 match self {
242 Algorithm::Dsa => CERT_DSA,
243 Algorithm::Ecdsa { curve } => match curve {
244 EcdsaCurve::NistP256 => CERT_ECDSA_SHA2_P256,
245 EcdsaCurve::NistP384 => CERT_ECDSA_SHA2_P384,
246 EcdsaCurve::NistP521 => CERT_ECDSA_SHA2_P521,
247 },
248 Algorithm::Ed25519 => CERT_ED25519,
249 Algorithm::Rsa { .. } => CERT_RSA,
250 Algorithm::SkEcdsaSha2NistP256 => CERT_SK_ECDSA_SHA2_P256,
251 Algorithm::SkEd25519 => CERT_SK_SSH_ED25519,
252 }
253 }
254
255 pub fn is_dsa(self) -> bool {
257 self == Algorithm::Dsa
258 }
259
260 pub fn is_ecdsa(self) -> bool {
262 matches!(self, Algorithm::Ecdsa { .. })
263 }
264
265 pub fn is_ed25519(self) -> bool {
267 self == Algorithm::Ed25519
268 }
269
270 pub fn is_rsa(self) -> bool {
272 matches!(self, Algorithm::Rsa { .. })
273 }
274}
275
276impl AsRef<str> for Algorithm {
277 fn as_ref(&self) -> &str {
278 self.as_str()
279 }
280}
281
282impl AlgString for Algorithm {}
283
284impl Default for Algorithm {
285 fn default() -> Algorithm {
286 Algorithm::Ed25519
287 }
288}
289
290impl fmt::Display for Algorithm {
291 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292 f.write_str(self.as_str())
293 }
294}
295
296impl str::FromStr for Algorithm {
297 type Err = Error;
298
299 fn from_str(id: &str) -> Result<Self> {
300 Self::new(id)
301 }
302}
303
304#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
306pub enum EcdsaCurve {
307 NistP256,
309
310 NistP384,
312
313 NistP521,
315}
316
317impl EcdsaCurve {
318 pub fn new(id: &str) -> Result<Self> {
326 match id {
327 "nistp256" => Ok(EcdsaCurve::NistP256),
328 "nistp384" => Ok(EcdsaCurve::NistP384),
329 "nistp521" => Ok(EcdsaCurve::NistP521),
330 _ => Err(Error::Algorithm),
331 }
332 }
333
334 pub fn as_str(self) -> &'static str {
336 match self {
337 EcdsaCurve::NistP256 => "nistp256",
338 EcdsaCurve::NistP384 => "nistp384",
339 EcdsaCurve::NistP521 => "nistp521",
340 }
341 }
342
343 #[cfg(feature = "alloc")]
345 pub(crate) const fn field_size(self) -> usize {
346 match self {
347 EcdsaCurve::NistP256 => 32,
348 EcdsaCurve::NistP384 => 48,
349 EcdsaCurve::NistP521 => 66,
350 }
351 }
352}
353
354impl AsRef<str> for EcdsaCurve {
355 fn as_ref(&self) -> &str {
356 self.as_str()
357 }
358}
359
360impl AlgString for EcdsaCurve {}
361
362impl fmt::Display for EcdsaCurve {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 f.write_str(self.as_str())
365 }
366}
367
368impl str::FromStr for EcdsaCurve {
369 type Err = Error;
370
371 fn from_str(id: &str) -> Result<Self> {
372 EcdsaCurve::new(id)
373 }
374}
375
376#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
378#[non_exhaustive]
379pub enum HashAlg {
380 Sha256,
382
383 Sha512,
385}
386
387impl HashAlg {
388 pub fn new(id: &str) -> Result<Self> {
395 match id {
396 SHA256 => Ok(HashAlg::Sha256),
397 SHA512 => Ok(HashAlg::Sha512),
398 _ => Err(Error::Algorithm),
399 }
400 }
401
402 pub fn as_str(self) -> &'static str {
404 match self {
405 HashAlg::Sha256 => SHA256,
406 HashAlg::Sha512 => SHA512,
407 }
408 }
409
410 pub const fn digest_size(self) -> usize {
412 match self {
413 HashAlg::Sha256 => 32,
414 HashAlg::Sha512 => 64,
415 }
416 }
417}
418
419impl AsRef<str> for HashAlg {
420 fn as_ref(&self) -> &str {
421 self.as_str()
422 }
423}
424
425impl Default for HashAlg {
426 fn default() -> Self {
427 HashAlg::Sha256
428 }
429}
430
431impl fmt::Display for HashAlg {
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 f.write_str(self.as_str())
434 }
435}
436
437impl str::FromStr for HashAlg {
438 type Err = Error;
439
440 fn from_str(id: &str) -> Result<Self> {
441 HashAlg::new(id)
442 }
443}
444
445#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
447#[non_exhaustive]
448pub enum KdfAlg {
449 None,
451
452 Bcrypt,
454}
455
456impl KdfAlg {
457 pub fn new(kdfname: &str) -> Result<Self> {
462 match kdfname {
463 NONE => Ok(Self::None),
464 BCRYPT => Ok(Self::Bcrypt),
465 _ => Err(Error::Algorithm),
466 }
467 }
468
469 pub fn as_str(self) -> &'static str {
471 match self {
472 Self::None => NONE,
473 Self::Bcrypt => BCRYPT,
474 }
475 }
476
477 pub fn is_none(self) -> bool {
479 self == Self::None
480 }
481}
482
483impl AsRef<str> for KdfAlg {
484 fn as_ref(&self) -> &str {
485 self.as_str()
486 }
487}
488
489impl AlgString for KdfAlg {}
490
491impl Default for KdfAlg {
492 fn default() -> KdfAlg {
493 KdfAlg::Bcrypt
494 }
495}
496
497impl fmt::Display for KdfAlg {
498 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499 f.write_str(self.as_str())
500 }
501}
502
503impl str::FromStr for KdfAlg {
504 type Err = Error;
505
506 fn from_str(id: &str) -> Result<Self> {
507 Self::new(id)
508 }
509}