1 use std
::path
::PathBuf
;
2 use std
::mem
::MaybeUninit
;
4 use anyhow
::{bail, format_err, Error}
;
5 use foreign_types
::ForeignTypeRef
;
6 use openssl
::x509
::{X509, GeneralName}
;
7 use openssl
::stack
::Stack
;
8 use openssl
::pkey
::{Public, PKey}
;
10 use pbs_buildcfg
::configdir
;
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 proxmox
::tools
::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 new() -> Result
<Self, Error
> {
44 Self::from_path(PathBuf
::from(configdir
!("/proxy.pem")))
47 pub fn from_path(path
: PathBuf
) -> Result
<Self, Error
> {
48 Self::from_pem(&proxmox
::tools
::fs
::file_get_contents(&path
)?
)
49 .map_err(|err
| format_err
!("failed to load certificate from {:?} - {}", path
, err
))
52 pub fn from_pem(cert_pem
: &[u8]) -> Result
<Self, Error
> {
53 let x509
= openssl
::x509
::X509
::from_pem(&cert_pem
)?
;
59 pub fn subject_alt_names(&self) -> Option
<Stack
<GeneralName
>> {
60 self.x509
.subject_alt_names()
63 pub fn subject_name(&self) -> Result
<String
, Error
> {
64 Ok(x509name_to_string(self.x509
.subject_name())?
)
67 pub fn issuer_name(&self) -> Result
<String
, Error
> {
68 Ok(x509name_to_string(self.x509
.issuer_name())?
)
71 pub fn fingerprint(&self) -> Result
<String
, Error
> {
72 let fp
= self.x509
.digest(openssl
::hash
::MessageDigest
::sha256())?
;
73 let fp_string
= proxmox
::tools
::digest_to_hex(&fp
);
74 let fp_string
= fp_string
.as_bytes().chunks(2).map(|v
| std
::str::from_utf8(v
).unwrap())
75 .collect
::<Vec
<&str>>().join(":");
79 pub fn public_key(&self) -> Result
<PKey
<Public
>, Error
> {
80 let pubkey
= self.x509
.public_key()?
;
84 pub fn not_before(&self) -> &openssl
::asn1
::Asn1TimeRef
{
85 self.x509
.not_before()
88 pub fn not_after(&self) -> &openssl
::asn1
::Asn1TimeRef
{
92 pub fn not_before_unix(&self) -> Result
<i64, Error
> {
93 asn1_time_to_unix(&self.not_before())
96 pub fn not_after_unix(&self) -> Result
<i64, Error
> {
97 asn1_time_to_unix(&self.not_after())
100 /// Check if the certificate is expired at or after a specific unix epoch.
101 pub fn is_expired_after_epoch(&self, epoch
: i64) -> Result
<bool
, Error
> {
102 Ok(self.not_after_unix()?
< epoch
)