1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use base64;
use std::io::{self, ErrorKind};
#[non_exhaustive]
#[derive(Debug, PartialEq)]
pub enum Item {
X509Certificate(Vec<u8>),
RSAKey(Vec<u8>),
PKCS8Key(Vec<u8>),
ECKey(Vec<u8>),
}
impl Item {
fn from_start_line(start_line: &str, der: Vec<u8>) -> Option<Item> {
match start_line {
"CERTIFICATE" => Some(Item::X509Certificate(der)),
"RSA PRIVATE KEY" => Some(Item::RSAKey(der)),
"PRIVATE KEY" => Some(Item::PKCS8Key(der)),
"EC PRIVATE KEY" => Some(Item::ECKey(der)),
_ => None,
}
}
}
pub fn read_one(rd: &mut dyn io::BufRead) -> Result<Option<Item>, io::Error> {
let mut b64buf = String::with_capacity(1024);
let mut section_type = None;
let mut end_marker = None;
let mut line = String::with_capacity(80);
loop {
line.clear();
let len = rd.read_line(&mut line)?;
if len == 0 {
if end_marker.is_some() {
return Err(io::Error::new(
ErrorKind::InvalidData,
format!("section end {:?} missing", end_marker.unwrap()),
));
}
return Ok(None);
}
if line.starts_with("-----BEGIN ") {
let trailer = line[11..]
.find("-----")
.ok_or_else(|| {
io::Error::new(
ErrorKind::InvalidData,
format!("illegal section start: {:?}", line),
)
})?;
let ty = &line[11..11 + trailer];
section_type = Some(ty.to_string());
end_marker = Some(format!("-----END {}-----", ty).to_string());
continue;
}
if end_marker.is_some() && line.starts_with(end_marker.as_ref().unwrap()) {
let der = base64::decode(&b64buf)
.map_err(|err| io::Error::new(ErrorKind::InvalidData, err))?;
let item = Item::from_start_line(§ion_type.unwrap(), der);
if let Some(item) = item {
return Ok(Some(item));
} else {
section_type = None;
end_marker = None;
b64buf.clear();
}
}
if section_type.is_some() {
b64buf.push_str(line.trim());
}
}
}
pub fn read_all(rd: &mut dyn io::BufRead) -> Result<Vec<Item>, io::Error> {
let mut v = Vec::<Item>::new();
loop {
match read_one(rd)? {
None => return Ok(v),
Some(item) => v.push(item),
}
}
}