use crate::tls::{nid::Nid, pkey::PKey, pkey::Private, x509::X509};
use crate::Result;
use bytes::Bytes;
use pingora_error::{ErrorType::*, OrErr};
use std::hash::{Hash, Hasher};
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct BufRef(pub usize, pub usize);
impl BufRef {
pub fn get<'a>(&self, buf: &'a [u8]) -> &'a [u8] {
&buf[self.0..self.1]
}
pub fn get_bytes(&self, buf: &Bytes) -> Bytes {
buf.slice(self.0..self.1)
}
pub fn len(&self) -> usize {
self.1 - self.0
}
pub fn is_empty(&self) -> bool {
self.1 == self.0
}
}
impl BufRef {
pub fn new(start: usize, len: usize) -> Self {
BufRef(start, start + len)
}
}
#[derive(Clone)]
pub struct KVRef {
name: BufRef,
value: BufRef,
}
impl KVRef {
pub fn get_name<'a>(&self, buf: &'a [u8]) -> &'a [u8] {
self.name.get(buf)
}
pub fn get_value<'a>(&self, buf: &'a [u8]) -> &'a [u8] {
self.value.get(buf)
}
pub fn get_name_bytes(&self, buf: &Bytes) -> Bytes {
self.name.get_bytes(buf)
}
pub fn get_value_bytes(&self, buf: &Bytes) -> Bytes {
self.value.get_bytes(buf)
}
pub fn new(name_s: usize, name_len: usize, value_s: usize, value_len: usize) -> Self {
KVRef {
name: BufRef(name_s, name_s + name_len),
value: BufRef(value_s, value_s + value_len),
}
}
pub fn value(&self) -> &BufRef {
&self.value
}
}
pub const EMPTY_KV_REF: KVRef = KVRef {
name: BufRef(0, 0),
value: BufRef(0, 0),
};
fn get_subject_name(cert: &X509, name_type: Nid) -> Option<String> {
cert.subject_name()
.entries_by_nid(name_type)
.next()
.map(|name| {
name.data()
.as_utf8()
.map(|s| s.to_string())
.unwrap_or_default()
})
}
pub fn get_organization(cert: &X509) -> Option<String> {
get_subject_name(cert, Nid::ORGANIZATIONNAME)
}
pub fn get_common_name(cert: &X509) -> Option<String> {
get_subject_name(cert, Nid::COMMONNAME)
}
pub fn get_organization_unit(cert: &X509) -> Option<String> {
get_subject_name(cert, Nid::ORGANIZATIONALUNITNAME)
}
pub fn get_serial(cert: &X509) -> Result<String> {
let bn = cert
.serial_number()
.to_bn()
.or_err(InvalidCert, "Invalid serial")?;
let hex = bn.to_hex_str().or_err(InvalidCert, "Invalid serial")?;
let hex_str: &str = hex.as_ref();
Ok(hex_str.to_owned())
}
#[derive(Clone)]
pub struct CertKey {
certificates: Vec<X509>,
key: PKey<Private>,
}
impl CertKey {
pub fn new(certificates: Vec<X509>, key: PKey<Private>) -> CertKey {
assert!(
!certificates.is_empty(),
"expected a non-empty vector of certificates in CertKey::new"
);
CertKey { certificates, key }
}
pub fn leaf(&self) -> &X509 {
&self.certificates[0]
}
pub fn key(&self) -> &PKey<Private> {
&self.key
}
pub fn intermediates(&self) -> &[X509] {
if self.certificates.len() <= 1 {
return &[];
}
&self.certificates[1..]
}
pub fn organization(&self) -> Option<String> {
get_organization(self.leaf())
}
pub fn serial(&self) -> Result<String> {
get_serial(self.leaf())
}
}
impl Hash for CertKey {
fn hash<H: Hasher>(&self, state: &mut H) {
for certificate in &self.certificates {
if let Ok(serial) = get_serial(certificate) {
serial.hash(state)
}
}
}
}
impl std::fmt::Debug for CertKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CertKey")
.field("X509", &self.leaf())
.finish()
}
}
impl std::fmt::Display for CertKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let leaf = self.leaf();
if let Some(cn) = get_common_name(leaf) {
write!(f, "CN: {cn},")?;
} else if let Some(org_unit) = get_organization_unit(leaf) {
write!(f, "Org Unit: {org_unit},")?;
}
write!(f, ", expire: {}", leaf.not_after())
}
}