rustica_keys/ssh/
privkey.rs1use super::keytype::{Curve, KeyType, KeyTypeKind};
2use super::error::{Error, ErrorKind};
3use super::PublicKey;
4use super::reader::Reader;
5
6use std::fs::File;
7use std::io::{Read};
8use std::path::Path;
9
10#[derive(Debug, PartialEq, Clone)]
12pub struct RsaPrivateKey {
13 pub d: Vec<u8>,
15
16 pub n: Vec<u8>,
18}
19
20#[derive(Debug, PartialEq, Clone)]
22pub struct EcdsaPrivateKey {
23 pub curve: Curve,
25
26 pub key: Vec<u8>,
28}
29
30#[derive(Debug, PartialEq, Clone)]
32pub struct Ed25519PrivateKey {
33 pub key: Vec<u8>,
35}
36
37#[derive(Debug, PartialEq, Clone)]
39pub enum PrivateKeyKind {
40 Rsa(RsaPrivateKey),
42
43 Ecdsa(EcdsaPrivateKey),
45
46 Ed25519(Ed25519PrivateKey),
48}
49
50#[derive(Debug, PartialEq, Clone)]
52pub struct PrivateKey {
53 pub key_type: KeyType,
55
56 pub kind: PrivateKeyKind,
58
59 pub pubkey: PublicKey,
61
62 pub comment: Option<String>,
64}
65
66impl PrivateKey {
67 pub fn from_path<P: AsRef<Path>>(path: P) -> Result<PrivateKey, Error> {
69 let mut contents = String::new();
70 File::open(path)?.read_to_string(&mut contents)?;
71
72 PrivateKey::from_string(&contents)
73 }
74
75 pub fn from_string(contents: &str) -> Result<PrivateKey, Error> {
77 let mut iter = contents.lines();
78 let header = iter.next().unwrap_or("");
79 if header != "-----BEGIN OPENSSH PRIVATE KEY-----" {
80 return Err(Error::with_kind(ErrorKind::InvalidFormat));
81 }
82
83 let mut encoded_key = String::new();
84 loop {
85 let part = match iter.next() {
86 Some(p) => p,
87 None => return Err(Error::with_kind(ErrorKind::InvalidFormat)),
88 };
89
90 if part == "-----END OPENSSH PRIVATE KEY-----" {
91 break;
92 }
93 encoded_key.push_str(part);
94 }
95
96 let decoded = base64::decode(encoded_key)?;
97 let mut reader = Reader::new(&decoded);
98
99 let k = PrivateKey::from_reader(&mut reader)?;
101
102 Ok(k)
103 }
104
105 pub(crate) fn from_reader(reader: &mut Reader) -> Result<PrivateKey, Error> {
107 let preamble = reader.read_cstring()?;
108
109 if preamble != "openssh-key-v1" {
110 return Err(Error::with_kind(ErrorKind::InvalidFormat));
111 }
112
113 let cipher_name = reader.read_string()?;
115 let kdf = reader.read_string()?;
116 if cipher_name != "none" || kdf != "none" {
117 return Err(Error::with_kind(ErrorKind::EncryptedPrivateKeyNotSupported));
118 }
119
120 reader.read_string()?;
122
123 let number_of_keys = reader.read_u32()?;
125 if number_of_keys != 1 {
126 return Err(Error::with_kind(ErrorKind::InvalidFormat));
127 }
128
129 let pubkey = reader
131 .read_bytes()
132 .and_then(|v| PublicKey::from_bytes(&v))?;
133
134 let _remaining_length = reader.read_u32()?;
139
140 let c1 = reader.read_u32()?;
142 let c2 = reader.read_u32()?;
143
144 if c1 != c2 {
145 return Err(Error::with_kind(ErrorKind::InvalidFormat));
146 }
147
148 let key_type = reader.read_string()?;
150 let kt = KeyType::from_name(&key_type)?;
151
152 let kind = match kt.kind {
153 KeyTypeKind::Ecdsa => {
162 let identifier = reader.read_string()?;
163 let curve = Curve::from_identifier(&identifier)?;
164 let _pubkey = reader.read_bytes()?;
166 let key = reader.read_bytes()?;
167 let k = EcdsaPrivateKey {
168 curve,
169 key,
170 };
171
172 PrivateKeyKind::Ecdsa(k)
173 }
174 _ => return Err(Error::with_kind(ErrorKind::UnknownKeyType(kt.name.to_string()))),
182 };
183
184 Ok(PrivateKey {
185 key_type: kt,
186 kind,
187 pubkey,
188 comment: None,
189 })
190 }
191}
192