#[cfg(feature = "rand")]
use rand::RngCore;
pub const MAGIC: u32 = 0xfeedfeed;
pub const VERSION_01: u32 = 1;
pub const VERSION_02: u32 = 2;
pub const PRIVATE_KEY_TAG: u32 = 1;
pub const TRUSTED_CERT_TAG: u32 = 2;
pub const WHITENER_MESSAGE: &[u8] = b"Mighty Aphrodite";
pub const SALT_LEN: usize = 20;
pub const SUPPORTED_KEY_ALGORITHM_OID: &[u64] = &[1, 3, 6, 1, 4, 1, 42, 2, 17, 1, 1];
pub struct KeyStoreOptions {
pub ordered_aliases: bool,
pub case_exact_aliases: bool,
pub min_password_len: usize,
pub rng: Box<dyn RandomReader>,
pub password_bytes: fn(&[u8]) -> Vec<u8>,
}
impl Clone for KeyStoreOptions {
fn clone(&self) -> Self {
Self {
ordered_aliases: self.ordered_aliases,
case_exact_aliases: self.case_exact_aliases,
min_password_len: self.min_password_len,
rng: Box::new(SystemRandom),
password_bytes: self.password_bytes,
}
}
}
impl std::fmt::Debug for KeyStoreOptions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("KeyStoreOptions")
.field("ordered_aliases", &self.ordered_aliases)
.field("case_exact_aliases", &self.case_exact_aliases)
.field("min_password_len", &self.min_password_len)
.field("password_bytes", &"<fn>")
.finish()
}
}
impl Default for KeyStoreOptions {
fn default() -> Self {
Self {
ordered_aliases: false,
case_exact_aliases: false,
min_password_len: 6,
rng: Box::new(SystemRandom),
password_bytes: password_bytes,
}
}
}
pub trait RandomReader: Send + Sync {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<()>;
}
#[cfg(feature = "rand")]
#[derive(Debug, Clone, Copy)]
pub struct SystemRandom;
#[cfg(feature = "rand")]
impl RandomReader for SystemRandom {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
let mut rng = rand::thread_rng();
rng.fill_bytes(buf);
Ok(())
}
}
#[cfg(not(feature = "rand"))]
pub struct SystemRandom;
#[cfg(not(feature = "rand"))]
impl RandomReader for SystemRandom {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
for b in buf.iter_mut() {
*b = 0;
}
Ok(())
}
}
#[cfg(all(test, feature = "rand"))]
#[derive(Debug, Clone, Copy)]
pub struct FixedRandom(pub u8);
#[cfg(all(test, feature = "rand"))]
impl RandomReader for FixedRandom {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
buf.fill(self.0);
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Certificate {
pub cert_type: String,
pub content: Vec<u8>,
}
impl Certificate {
pub(crate) fn validate(&self) -> super::Result<()> {
use super::KeyStoreError;
if self.cert_type.is_empty() {
return Err(KeyStoreError::EmptyCertificateType);
}
if self.content.is_empty() {
return Err(KeyStoreError::EmptyCertificateContent);
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct PrivateKeyEntry {
pub creation_time: std::time::SystemTime,
pub private_key: Vec<u8>,
pub certificate_chain: Vec<Certificate>,
}
impl PrivateKeyEntry {
pub(crate) fn validate(&self) -> super::Result<()> {
use super::KeyStoreError;
if self.private_key.is_empty() {
return Err(KeyStoreError::EmptyPrivateKey);
}
for cert in self.certificate_chain.iter() {
cert.validate()?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct TrustedCertificateEntry {
pub creation_time: std::time::SystemTime,
pub certificate: Certificate,
}
impl TrustedCertificateEntry {
pub(crate) fn validate(&self) -> super::Result<()> {
self.certificate.validate()
}
}
pub fn password_bytes(password: &[u8]) -> Vec<u8> {
let mut result = Vec::with_capacity(password.len() * 2);
for &b in password {
result.push(0);
result.push(b);
}
result
}
pub fn zeroing(buf: &mut [u8]) {
for b in buf.iter_mut() {
*b = 0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_password_bytes() {
let result = password_bytes(b"test");
assert_eq!(result, vec![0, b't', 0, b'e', 0, b's', 0, b't']);
}
#[test]
fn test_password_bytes_empty() {
let result = password_bytes(b"");
assert!(result.is_empty());
}
#[test]
fn test_zeroing() {
let mut buf = vec![1, 2, 3, 4, 5];
zeroing(&mut buf);
assert_eq!(buf, vec![0, 0, 0, 0, 0]);
}
}