veridian_kernel/net/tls/
certificate.rs1#[cfg(feature = "alloc")]
7use alloc::vec::Vec;
8
9const ASN1_SEQUENCE: u8 = 0x30;
15const ASN1_SET: u8 = 0x31;
16const ASN1_OID: u8 = 0x06;
17const ASN1_UTF8STRING: u8 = 0x0C;
18const ASN1_PRINTABLESTRING: u8 = 0x13;
19const ASN1_BIT_STRING: u8 = 0x03;
20
21pub(crate) fn asn1_parse_tlv(data: &[u8]) -> Option<(u8, usize, usize)> {
24 if data.is_empty() {
25 return None;
26 }
27 let tag = data[0];
28 if data.len() < 2 {
29 return None;
30 }
31
32 let (content_start, content_len) = if data[1] & 0x80 == 0 {
33 (2, data[1] as usize)
35 } else {
36 let num_len_bytes = (data[1] & 0x7F) as usize;
37 if num_len_bytes == 0 || num_len_bytes > 4 || data.len() < 2 + num_len_bytes {
38 return None;
39 }
40 let mut len: usize = 0;
41 for i in 0..num_len_bytes {
42 len = (len << 8) | (data[2 + i] as usize);
43 }
44 (2 + num_len_bytes, len)
45 };
46
47 if content_start + content_len > data.len() {
48 return None;
49 }
50
51 Some((tag, content_start, content_len))
52}
53
54fn extract_cn(name_data: &[u8]) -> Vec<u8> {
56 let cn_oid: [u8; 3] = [0x55, 0x04, 0x03];
58
59 let mut pos = 0;
60 while pos < name_data.len() {
61 if let Some((_tag, start, len)) = asn1_parse_tlv(&name_data[pos..]) {
62 let inner = &name_data[pos + start..pos + start + len];
63 if let Some(idx) = find_subsequence(inner, &cn_oid) {
65 let after_oid = idx + cn_oid.len();
67 if after_oid < inner.len() {
68 if let Some((_vtag, vstart, vlen)) = asn1_parse_tlv(&inner[after_oid..]) {
69 let value = &inner[after_oid + vstart..after_oid + vstart + vlen];
70 return value.to_vec();
71 }
72 }
73 }
74 pos += start + len;
75 } else {
76 break;
77 }
78 }
79
80 Vec::new()
81}
82
83fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
85 if needle.is_empty() || needle.len() > haystack.len() {
86 return None;
87 }
88 for i in 0..=haystack.len() - needle.len() {
89 if haystack[i..i + needle.len()] == *needle {
90 return Some(i + needle.len());
91 }
92 }
93 None
94}
95
96#[derive(Debug, Clone)]
102pub struct X509Certificate {
103 pub raw: Vec<u8>,
105 pub subject_cn: Vec<u8>,
107 pub issuer_cn: Vec<u8>,
109 pub public_key: Vec<u8>,
111 pub not_before: u64,
113 pub not_after: u64,
115 pub is_ca: bool,
117}
118
119impl X509Certificate {
120 pub fn from_der(data: &[u8]) -> Option<Self> {
125 let (tag, start, len) = asn1_parse_tlv(data)?;
127 if tag != ASN1_SEQUENCE {
128 return None;
129 }
130 let cert_content = &data[start..start + len];
131
132 let (tbs_tag, tbs_start, tbs_len) = asn1_parse_tlv(cert_content)?;
134 if tbs_tag != ASN1_SEQUENCE {
135 return None;
136 }
137 let tbs = &cert_content[tbs_start..tbs_start + tbs_len];
138
139 let issuer_cn = extract_cn(tbs);
144
145 let subject_cn = if tbs.len() > 100 {
147 let second_half = &tbs[tbs.len() / 3..];
148 let cn = extract_cn(second_half);
149 if cn.is_empty() {
150 issuer_cn.clone()
151 } else {
152 cn
153 }
154 } else {
155 issuer_cn.clone()
156 };
157
158 let mut public_key = Vec::new();
160 let mut scan_pos = 0;
161 while scan_pos < tbs.len() {
162 if tbs[scan_pos] == ASN1_BIT_STRING {
163 if let Some((_, bs_start, bs_len)) = asn1_parse_tlv(&tbs[scan_pos..]) {
164 if bs_len > 1 {
165 public_key =
167 tbs[scan_pos + bs_start + 1..scan_pos + bs_start + bs_len].to_vec();
168 }
169 break;
170 }
171 }
172 scan_pos += 1;
173 }
174
175 Some(Self {
176 raw: data.to_vec(),
177 subject_cn,
178 issuer_cn,
179 public_key,
180 not_before: 0,
181 not_after: 0,
182 is_ca: false,
183 })
184 }
185}
186
187pub struct TrustStore {
193 anchors: Vec<X509Certificate>,
195}
196
197impl Default for TrustStore {
198 fn default() -> Self {
199 Self::new()
200 }
201}
202
203impl TrustStore {
204 pub fn new() -> Self {
206 Self {
207 anchors: Vec::new(),
208 }
209 }
210
211 pub fn add_anchor(&mut self, cert: X509Certificate) {
213 self.anchors.push(cert);
214 }
215
216 pub fn validate_chain(&self, chain: &[X509Certificate]) -> bool {
221 if chain.is_empty() {
222 return false;
223 }
224
225 for i in 0..chain.len().saturating_sub(1) {
227 if chain[i].issuer_cn != chain[i + 1].subject_cn {
228 return false;
229 }
230 }
231
232 let root_issuer = &chain[chain.len() - 1].issuer_cn;
234 self.anchors
235 .iter()
236 .any(|anchor| &anchor.subject_cn == root_issuer)
237 }
238
239 pub fn anchor_count(&self) -> usize {
241 self.anchors.len()
242 }
243}