1pub mod read;
2
3use core::panic;
4use std::collections::HashMap;
5use std::error::Error;
6use std::io::{BufReader, Read};
7
8use read::read_cert;
9use x509_certificate::certificate::X509Certificate;
10
11const MAGIC: [u8; 4] = [0xFE, 0xED, 0xFE, 0xED];
12
13#[derive(PartialEq)]
16enum Version {
17 Unsupported,
18 V2,
19}
20
21impl From<[u8; 4]> for Version {
22 fn from(value: [u8; 4]) -> Self {
23 match u32::from_be_bytes(value) {
24 2 => Version::V2,
25 _ => Version::Unsupported,
26 }
27 }
28}
29
30#[derive(PartialEq)]
31enum EntryType {
32 KeyPair,
33 Certs,
34}
35
36impl From<[u8; 4]> for EntryType {
37 fn from(value: [u8; 4]) -> Self {
38 match u32::from_be_bytes(value) {
39 1 => EntryType::KeyPair,
40 2 => EntryType::Certs,
41 _ => panic!("invalid entry type"),
42 }
43 }
44}
45
46#[derive(Debug)]
47pub struct Store {
48 pub certs: Vec<CertInfo>,
49 pub key_pairs: Vec<KeyPair>,
50}
51
52#[derive(Debug)]
53pub struct CertInfo {
54 pub alias: String,
55 pub timestamp: u64,
56 pub certificate: Cert,
57}
58
59#[derive(Debug)]
60pub struct Cert {
61 pub raw: Vec<u8>,
62 pub cert: X509Certificate,
63}
64
65#[derive(Debug)]
66pub struct KeyPair {
67 pub alias: String,
68 pub timestamp: u64,
69 pub encrypted_key: Vec<u8>,
70 pub cert_chain: Vec<KeyPairCert>,
71}
72
73#[derive(Debug)]
74pub struct KeyPairCert {
75 pub raw: Vec<u8>,
76 pub cert: X509Certificate,
77}
78
79#[derive(Debug)]
80pub struct Options {
81 pub password: String,
82 pub skip_verify: bool,
83 pub key_passwords: HashMap<String, String>,
84}
85
86impl Default for Options {
87 fn default() -> Self {
88 Options {
89 password: "changeit".to_owned(),
90 skip_verify: false,
91 key_passwords: HashMap::new(),
92 }
93 }
94}
95
96impl Store {
97 pub fn parse(data: impl AsRef<[u8]>, opts: Option<Options>) -> Result<Self, Box<dyn Error>> {
98 let mut buffer = BufReader::new(data.as_ref());
99
100 let magic = read::read_u32(&mut buffer)?;
101 if !magic.eq(&MAGIC) {
102 return Err(format!(
103 "invalid file format, expected header '{:#x?}', but got '{:#x?}'",
104 MAGIC, magic
105 ))?;
106 }
107 let version = read::read_u32(&mut buffer)?;
108 if Version::from(version) == Version::Unsupported {
109 return Err("unsupported version, supported only version 2".to_owned())?;
110 }
111 let mut key_pairs: Vec<KeyPair> = vec![];
112 let mut certs: Vec<CertInfo> = vec![];
113 let mut opts = opts.unwrap_or_default();
114
115 let entries = u32::from_be_bytes(read::read_u32(&mut buffer)?);
116 for _ in 0..entries {
117 let entry_type = EntryType::from(read::read_u32(&mut buffer)?);
118 match entry_type {
119 EntryType::KeyPair => key_pairs.push(process_key_pair(&mut buffer, &mut opts)?),
120 EntryType::Certs => certs.push(process_cert(&mut buffer)?),
121 }
122 }
123
124 Ok(Store { certs, key_pairs })
125 }
126}
127
128fn process_cert<T>(data: &mut BufReader<T>) -> Result<CertInfo, Box<dyn Error>>
129where
130 T: Read,
131{
132 let alias = read::read_str(data)?;
133 let timestamp = read::read_timestamp(data)?;
134 let certificate = read::read_cert(data)?;
135 Ok(CertInfo {
136 alias,
137 timestamp,
138 certificate,
139 })
140}
141
142fn process_key_pair<T>(
143 data: &mut BufReader<T>,
144 opts: &mut Options,
145) -> Result<KeyPair, Box<dyn Error>>
146where
147 T: Read,
148{
149 let alias = read::read_str(data)?;
150 let timestamp = read::read_timestamp(data)?;
151 let _password = opts.key_passwords.get(&alias).unwrap_or(&opts.password);
152 let enc_key_len = u32::from_be_bytes(read::read_u32(data)?);
153 let enc_key = read::read_bytes(data, enc_key_len as usize)?;
154 let certs_entries_count = u32::from_be_bytes(read::read_u32(data)?);
155 let mut cert_chains = vec![];
156 for _ in 0..certs_entries_count {
157 let cert = read_cert(data)?;
158 let kps = KeyPairCert {
159 raw: cert.raw,
160 cert: cert.cert,
161 };
162 cert_chains.push(kps);
163 }
164
165 Ok(KeyPair {
166 alias,
167 timestamp,
168 encrypted_key: enc_key,
169 cert_chain: cert_chains,
170 })
171}