1use std::str::from_utf8;
13
14use base64;
15use byteorder::{BigEndian, ByteOrder};
16
17
18use {PublicKey, PrivateKey, Error};
19
20struct Cursor<'a> {
21 data: &'a [u8],
22 offset: usize,
23}
24
25struct Asn1<'a> {
26 data: &'a [u8],
27 offset: usize,
28}
29
30
31pub fn parse_public_key(line: &str) -> Result<PublicKey, Error> {
33 let mut iter = line.split_whitespace();
34 let kind = iter.next().ok_or(Error::InvalidFormat)?;
35 let data = iter.next().ok_or(Error::InvalidFormat)?;
36 let buf = b64decode(data.as_bytes())?;
37
38 let mut cur = Cursor::new(&buf);
39 let int_kind = cur.read_string()?;
40 if int_kind != int_kind {
41 return Err(Error::InvalidFormat);
42 }
43
44 match kind {
45 "ssh-rsa" => {
46 let e = cur.read_bytes()?;
47 let n = cur.read_bytes()?;
48 Ok(PublicKey::Rsa { exponent: e.to_vec(), modulus: n.to_vec() })
49 }
50 "ssh-ed25519" => {
51 let key = cur.read_bytes()?;
52 if key.len() != 32 {
53 return Err(Error::InvalidFormat);
54 }
55 let mut array_key = [0u8; 32];
56 array_key.copy_from_slice(key);
57 Ok(PublicKey::Ed25519(array_key))
58 }
59 _ => Err(Error::UnsupportedType(kind.to_string()))
60 }
61}
62
63fn b64decode(data: &[u8]) -> Result<Vec<u8>, Error> {
64 base64::decode_config(data, base64::Config::new(
65 base64::CharacterSet::Standard,
66 true,
67 true,
68 base64::LineWrap::NoWrap, ))
70 .map_err(|_| Error::InvalidFormat)
71}
72
73pub fn parse_private_key(data: &str) -> Result<Vec<PrivateKey>, Error> {
77 if data.starts_with("-----BEGIN RSA PRIVATE KEY-----") {
78 let end = data.find("-----END RSA PRIVATE KEY-----")
79 .ok_or(Error::InvalidFormat)?;
80 let start = match (data[..end].find("\n\n"),
81 data[..end].find("\r\n\r\n"))
82 {
83 (Some(x), Some(y)) if x < y => x,
84 (Some(_), Some(y)) => y,
85 (Some(x), None) => x,
86 (None, Some(y)) => y,
87 (None, None) => "-----BEGIN RSA PRIVATE KEY-----".len(),
88 };
89 let data = b64decode(data[start..end].trim().as_bytes())?;
90 let mut cur = Asn1::new(&data);
91 let mut items = cur.sequence()?;
92 let ver = items.read_short_int()?;
93 if ver != 0 {
94 return Err(Error::UnsupportedType(format!("version {}", ver)));
95 }
96 let n = items.read_big_int()?;
97 let e = items.read_big_int()?;
98 let d = items.read_big_int()?;
99 let p = items.read_big_int()?;
100 let q = items.read_big_int()?;
101 let _x = items.read_big_int()?;
102 let _y = items.read_big_int()?;
103 let iqmp = items.read_big_int()?;
104 return Ok(vec![PrivateKey::Rsa {
105 n: n.to_vec(), e: e.to_vec(), d: d.to_vec(),
106 iqmp: iqmp.to_vec(),
107 p: p.to_vec(), q: q.to_vec(),
108 }]);
109 } else if data.starts_with("-----BEGIN OPENSSH PRIVATE KEY-----") {
110 let start = "-----BEGIN OPENSSH PRIVATE KEY-----".len();
111 let end = data.find("-----END OPENSSH PRIVATE KEY-----")
112 .ok_or(Error::InvalidFormat)?;
113 if start >= end {
114 return Err(Error::InvalidFormat);
115 }
116 let data = b64decode(data[start..end].trim().as_bytes())?;
117 let end = data.iter().position(|&x| x == 0)
118 .ok_or(Error::InvalidFormat)?;
119 let kind = from_utf8(&data[..end]).map_err(|_| Error::InvalidFormat)?;
120 match kind {
121 "openssh-key-v1" => {
122 let mut cur = Cursor::new(&data[end+1..]);
123 let cipher_name = cur.read_string()?;
124 let kdf_name = cur.read_string()?;
125 let opt = cur.read_string()?;
126 if cipher_name != "none" || kdf_name != "none" || opt != "" {
127 return Err(Error::Encrypted);
128 }
129 let num_keys = cur.read_int()?;
130 let mut result = Vec::new();
131 for _ in 0..num_keys {
132 let _pub_key = cur.read_bytes()?;
133 let priv_key = cur.read_bytes()?;
134 let mut pcur = Cursor::new(priv_key);
135 let c1 = pcur.read_int()?;
136 let c2 = pcur.read_int()?;
137 if c1 != c2 {
138 return Err(Error::InvalidFormat);
139 }
140 let key_type = pcur.read_string()?;
141 match key_type {
142 "ssh-ed25519" => {
143 let _pub_key = pcur.read_bytes()?;
144 let priv_key = pcur.read_bytes()?;
145 let _comment = pcur.read_string()?;
146
147 let mut array_key = [0u8; 64];
148 array_key.copy_from_slice(priv_key);
149 result.push(PrivateKey::Ed25519(array_key));
150 }
151 "ssh-rsa" => {
152 let n = pcur.read_bytes()?;
153 let e = pcur.read_bytes()?;
154 let d = pcur.read_bytes()?;
155 let iqmp = pcur.read_bytes()?;
156 let p = pcur.read_bytes()?;
157 let q = pcur.read_bytes()?;
158 let _comment = pcur.read_string()?;
159 result.push(PrivateKey::Rsa {
160 n: n.to_vec(), e: e.to_vec(), d: d.to_vec(),
161 iqmp: iqmp.to_vec(),
162 p: p.to_vec(), q: q.to_vec(),
163 })
164 }
165 _ => {
166 return Err(Error::UnsupportedType(
167 key_type.to_string()));
168 }
169 }
170 }
171 return Ok(result);
172 }
173 _ => return Err(Error::UnsupportedType(kind.to_string())),
174 }
175 } else {
176 Err(Error::UnsupportedType("unknown".to_string()))
177 }
178}
179
180impl<'a> Cursor<'a> {
181 pub fn new(data: &[u8]) -> Cursor {
182 Cursor {
183 data: data,
184 offset: 0,
185 }
186 }
187 fn read_int(&mut self) -> Result<u32, Error> {
188 let cur = &self.data[self.offset..];
189 if cur.len() < 4 {
190 return Err(Error::InvalidFormat);
191 }
192 self.offset += 4;
193 return Ok(BigEndian::read_u32(&cur[..4]));
194 }
195 fn read_bytes(&mut self) -> Result<&'a [u8], Error> {
196 let cur = &self.data[self.offset..];
197 if cur.len() < 4 {
198 return Err(Error::InvalidFormat);
199 }
200 let len = BigEndian::read_u32(&cur[..4]) as usize;
201 if cur.len() < len + 4 {
202 return Err(Error::InvalidFormat);
203 }
204 self.offset += len + 4;
205 return Ok(&cur[4..len+4]);
206 }
207 fn read_string(&mut self) -> Result<&'a str, Error> {
208 from_utf8(self.read_bytes()?)
209 .map_err(|_| Error::InvalidFormat)
210 }
211}
212
213
214impl<'a> Asn1<'a> {
216 pub fn new(data: &[u8]) -> Asn1 {
217 Asn1 {
218 data: data,
219 offset: 0,
220 }
221 }
222 fn read_len(&mut self) -> Result<usize, Error> {
223 if self.offset >= self.data.len() {
224 return Err(Error::InvalidFormat);
225 }
226 let lbyte = self.data[self.offset];
227 self.offset += 1;
228 if lbyte == 128 || lbyte == 255 {
229 return Err(Error::InvalidFormat);
230 }
231 if lbyte & 128 == 0 {
232 return Ok(lbyte as usize);
233 }
234 let nbytes = (lbyte & 127) as usize;
235 if self.data.len() < self.offset + nbytes {
236 return Err(Error::InvalidFormat);
237 }
238 let mut result: usize = 0;
239 for i in 0..nbytes {
240 result = result.checked_mul(256).ok_or(Error::InvalidFormat)?
241 + self.data[self.offset+i] as usize;
242 }
243 self.offset += nbytes;
244 return Ok(result);
245 }
246 pub fn sequence(&mut self) -> Result<Asn1<'a>, Error> {
247 if self.offset >= self.data.len() {
248 return Err(Error::InvalidFormat);
249 }
250 let byte = self.data[self.offset];
251 if byte != (0 << 6) | (1 << 5) | 16 {
253 return Err(Error::InvalidFormat);
254 }
255 self.offset += 1;
256 let bytes = self.read_len()?;
257 if self.offset+bytes > self.data.len() {
258 return Err(Error::InvalidFormat);
259 }
260 let res = Asn1::new(&self.data[self.offset..self.offset+bytes]);
261 self.offset += bytes;
262 return Ok(res);
263 }
264 pub fn read_big_int(&mut self) -> Result<&'a [u8], Error> {
265 if self.offset >= self.data.len() {
266 return Err(Error::InvalidFormat);
267 }
268 let byte = self.data[self.offset];
269 if byte != (0 << 6) | (0 << 5) | 2 {
271 return Err(Error::InvalidFormat);
272 }
273 self.offset += 1;
274 let len = self.read_len()?;
275 if self.data.len() < self.offset + len {
276 return Err(Error::InvalidFormat);
277 }
278 let result = &self.data[self.offset..self.offset + len];
279 self.offset += len;
280 return Ok(result);
281 }
282 pub fn read_short_int(&mut self) -> Result<u8, Error> {
283 let data = self.read_big_int()?;
284 if data.len() != 1 {
285 return Err(Error::InvalidFormat);
286 }
287 return Ok(data[0]);
288 }
289}