1use crate::{EstError, EstResult};
7use base64::Engine;
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub struct CaCertsResponse {
22 #[serde(with = "serde_bytes")]
24 pkcs7_der: Vec<u8>,
25}
26
27impl CaCertsResponse {
28 pub fn new(pkcs7_der: Vec<u8>) -> Self {
38 Self { pkcs7_der }
39 }
40
41 pub fn pkcs7_der(&self) -> &[u8] {
43 &self.pkcs7_der
44 }
45
46 pub fn into_pkcs7_der(self) -> Vec<u8> {
48 self.pkcs7_der
49 }
50
51 pub fn to_base64(&self) -> String {
55 base64::engine::general_purpose::STANDARD.encode(&self.pkcs7_der)
56 }
57
58 pub fn from_base64(base64_data: &str) -> EstResult<Self> {
68 let pkcs7_der = base64::engine::general_purpose::STANDARD
69 .decode(base64_data)
70 .map_err(|e| EstError::InvalidBase64(e.to_string()))?;
71
72 Ok(Self::new(pkcs7_der))
73 }
74
75 pub fn validate(&self) -> EstResult<()> {
80 if self.pkcs7_der.is_empty() {
82 return Err(EstError::InvalidPkcs7("Empty PKCS#7 structure".to_string()));
83 }
84
85 if self.pkcs7_der[0] != 0x30 {
86 return Err(EstError::InvalidPkcs7(
87 "Invalid DER: expected SEQUENCE tag".to_string(),
88 ));
89 }
90
91 if self.pkcs7_der.len() < 50 {
93 return Err(EstError::InvalidPkcs7(format!(
94 "PKCS#7 too small: {} bytes",
95 self.pkcs7_der.len()
96 )));
97 }
98
99 Ok(())
100 }
101}
102
103mod serde_bytes {
105 use serde::{Deserialize, Deserializer, Serializer};
106
107 pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
108 where
109 S: Serializer,
110 {
111 serializer.serialize_bytes(bytes)
112 }
113
114 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
115 where
116 D: Deserializer<'de>,
117 {
118 Vec::<u8>::deserialize(deserializer)
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_cacerts_roundtrip() {
128 let der = vec![0x30, 0x82, 0x01, 0x00]; let mut full_der = der.clone();
131 full_der.extend(vec![0x00; 252]); let response = CaCertsResponse::new(full_der.clone());
134 assert_eq!(response.pkcs7_der(), &full_der);
135
136 let base64 = response.to_base64();
137 let decoded = CaCertsResponse::from_base64(&base64).unwrap();
138 assert_eq!(decoded.pkcs7_der(), &full_der);
139 }
140
141 #[test]
142 fn test_invalid_base64() {
143 let result = CaCertsResponse::from_base64("not-valid-base64!!!");
144 assert!(matches!(result, Err(EstError::InvalidBase64(_))));
145 }
146
147 #[test]
148 fn test_validate_empty() {
149 let response = CaCertsResponse::new(vec![]);
150 assert!(matches!(
151 response.validate(),
152 Err(EstError::InvalidPkcs7(_))
153 ));
154 }
155
156 #[test]
157 fn test_validate_wrong_tag() {
158 let response = CaCertsResponse::new(vec![0x04, 0x00]); assert!(matches!(
160 response.validate(),
161 Err(EstError::InvalidPkcs7(_))
162 ));
163 }
164
165 #[test]
166 fn test_validate_too_small() {
167 let response = CaCertsResponse::new(vec![0x30, 0x00]); assert!(matches!(
169 response.validate(),
170 Err(EstError::InvalidPkcs7(_))
171 ));
172 }
173}