use lazy_static::lazy_static;
use openssl::ec::{Asn1Flag, EcGroup, EcKey};
use openssl::hash::MessageDigest;
use openssl::nid::Nid;
use openssl::pkey::{self, PKey};
use openssl::rsa::Rsa;
use openssl::stack::Stack;
use openssl::x509::extension::SubjectAlternativeName;
use openssl::x509::{X509Req, X509ReqBuilder, X509};
use crate::Result;
lazy_static! {
pub(crate) static ref EC_GROUP_P256: EcGroup = ec_group(Nid::X9_62_PRIME256V1);
pub(crate) static ref EC_GROUP_P384: EcGroup = ec_group(Nid::SECP384R1);
}
fn ec_group(nid: Nid) -> EcGroup {
let mut g = EcGroup::from_curve_name(nid).expect("EcGroup");
g.set_asn1_flag(Asn1Flag::NAMED_CURVE);
g
}
pub fn create_rsa_key(bits: u32) -> PKey<pkey::Private> {
let pri_key_rsa = Rsa::generate(bits).expect("Rsa::generate");
PKey::from_rsa(pri_key_rsa).expect("from_rsa")
}
pub fn create_p256_key() -> PKey<pkey::Private> {
let pri_key_ec = EcKey::generate(&*EC_GROUP_P256).expect("EcKey");
PKey::from_ec_key(pri_key_ec).expect("from_ec_key")
}
pub fn create_p384_key() -> PKey<pkey::Private> {
let pri_key_ec = EcKey::generate(&*EC_GROUP_P384).expect("EcKey");
PKey::from_ec_key(pri_key_ec).expect("from_ec_key")
}
pub(crate) fn create_csr(pkey: &PKey<pkey::Private>, domains: &[&str]) -> Result<X509Req> {
let mut req_bld = X509ReqBuilder::new().expect("X509ReqBuilder");
req_bld.set_pubkey(pkey).expect("set_pubkey");
let mut stack = Stack::new().expect("Stack::new");
let ctx = req_bld.x509v3_context(None);
let mut an = SubjectAlternativeName::new();
for d in domains {
an.dns(d);
}
let ext = an.build(&ctx).expect("SubjectAlternativeName::build");
stack.push(ext).expect("Stack::push");
req_bld.add_extensions(&stack).expect("add_extensions");
req_bld
.sign(pkey, MessageDigest::sha256())
.expect("csr_sign");
Ok(req_bld.build())
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Certificate {
private_key: String,
certificate: String,
}
impl Certificate {
pub(crate) fn new(private_key: String, certificate: String) -> Self {
Certificate {
private_key,
certificate,
}
}
pub fn private_key(&self) -> &str {
&self.private_key
}
pub fn private_key_der(&self) -> Vec<u8> {
let pkey = PKey::private_key_from_pem(self.private_key.as_bytes()).expect("from_pem");
pkey.private_key_to_der().expect("private_key_to_der")
}
pub fn certificate(&self) -> &str {
&self.certificate
}
pub fn certificate_der(&self) -> Vec<u8> {
let x509 = X509::from_pem(self.certificate.as_bytes()).expect("from_pem");
x509.to_der().expect("to_der")
}
pub fn valid_days_left(&self) -> i64 {
if cfg!(test) {
return 89;
}
let x509 = X509::from_pem(self.certificate.as_bytes()).expect("from_pem");
let not_after = format!("{}", x509.not_after());
let expires = parse_date(¬_after);
let dur = expires - time::now();
dur.num_days()
}
}
fn parse_date(s: &str) -> time::Tm {
debug!("Parse date/time: {}", s);
time::strptime(s, "%h %e %H:%M:%S %Y %Z").expect("strptime")
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_parse_date() {
let x = parse_date("May 3 07:40:15 2019 GMT");
assert_eq!(time::strftime("%F %T", &x).unwrap(), "2019-05-03 07:40:15");
}
}