use std::time::SystemTime;
use openssl::asn1::{Asn1Integer, Asn1Time, Asn1Type};
use openssl::bn::BigNum;
use openssl::hash::MessageDigest;
use openssl::nid::Nid;
use openssl::pkey::{PKey, Private};
use openssl::rsa::Rsa;
use openssl::x509::{X509Name, X509};
use crate::crypto::dtls::DTLS_CERT_IDENTITY;
use crate::crypto::Fingerprint;
use super::CryptoError;
const RSA_F4: u32 = 0x10001;
#[derive(Debug, Clone)]
pub struct OsslDtlsCert {
pub(crate) pkey: PKey<Private>,
pub(crate) x509: X509,
}
impl OsslDtlsCert {
pub fn new() -> Self {
Self::self_signed().expect("create dtls cert")
}
fn self_signed() -> Result<Self, CryptoError> {
let f4 = BigNum::from_u32(RSA_F4).unwrap();
let key = Rsa::generate_with_e(2048, &f4)?;
let pkey = PKey::from_rsa(key)?;
let mut x509b = X509::builder()?;
x509b.set_version(2)?;
let mut serial_buf = [0u8; 16];
openssl::rand::rand_bytes(&mut serial_buf)?;
let serial_bn = BigNum::from_slice(&serial_buf)?;
let serial = Asn1Integer::from_bn(&serial_bn)?;
x509b.set_serial_number(&serial)?;
let before = Asn1Time::from_unix(unix_time() - 3600)?;
x509b.set_not_before(&before)?;
let after = Asn1Time::days_from_now(7)?;
x509b.set_not_after(&after)?;
x509b.set_pubkey(&pkey)?;
let mut nameb = X509Name::builder()?;
nameb.append_entry_by_nid_with_type(
Nid::COMMONNAME,
DTLS_CERT_IDENTITY,
Asn1Type::UTF8STRING,
)?;
let name = nameb.build();
x509b.set_subject_name(&name)?;
x509b.set_issuer_name(&name)?;
x509b.sign(&pkey, MessageDigest::sha1())?;
let x509 = x509b.build();
Ok(OsslDtlsCert { pkey, x509 })
}
pub fn fingerprint(&self) -> Fingerprint {
let digest: &[u8] = &self
.x509
.digest(MessageDigest::sha256())
.expect("digest to fingerprint");
Fingerprint {
hash_func: "sha-256".into(),
bytes: digest.to_vec(),
}
}
}
pub fn unix_time() -> libc::time_t {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs() as libc::time_t
}