minijks/
lib.rs

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/// Java KeyStore version
14/// Support only Version 2
15#[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}