use super::key::KeyType;
use super::usage::Usage;
use openssl::hash::MessageDigest;
use std::collections::HashSet;
macro_rules! vec_str_to_hs {
($vec:expr) => {
$vec.iter()
.map(|s| s.to_string())
.collect::<HashSet<String>>()
};
}
#[derive(Debug, Clone)]
pub enum HashAlg {
SHA1,
SHA256,
SHA384,
SHA512,
}
pub trait BuilderCommon {
fn set_common_name(&mut self, name: &str);
fn set_signer(&mut self, signer: &str);
fn set_country_name(&mut self, name: &str);
fn set_state_province(&mut self, name: &str);
fn set_organization(&mut self, name: &str);
fn set_organization_unit(&mut self, name: &str);
fn set_alternative_names(&mut self, alternative_names: Vec<&str>);
fn set_locality_time(&mut self, locality_time: &str);
fn set_key_type(&mut self, key_type: KeyType);
fn set_signature_alg(&mut self, signature_alg: HashAlg);
fn set_key_usage(&mut self, key_usage: HashSet<Usage>);
}
#[derive(Debug)]
pub struct BuilderFields {
pub(crate) common_name: String,
pub(crate) signer: Option<String>, pub(crate) alternative_names: HashSet<String>,
pub(crate) organization_unit: String,
pub(crate) country_name: String,
pub(crate) state_province: String,
pub(crate) organization: String,
pub(crate) locality_time: String,
pub(crate) key_type: Option<KeyType>,
pub(crate) signature_alg: Option<HashAlg>,
pub(crate) usage: Option<HashSet<Usage>>,
}
impl BuilderCommon for BuilderFields {
fn set_common_name(&mut self, common_name: &str) {
self.common_name = common_name.into();
self.alternative_names.insert(String::from(common_name));
}
fn set_alternative_names(&mut self, alternative_names: Vec<&str>) {
self.alternative_names
.extend(vec_str_to_hs!(alternative_names));
}
fn set_signer(&mut self, signer: &str) {
self.signer = Some(signer.into());
}
fn set_country_name(&mut self, country_name: &str) {
self.country_name = country_name.into();
}
fn set_state_province(&mut self, state_province: &str) {
self.state_province = state_province.into();
}
fn set_organization(&mut self, organization: &str) {
self.organization = organization.into();
}
fn set_organization_unit(&mut self, organization_unit: &str) {
self.organization_unit = organization_unit.into();
}
fn set_locality_time(&mut self, locality_time: &str) {
self.locality_time = locality_time.into();
}
fn set_key_type(&mut self, key_type: KeyType) {
self.key_type = Some(key_type);
}
fn set_signature_alg(&mut self, signature_alg: HashAlg) {
self.signature_alg = Some(signature_alg);
}
fn set_key_usage(&mut self, key_usage: HashSet<Usage>) {
match &mut self.usage {
Some(existing_usage) => {
existing_usage.extend(key_usage);
}
None => {
self.usage = Some(key_usage);
}
};
}
}
impl Default for BuilderFields {
fn default() -> Self {
Self {
common_name: Default::default(),
signer: Default::default(),
alternative_names: Default::default(),
country_name: Default::default(),
state_province: Default::default(),
organization: Default::default(),
organization_unit: Default::default(),
locality_time: Default::default(),
key_type: Default::default(),
signature_alg: Default::default(),
usage: Default::default(),
}
}
}
pub trait UseesBuilderFields: Sized {
fn fields_mut(&mut self) -> &mut BuilderFields;
fn common_name(mut self, common_name: &str) -> Self {
self.fields_mut().set_common_name(common_name);
self
}
fn signer(mut self, signer: &str) -> Self {
self.fields_mut().set_signer(signer);
self
}
fn alternative_names(mut self, alternative_names: Vec<&str>) -> Self {
self.fields_mut().set_alternative_names(alternative_names);
self
}
fn country_name(mut self, country_name: &str) -> Self {
self.fields_mut().set_country_name(country_name);
self
}
fn state_province(mut self, state_province: &str) -> Self {
self.fields_mut().set_state_province(state_province);
self
}
fn organization(mut self, organization: &str) -> Self {
self.fields_mut().set_organization(organization);
self
}
fn locality_time(mut self, locality_time: &str) -> Self {
self.fields_mut().set_locality_time(locality_time);
self
}
fn key_type(mut self, key_type: KeyType) -> Self {
self.fields_mut().set_key_type(key_type);
self
}
fn signature_alg(mut self, signature_alg: HashAlg) -> Self {
self.fields_mut().set_signature_alg(signature_alg);
self
}
fn key_usage(mut self, key_usage: HashSet<Usage>) -> Self {
self.fields_mut().set_key_usage(key_usage);
self
}
}
pub(crate) fn select_hash(hash_type: &Option<HashAlg>) -> MessageDigest {
match hash_type {
Some(HashAlg::SHA1) => MessageDigest::sha1(),
Some(HashAlg::SHA384) => MessageDigest::sha384(),
Some(HashAlg::SHA512) => MessageDigest::sha512(),
_ => MessageDigest::sha256(),
}
}