1#[cfg(feature = "native-tls")]
9use compio_tls::native_tls::{Certificate as NativeCertificate, Identity as NativeIdentity};
10#[cfg(feature = "rust-tls")]
11use deboa::cert::Certificate as _;
12#[cfg(feature = "native-tls")]
13use deboa::cert::{Certificate as _, IdentityNativeExt};
14use deboa::cert::{CertificateExt, ContentEncoding, IdentityExt};
15#[cfg(feature = "rust-tls")]
16use rustls::pki_types::{pem::PemObject, CertificateDer, PrivateKeyDer};
17
18pub type Identity = DeboaIdentity;
20pub type Certificate = DeboaCertificate;
22
23#[derive(Debug, Clone)]
49pub struct DeboaIdentity {
50 cert: Vec<u8>,
51 key: Option<Vec<u8>>,
52 #[allow(unused)]
53 password: Option<String>,
54 #[allow(unused)]
55 encoding: Option<ContentEncoding>,
56}
57
58#[cfg(feature = "native-tls")]
59impl IdentityNativeExt for DeboaIdentity {
60 fn from_pkcs12(bundle: &[u8], password: Option<String>) -> Self {
72 Identity { cert: bundle.to_vec(), key: None, password, encoding: None }
73 }
74
75 async fn from_pkcs12_file(file: &str, password: Option<String>) -> std::io::Result<Self> {
87 let data = compio::fs::read(file).await?;
88 Ok(Identity { cert: data, key: None, password, encoding: None })
89 }
90}
91
92impl deboa::cert::Identity for DeboaIdentity {
93 fn cert(&self) -> &Vec<u8> {
94 &self.cert
95 }
96
97 fn key(&self) -> &Option<Vec<u8>> {
98 &self.key
99 }
100
101 fn encoding(&self) -> &Option<ContentEncoding> {
102 &self.encoding
103 }
104}
105
106impl IdentityExt for DeboaIdentity {
107 fn from_pkcs8(cert: &[u8], key: &[u8], encoding: ContentEncoding) -> Self {
119 DeboaIdentity {
120 cert: cert.to_vec(),
121 key: Some(key.to_vec()),
122 password: None,
123 encoding: Some(encoding),
124 }
125 }
126
127 async fn from_pkcs8_file(
128 cert: &str,
129 key: &str,
130 encoding: ContentEncoding,
131 ) -> std::io::Result<Self> {
132 let cert = compio::fs::read(cert).await?;
133 let key = compio::fs::read(key).await?;
134 Ok(DeboaIdentity { cert, key: Some(key), password: None, encoding: Some(encoding) })
135 }
136}
137
138#[cfg(feature = "rust-tls")]
139impl TryFrom<&Identity> for (CertificateDer<'static>, PrivateKeyDer<'static>) {
140 type Error = std::io::Error;
141
142 fn try_from(value: &Identity) -> std::result::Result<Self, Self::Error> {
143 let cert = value.cert.clone();
144 let key = value
145 .key
146 .as_ref()
147 .unwrap()
148 .clone();
149
150 let pair = match value.encoding {
151 Some(ContentEncoding::DER) => {
152 let cert = CertificateDer::from(cert);
153
154 let key = PrivateKeyDer::try_from(key);
155 if key.is_err() {
156 return Err(std::io::Error::new(
157 std::io::ErrorKind::InvalidData,
158 "Invalid certificate",
159 ));
160 }
161 (cert, key.unwrap())
162 }
163 Some(ContentEncoding::PEM) => {
164 let cert = CertificateDer::from_pem_slice(&cert);
165 if let Err(e) = cert {
166 return Err(std::io::Error::new(
167 std::io::ErrorKind::InvalidData,
168 format!("Invalid certificate: {}", e),
169 ));
170 }
171
172 let key = PrivateKeyDer::from_pem_slice(&key);
173 if let Err(e) = key {
174 return Err(std::io::Error::new(
175 std::io::ErrorKind::InvalidData,
176 format!("Invalid certificate: {}", e),
177 ));
178 }
179 (cert.unwrap(), key.unwrap())
180 }
181 None => {
182 return Err(std::io::Error::new(
183 std::io::ErrorKind::InvalidData,
184 "Invalid certificate",
185 ));
186 }
187 };
188
189 Ok(pair)
190 }
191}
192
193#[cfg(feature = "native-tls")]
194impl TryFrom<&Identity> for NativeIdentity {
195 type Error = std::io::Error;
196
197 fn try_from(value: &Identity) -> std::result::Result<Self, Self::Error> {
198 let identity = if let Some(password) = &value.password {
199 let identity = NativeIdentity::from_pkcs12(&value.cert, password);
200 if identity.is_err() {
201 return Err(std::io::Error::new(
202 std::io::ErrorKind::InvalidData,
203 "Invalid certificate",
204 ));
205 }
206 identity.unwrap()
207 } else if let Some(key) = &value.key {
208 let identity = NativeIdentity::from_pkcs8(&value.cert, key);
209 if identity.is_err() {
210 return Err(std::io::Error::new(
211 std::io::ErrorKind::InvalidData,
212 "Invalid certificate",
213 ));
214 }
215 identity.unwrap()
216 } else {
217 return Err(std::io::Error::new(
218 std::io::ErrorKind::InvalidData,
219 "You need provide a password or a key",
220 ));
221 };
222
223 Ok(identity)
224 }
225}
226
227#[derive(Debug, Clone)]
242pub struct DeboaCertificate {
243 data: Vec<u8>,
244 encoding: ContentEncoding,
245}
246
247impl CertificateExt for DeboaCertificate {
248 fn from_slice(data: &[u8], encoding: ContentEncoding) -> Self {
259 DeboaCertificate { data: data.to_vec(), encoding }
260 }
261
262 async fn from_file(file: &str, encoding: ContentEncoding) -> std::io::Result<Self> {
273 let data = compio::fs::read(file).await?;
274 Ok(DeboaCertificate { data, encoding })
275 }
276}
277
278impl deboa::cert::Certificate for DeboaCertificate {
279 #[inline]
286 fn as_bytes(&self) -> &Vec<u8> {
287 &self.data
288 }
289}
290
291#[cfg(feature = "rust-tls")]
292impl TryFrom<&DeboaCertificate> for CertificateDer<'static> {
293 type Error = std::io::Error;
294
295 fn try_from(value: &DeboaCertificate) -> std::result::Result<Self, Self::Error> {
296 let cert = match value.encoding {
297 ContentEncoding::DER => CertificateDer::from(
298 value
299 .as_bytes()
300 .to_vec(),
301 ),
302 ContentEncoding::PEM => {
303 let result = CertificateDer::from_pem_slice(value.as_bytes());
304 if let Err(e) = result {
305 return Err(std::io::Error::new(
306 std::io::ErrorKind::InvalidData,
307 format!("Invalid certificate: {}", e),
308 ));
309 }
310 result.unwrap()
311 }
312 };
313
314 Ok(cert)
315 }
316}
317
318#[cfg(feature = "native-tls")]
319impl TryFrom<&DeboaCertificate> for NativeCertificate {
320 type Error = std::io::Error;
321
322 fn try_from(value: &DeboaCertificate) -> std::result::Result<Self, Self::Error> {
323 let cert = match value.encoding {
324 ContentEncoding::DER => NativeCertificate::from_der(value.as_bytes()),
325 ContentEncoding::PEM => NativeCertificate::from_pem(value.as_bytes()),
326 };
327
328 if let Err(e) = cert {
329 return Err(std::io::Error::new(
330 std::io::ErrorKind::InvalidData,
331 format!("Invalid certificate: {}", e),
332 ));
333 }
334
335 Ok(cert.unwrap())
336 }
337}