plabble_codec/codec/objects/
certificate.rs1use time::OffsetDateTime;
2
3use crate::{
4 abstractions::{Serializable, SerializationError, SerializationInfo, KEY_SIZE, SIGNATURE_SIZE},
5 codec::common::{assert_len, plabble_date},
6};
7
8#[derive(Debug)]
18pub struct Certificate {
19 pub public_key: [u8; KEY_SIZE],
20 pub valid_from: OffsetDateTime,
21 pub valid_to: OffsetDateTime,
22 pub signature: [u8; SIGNATURE_SIZE],
23 pub domain_or_ip: String,
24}
25
26impl Serializable for Certificate {
27 fn size(&self) -> usize {
28 KEY_SIZE + 4 + 4 + SIGNATURE_SIZE + self.domain_or_ip.len()
29 }
30
31 fn get_bytes(&self) -> Vec<u8> {
32 let mut buff = Vec::new();
33 buff.extend_from_slice(&self.public_key);
34 buff.extend_from_slice(&plabble_date::to_timestamp(&self.valid_from).to_be_bytes());
35 buff.extend_from_slice(&plabble_date::to_timestamp(&self.valid_to).to_be_bytes());
36 buff.extend_from_slice(&self.signature);
37 buff.extend_from_slice(self.domain_or_ip.as_bytes());
38 buff
39 }
40
41 fn from_bytes(data: &[u8], _: Option<SerializationInfo>) -> Result<Self, SerializationError>
42 where
43 Self: Sized,
44 {
45 assert_len(data, KEY_SIZE + SIGNATURE_SIZE + 8)?;
46 let mut cert = Self {
47 public_key: [0u8; KEY_SIZE],
48 valid_from: plabble_date::from_timestamp(u32::from_be_bytes(
49 data[KEY_SIZE..(KEY_SIZE + 4)].try_into().unwrap(),
50 )),
51 valid_to: plabble_date::from_timestamp(u32::from_be_bytes(
52 data[(KEY_SIZE + 4)..(KEY_SIZE + 8)].try_into().unwrap(),
53 )),
54 signature: [0u8; SIGNATURE_SIZE],
55 domain_or_ip: String::new(),
56 };
57 cert.public_key.copy_from_slice(&data[..KEY_SIZE]);
58 cert.signature
59 .copy_from_slice(&data[(KEY_SIZE + 8)..(KEY_SIZE + 8 + SIGNATURE_SIZE)]);
60 cert.domain_or_ip =
61 String::from_utf8_lossy(&data[(KEY_SIZE + 8 + SIGNATURE_SIZE)..]).to_string();
62 Ok(cert)
63 }
64}
65
66#[cfg(test)]
67mod test {
68 use time_macros::datetime;
69
70 use crate::abstractions::EPOCH;
71
72 use super::*;
73
74 #[test]
75 fn can_parse_cert() {
76 let cert = &[
77 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
78 25, 26, 27, 28, 29, 30, 31, 32, 0, 0, 0, 12, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x70, 0x6c,
81 0x61, 0x62, 0x62, 0x6c, 0x65, 0x2e, 0x6f, 0x72, 0x67,
82 ];
83
84 let cert = Certificate::from_bytes(cert, None).unwrap();
85 assert_eq!(1, cert.public_key[0]);
86 assert_eq!(32, cert.public_key[31]);
87 assert_eq!(64, cert.signature.len());
88 assert_eq!(
89 OffsetDateTime::from_unix_timestamp(EPOCH + 12).unwrap(),
90 cert.valid_from
91 );
92 assert_eq!(
93 OffsetDateTime::from_unix_timestamp(EPOCH + 14).unwrap(),
94 cert.valid_to
95 );
96 assert_eq!("plabble.org", &cert.domain_or_ip);
97 }
98
99 #[test]
100 fn can_serialize_cert() {
101 let cert1 = Certificate {
102 public_key: [2u8; 32],
103 signature: [3u8; 64],
104 valid_from: datetime!(2020-01-01 00:00:00 UTC),
105 valid_to: datetime!(2020-01-15 00:00:00 UTC),
106 domain_or_ip: String::from("cert.plabble.org"),
107 };
108 let cert2 = Certificate::from_bytes(&cert1.get_bytes(), None).unwrap();
109 assert_eq!(cert1.domain_or_ip, cert2.domain_or_ip);
110 assert_eq!(cert1.public_key, cert2.public_key);
111 assert_eq!(cert1.signature, cert2.signature);
112 assert_eq!(cert1.valid_from, cert2.valid_from);
113 assert_eq!(cert1.valid_to, cert2.valid_to);
114 }
115}