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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use chrono::Datelike;
use core::convert::TryFrom;
use p12::PFX;
use rcgen::{
    BasicConstraints, Certificate, CertificateParams, ExtendedKeyUsagePurpose::*, IsCa,
    KeyIdMethod, KeyPair, RcgenError,
};
use std::net::IpAddr;

#[derive(Debug)]
pub enum Error {
    PFXError,
    RcgenError(RcgenError),
    PemError(pem::PemError),
}

impl From<RcgenError> for Error {
    fn from(src: RcgenError) -> Error {
        Error::RcgenError(src)
    }
}

impl From<pem::PemError> for Error {
    fn from(src: pem::PemError) -> Error {
        Error::PemError(src)
    }
}

pub struct CA(Certificate, Option<Vec<u8>>);

impl CA {
    pub fn from_pem(ca_cert: &str, ca_key: &str) -> Result<Self, Error> {
        let key = KeyPair::from_pem(ca_key)?;
        let params = CertificateParams::from_ca_cert_pem(ca_cert, key)?;
        let ca_data = pem::parse(ca_cert)?.contents;
        let mut result = Self::from_params(params)?;
        result.1 = Some(ca_data);
        Ok(result)
    }
    pub fn from_der(ca_cert: &[u8], ca_key: &[u8]) -> Result<Self, Error> {
        let key = KeyPair::try_from(ca_key)?;
        let params = CertificateParams::from_ca_cert_der(ca_cert, key)?;
        let mut result = Self::from_params(params)?;
        result.1 = Some(ca_cert.to_owned());
        Ok(result)
    }
    pub fn from_params(mut params: CertificateParams) -> Result<Self, Error> {
        if let IsCa::SelfSignedOnly = params.is_ca {
            params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
        }
        Ok(CA(Certificate::from_params(params)?, None))
    }
    pub fn make_pfx(
        &self,
        cert: &Cert,
        password: &str,
        friendly_name: &str,
    ) -> Result<Vec<u8>, Error> {
        let cert_der = cert.0.serialize_der_with_signer(&self.0)?;
        let key_der = cert.0.serialize_private_key_der();

        let ca_der = self.serialize_der()?;

        Ok(
            PFX::new(&cert_der, &key_der, Some(&ca_der), password, friendly_name)
                .ok_or_else(|| Error::PFXError)?
                .to_der(),
        )
    }

    pub fn serialize_der(&self) -> Result<Vec<u8>, Error> {
        match &self.1 {
            Some(data) => Ok(data.to_owned()),
            None => Ok(self.0.serialize_der()?),
        }
    }

    pub fn serialize_pem(&self) -> Result<String, Error> {
        let p = pem::Pem {
            tag: "CERTIFICATE".to_string(),
            contents: self.serialize_der()?,
        };
        Ok(pem::encode(&p))
    }
    pub fn serialize_private_key_pem(&self) -> String {
        self.0.serialize_private_key_pem()
    }
    pub fn serialize_private_key_der(&self) -> Vec<u8> {
        self.0.serialize_private_key_der()
    }
}

pub struct Cert(Certificate);

impl Cert {
    pub fn from_params(params: CertificateParams) -> Result<Self, Error> {
        Ok(Cert(Certificate::from_params(params)?))
    }
}

pub struct Params {
    pub domain_names: Vec<String>,
    pub ip_address: Vec<IpAddr>,
    pub country: String,
    pub organization: String,
    pub common: String,
}

impl Params {
    fn build_cert_params(&self) -> CertificateParams {
        use chrono::offset::Utc;
        use rcgen::{DistinguishedName, DnType, SanType, PKCS_ECDSA_P256_SHA256};
        let alg = &PKCS_ECDSA_P256_SHA256;
        let not_before = Utc::now();
        let not_after = not_before.with_year(not_before.year() + 1).unwrap();
        let mut subject_alt_names = vec![];
        for dns in self.domain_names.iter() {
            subject_alt_names.push(SanType::DnsName(dns.to_owned()));
        }
        for ip in self.ip_address.iter() {
            subject_alt_names.push(SanType::IpAddress(ip.to_owned()));
        }
        let mut distinguished_name = DistinguishedName::new();
        distinguished_name.push(DnType::CountryName, &self.country);
        distinguished_name.push(DnType::OrganizationName, &self.organization);
        distinguished_name.push(DnType::CommonName, &self.common);
        let extended_key_usages = vec![ServerAuth, ClientAuth];
        let mut params = CertificateParams::default();
        params.alg = alg;
        params.not_before = not_before;
        params.not_after = not_after;
        params.subject_alt_names = subject_alt_names;
        params.distinguished_name = distinguished_name;
        params.extended_key_usages = extended_key_usages;
        params.use_authority_key_identifier_extension = true;
        params.key_identifier_method = KeyIdMethod::Sha512;
        params
    }
    pub fn ca(&self) -> Result<CA, Error> {
        let mut params = self.build_cert_params();
        params.not_after = params
            .not_before
            .with_year(params.not_before.year() + 10)
            .unwrap();
        params.extended_key_usages = vec![Any];
        CA::from_params(params)
    }
    pub fn cert(&self) -> Result<Cert, Error> {
        let params = self.build_cert_params();
        Cert::from_params(params)
    }
}