sare_core/format/
certificate.rs1use 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}