1 //! Deals with the server's current certificates (proxy.pem).
3 use std
::path
::PathBuf
;
4 use std
::mem
::MaybeUninit
;
6 use anyhow
::{bail, format_err, Error}
;
7 use foreign_types
::ForeignTypeRef
;
8 use openssl
::x509
::{X509, GeneralName}
;
9 use openssl
::stack
::Stack
;
10 use openssl
::pkey
::{Public, PKey}
;
13 #[allow(non_camel_case_types)]
14 type ASN1_TIME
= <openssl
::asn1
::Asn1TimeRef
as ForeignTypeRef
>::CType
;
17 fn ASN1_TIME_to_tm(s
: *const ASN1_TIME
, tm
: *mut libc
::tm
) -> libc
::c_int
;
20 fn asn1_time_to_unix(time
: &openssl
::asn1
::Asn1TimeRef
) -> Result
<i64, Error
> {
21 let mut c_tm
= MaybeUninit
::<libc
::tm
>::uninit();
22 let rc
= unsafe { ASN1_TIME_to_tm(time.as_ptr(), c_tm.as_mut_ptr()) }
;
24 bail
!("failed to parse ASN1 time");
26 let mut c_tm
= unsafe { c_tm.assume_init() }
;
27 Ok(proxmox_time
::timegm(&mut c_tm
)?
)
34 fn x509name_to_string(name
: &openssl
::x509
::X509NameRef
) -> Result
<String
, Error
> {
35 let mut parts
= Vec
::new();
36 for entry
in name
.entries() {
37 parts
.push(format
!("{} = {}", entry
.object().nid().short_name()?
, entry
.data().as_utf8()?
));
43 pub fn from_path(path
: PathBuf
) -> Result
<Self, Error
> {
44 Self::from_pem(&proxmox
::tools
::fs
::file_get_contents(&path
)?
)
45 .map_err(|err
| format_err
!("failed to load certificate from {:?} - {}", path
, err
))
48 pub fn from_pem(cert_pem
: &[u8]) -> Result
<Self, Error
> {
49 let x509
= openssl
::x509
::X509
::from_pem(&cert_pem
)?
;
55 pub fn subject_alt_names(&self) -> Option
<Stack
<GeneralName
>> {
56 self.x509
.subject_alt_names()
59 pub fn subject_name(&self) -> Result
<String
, Error
> {
60 Ok(x509name_to_string(self.x509
.subject_name())?
)
63 pub fn issuer_name(&self) -> Result
<String
, Error
> {
64 Ok(x509name_to_string(self.x509
.issuer_name())?
)
67 pub fn fingerprint(&self) -> Result
<String
, Error
> {
68 let fp
= self.x509
.digest(openssl
::hash
::MessageDigest
::sha256())?
;
72 .map(|v
| std
::str::from_utf8(v
).unwrap())
73 .collect
::<Vec
<&str>>().join(":"))
76 pub fn public_key(&self) -> Result
<PKey
<Public
>, Error
> {
77 let pubkey
= self.x509
.public_key()?
;
81 pub fn not_before(&self) -> &openssl
::asn1
::Asn1TimeRef
{
82 self.x509
.not_before()
85 pub fn not_after(&self) -> &openssl
::asn1
::Asn1TimeRef
{
89 pub fn not_before_unix(&self) -> Result
<i64, Error
> {
90 asn1_time_to_unix(&self.not_before())
93 pub fn not_after_unix(&self) -> Result
<i64, Error
> {
94 asn1_time_to_unix(&self.not_after())
97 /// Check if the certificate is expired at or after a specific unix epoch.
98 pub fn is_expired_after_epoch(&self, epoch
: i64) -> Result
<bool
, Error
> {
99 Ok(self.not_after_unix()?
< epoch
)