darkbio_crypto/xdsa/
cert.rs1use crate::x509;
10use crate::xdsa::{PublicKey, SecretKey};
11use const_oid::ObjectIdentifier;
12use der::Encode;
13use std::error::Error;
14use x509_cert::Certificate;
15
16impl x509::Subject for PublicKey {
18 type Bytes = [u8; 1984];
19
20 fn to_bytes(&self) -> Self::Bytes {
22 self.to_bytes()
23 }
24
25 fn algorithm_oid(&self) -> ObjectIdentifier {
27 ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.6.48")
28 }
29}
30
31impl PublicKey {
32 pub fn from_cert_pem(pem: &str, signer: PublicKey) -> Result<(Self, u64, u64), Box<dyn Error>> {
36 let (_, der) = x509_parser::pem::parse_x509_pem(pem.as_bytes())?;
37 PublicKey::from_cert_der(der.contents.as_slice(), signer)
38 }
39
40 pub fn from_cert_der(
44 der: &[u8],
45 signer: PublicKey,
46 ) -> Result<(Self, u64, u64), Box<dyn Error>> {
47 let (_, cert) = x509_parser::parse_x509_certificate(der)?;
49
50 let tbs = cert.tbs_certificate.as_ref();
52 let sig_bytes: [u8; 3373] = cert
53 .signature_value
54 .data
55 .as_ref()
56 .try_into()
57 .map_err(|_| "invalid signature length")?;
58 let sig = super::Signature::from_bytes(&sig_bytes);
59 signer.verify(tbs, &sig)?;
60
61 let key = PublicKey::from_bytes(
63 cert.tbs_certificate
64 .subject_pki
65 .subject_public_key
66 .data
67 .as_ref()
68 .try_into()?,
69 )?;
70 let start = cert.tbs_certificate.validity.not_before.timestamp() as u64;
72 let until = cert.tbs_certificate.validity.not_after.timestamp() as u64;
73
74 Ok((key, start, until))
75 }
76
77 pub fn to_cert_pem(
80 &self,
81 signer: &SecretKey,
82 params: &x509::Params,
83 ) -> Result<String, Box<dyn Error>> {
84 let cert = self.to_cert(signer, params)?;
85 let der = cert.to_der()?;
86 let pem_str = der::pem::encode_string("CERTIFICATE", der::pem::LineEnding::LF, &der)
87 .map_err(|e| format!("PEM encoding error: {:?}", e))?;
88 Ok(pem_str)
89 }
90
91 pub fn to_cert_der(
94 &self,
95 signer: &SecretKey,
96 params: &x509::Params,
97 ) -> Result<Vec<u8>, Box<dyn Error>> {
98 Ok(self.to_cert(signer, params)?.to_der()?)
99 }
100
101 pub fn to_cert(
104 &self,
105 signer: &SecretKey,
106 params: &x509::Params,
107 ) -> Result<Certificate, Box<dyn Error>> {
108 x509::new(self, signer, params)
109 }
110}
111
112#[cfg(test)]
113mod test {
114 use crate::x509::Params;
115 use crate::xdsa::{PublicKey, SecretKey};
116 use std::time::{SystemTime, UNIX_EPOCH};
117
118 #[test]
120 fn test_cert_parse() {
121 let alice_secret = SecretKey::generate();
123 let bobby_secret = SecretKey::generate();
124 let alice_public = alice_secret.public_key();
125 let bobby_public = bobby_secret.public_key();
126
127 let start = SystemTime::now()
129 .duration_since(UNIX_EPOCH)
130 .unwrap()
131 .as_secs();
132 let until = start + 3600;
133
134 let pem = alice_public
136 .to_cert_pem(
137 &bobby_secret,
138 &Params {
139 subject_name: "Alice",
140 issuer_name: "Bobby",
141 not_before: start,
142 not_after: until,
143 is_ca: false,
144 path_len: None,
145 },
146 )
147 .unwrap();
148 let (parsed_key, parsed_start, parsed_until) =
149 PublicKey::from_cert_pem(pem.as_str(), bobby_public.clone()).unwrap();
150 assert_eq!(parsed_key.to_bytes(), alice_public.to_bytes());
151 assert_eq!(parsed_start, start);
152 assert_eq!(parsed_until, until);
153
154 let der = alice_public
156 .to_cert_der(
157 &bobby_secret,
158 &Params {
159 subject_name: "Alice",
160 issuer_name: "Bobby",
161 not_before: start,
162 not_after: until,
163 is_ca: true,
164 path_len: Some(0),
165 },
166 )
167 .unwrap();
168 let (parsed_key, parsed_start, parsed_until) =
169 PublicKey::from_cert_der(der.as_slice(), bobby_public.clone()).unwrap();
170 assert_eq!(parsed_key.to_bytes(), alice_public.to_bytes());
171 assert_eq!(parsed_start, start);
172 assert_eq!(parsed_until, until);
173 }
174
175 #[test]
177 fn test_cert_invalid_signer() {
178 let alice_secret = SecretKey::generate();
180 let bobby_secret = SecretKey::generate();
181 let wrong_secret = SecretKey::generate();
182
183 let alice_public = alice_secret.public_key();
184
185 let start = SystemTime::now()
187 .duration_since(UNIX_EPOCH)
188 .unwrap()
189 .as_secs();
190 let until = start + 3600;
191
192 let pem = alice_public
194 .to_cert_pem(
195 &bobby_secret,
196 &Params {
197 subject_name: "Alice",
198 issuer_name: "Bobby",
199 not_before: start,
200 not_after: until,
201 is_ca: false,
202 path_len: None,
203 },
204 )
205 .unwrap();
206 let result = PublicKey::from_cert_pem(pem.as_str(), wrong_secret.public_key());
207 assert!(result.is_err());
208 }
209}