sare_core/format/
certificate.rs

1use std::str::FromStr;
2
3use super::{EncodablePublic, FormatError};
4use serde::{Deserialize, Serialize};
5
6pub const CERTIFICATE_PEM_TAG: &str = "SARE CERTIFICATE";
7pub const REVOCATION_PEM_TAG: &str = "SARE REVOCATION CERTIFICATE";
8pub const VALIDATION_PEM_TAG: &str = "SARE VALIDATION CERTIFICATE";
9
10#[derive(Clone, Serialize, Deserialize)]
11pub struct Issuer {
12    pub name: String,
13    pub email: String,
14}
15
16impl Issuer {
17    pub fn new(name: String, email: String) -> Self {
18        Issuer { name, email }
19    }
20    pub fn parse(input: &str) -> Option<Self> {
21        let start = input.find('<')?;
22        let end = input.find('>')?;
23
24        if start >= end {
25            return None;
26        }
27
28        Some(Self {
29            name: input[..start].trim().to_string(),
30            email: input[start + 1..end].trim().to_string(),
31        })
32    }
33
34    pub fn to_string(&self) -> String {
35        format!("{} <{}>", self.name, self.email)
36    }
37}
38
39#[derive(Clone, Debug, Serialize, Deserialize)]
40pub enum RevocationReason {
41    Compromised,
42    NoReasonSpecified,
43}
44
45impl FromStr for RevocationReason {
46    type Err = String;
47
48    fn from_str(s: &str) -> Result<Self, Self::Err> {
49        match s.to_lowercase().as_str() {
50            "compromised" => Ok(RevocationReason::Compromised),
51            "no-reason" | "none" | "unspecified" => Ok(RevocationReason::NoReasonSpecified),
52            _ => Err(format!("Invalid revocation reason: {}", s)),
53        }
54    }
55}
56
57#[derive(Clone, Serialize, Deserialize)]
58pub struct RevocationCertificateFormat {
59    pub revocation_date: u64,
60    pub revocation_reason: RevocationReason,
61    pub fullchain_fingerprint: [u8; 32],
62}
63
64#[derive(Clone, Serialize, Deserialize)]
65pub struct ValidationCertificateFormat {
66    pub fullchain_public_key_fingerprint: [u8; 32],
67}
68
69#[derive(Clone, Serialize, Deserialize)]
70pub enum CertificateType {
71    Revocation(RevocationCertificateFormat),
72    Validation(ValidationCertificateFormat),
73}
74
75#[derive(Clone, Serialize, Deserialize)]
76pub struct CertificateFormat {
77    pub issuer: Issuer,
78    pub expiry_date: Option<u64>,
79    #[serde(flatten)]
80    pub certificate_type: CertificateType,
81}
82
83impl CertificateFormat {
84    pub fn get_revocation_data(&self) -> Option<&RevocationCertificateFormat> {
85        match &self.certificate_type {
86            CertificateType::Revocation(revocation_format) => Some(revocation_format),
87            _ => None,
88        }
89    }
90
91    pub fn get_validation_data(&self) -> Option<&ValidationCertificateFormat> {
92        match &self.certificate_type {
93            CertificateType::Validation(validation_format) => Some(validation_format),
94            _ => None,
95        }
96    }
97}
98
99impl EncodablePublic for CertificateFormat {
100    fn encode_bson(&self) -> Vec<u8> {
101        bson::to_vec(&self).unwrap()
102    }
103
104    fn decode_bson(bson_data: &[u8]) -> Result<Self, FormatError> {
105        let public_key = bson::from_slice::<CertificateFormat>(bson_data).unwrap();
106        Ok(public_key)
107    }
108
109    fn encode_pem(&self) -> String {
110        let tag = match self.certificate_type {
111            CertificateType::Revocation(_) => REVOCATION_PEM_TAG,
112            CertificateType::Validation(_) => VALIDATION_PEM_TAG,
113        };
114
115        let pem = pem::Pem::new(tag, self.encode_bson().as_slice());
116        pem::encode(&pem)
117    }
118
119    fn decode_pem(pem_public_key: &str) -> Result<Self, FormatError> {
120        let pem = pem::parse(pem_public_key)?;
121
122        let bson_data = pem.contents();
123        Self::decode_bson(bson_data)
124    }
125}