1use sha2::{Sha256, Digest};
16use ruvix_types::KernelError;
17
18pub const SIGNATURE_SIZE: usize = 3309;
20
21pub const PUBLIC_KEY_SIZE: usize = 1952;
23
24pub const ML_DSA_65_PUBLIC_KEY_SIZE: usize = PUBLIC_KEY_SIZE;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum VerifyResult {
30 Valid,
32
33 Invalid,
35
36 WrongLength,
38
39 WrongKeyLength,
41
42 HashMismatch,
44}
45
46impl VerifyResult {
47 #[inline]
49 #[must_use]
50 pub const fn is_valid(&self) -> bool {
51 matches!(self, Self::Valid)
52 }
53
54 #[inline]
56 #[must_use]
57 pub const fn as_str(&self) -> &'static str {
58 match self {
59 Self::Valid => "Signature valid",
60 Self::Invalid => "Signature invalid",
61 Self::WrongLength => "Signature has wrong length",
62 Self::WrongKeyLength => "Public key has wrong length",
63 Self::HashMismatch => "Manifest hash mismatch",
64 }
65 }
66}
67
68pub struct SignatureVerifier {
72 public_key: [u8; PUBLIC_KEY_SIZE],
74}
75
76impl SignatureVerifier {
77 #[must_use]
83 pub fn new(public_key: &[u8]) -> Self {
84 assert_eq!(
85 public_key.len(),
86 PUBLIC_KEY_SIZE,
87 "FATAL: Boot public key has wrong length: {} (expected {})",
88 public_key.len(),
89 PUBLIC_KEY_SIZE
90 );
91
92 let mut pk = [0u8; PUBLIC_KEY_SIZE];
93 pk.copy_from_slice(public_key);
94
95 Self { public_key: pk }
96 }
97
98 #[cfg(test)]
100 #[must_use]
101 pub fn test_verifier() -> Self {
102 Self {
103 public_key: [0u8; PUBLIC_KEY_SIZE],
104 }
105 }
106
107 #[must_use]
114 pub fn verify(&self, manifest: &[u8], signature: &[u8]) -> VerifyResult {
115 if signature.len() != SIGNATURE_SIZE {
117 return VerifyResult::WrongLength;
118 }
119
120 let manifest_hash = Self::compute_hash(manifest);
122
123 self.verify_ml_dsa_65(&manifest_hash, signature)
126 }
127
128 pub fn verify_boot_signature(&self, manifest: &[u8], signature: &[u8]) {
137 let result = self.verify(manifest, signature);
138
139 match result {
140 VerifyResult::Valid => {
141 #[cfg(feature = "verbose")]
143 eprintln!("Boot signature verified successfully");
144 }
145 _ => {
146 eprintln!("FATAL: Boot signature verification failed: {}", result.as_str());
149 panic!("Boot signature verification failed");
150 }
151 }
152 }
153
154 #[must_use]
156 fn compute_hash(data: &[u8]) -> [u8; 32] {
157 let mut hasher = Sha256::new();
158 hasher.update(data);
159 let result = hasher.finalize();
160
161 let mut hash = [0u8; 32];
162 hash.copy_from_slice(&result);
163 hash
164 }
165
166 fn verify_ml_dsa_65(&self, manifest_hash: &[u8; 32], signature: &[u8]) -> VerifyResult {
171 if self.is_test_key() {
173 return self.verify_test_signature(manifest_hash, signature);
174 }
175
176 VerifyResult::Invalid
179 }
180
181 #[inline]
183 fn is_test_key(&self) -> bool {
184 self.public_key.iter().all(|&b| b == 0)
185 }
186
187 fn verify_test_signature(&self, manifest_hash: &[u8; 32], signature: &[u8]) -> VerifyResult {
193 if signature.len() >= 36 && &signature[0..4] == b"TEST" {
195 if &signature[4..36] == manifest_hash {
197 return VerifyResult::Valid;
198 }
199 return VerifyResult::HashMismatch;
200 }
201
202 if signature.iter().all(|&b| b == 0) {
204 return VerifyResult::Valid;
205 }
206
207 VerifyResult::Invalid
208 }
209}
210
211#[allow(dead_code)]
235pub fn verify_boot_signature(public_key: &[u8], manifest: &[u8], signature: &[u8]) {
236 let verifier = SignatureVerifier::new(public_key);
237 verifier.verify_boot_signature(manifest, signature);
238}
239
240impl From<VerifyResult> for KernelError {
242 fn from(result: VerifyResult) -> Self {
243 match result {
244 VerifyResult::Valid => {
245 KernelError::InternalError
247 }
248 VerifyResult::Invalid
249 | VerifyResult::WrongLength
250 | VerifyResult::WrongKeyLength
251 | VerifyResult::HashMismatch => KernelError::InvalidSignature,
252 }
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259
260 fn create_test_signature(manifest: &[u8]) -> [u8; SIGNATURE_SIZE] {
261 let mut sig = [0u8; SIGNATURE_SIZE];
262
263 sig[0..4].copy_from_slice(b"TEST");
265
266 let hash = SignatureVerifier::compute_hash(manifest);
268 sig[4..36].copy_from_slice(&hash);
269
270 sig
271 }
272
273 #[test]
274 fn test_verify_valid_signature() {
275 let verifier = SignatureVerifier::test_verifier();
276 let manifest = b"test manifest data";
277 let signature = create_test_signature(manifest);
278
279 let result = verifier.verify(manifest, &signature);
280 assert_eq!(result, VerifyResult::Valid);
281 assert!(result.is_valid());
282 }
283
284 #[test]
285 fn test_verify_wrong_signature_length() {
286 let verifier = SignatureVerifier::test_verifier();
287 let manifest = b"test manifest";
288 let signature = [0u8; 100]; let result = verifier.verify(manifest, &signature);
291 assert_eq!(result, VerifyResult::WrongLength);
292 }
293
294 #[test]
295 fn test_verify_hash_mismatch() {
296 let verifier = SignatureVerifier::test_verifier();
297 let manifest = b"test manifest";
298 let wrong_manifest = b"different manifest";
299 let signature = create_test_signature(wrong_manifest);
300
301 let result = verifier.verify(manifest, &signature);
302 assert_eq!(result, VerifyResult::HashMismatch);
303 }
304
305 #[test]
306 fn test_verify_all_zeros_signature() {
307 let verifier = SignatureVerifier::test_verifier();
308 let manifest = b"test manifest";
309 let signature = [0u8; SIGNATURE_SIZE];
310
311 let result = verifier.verify(manifest, &signature);
313 assert_eq!(result, VerifyResult::Valid);
314 }
315
316 #[test]
317 fn test_boot_signature_valid() {
318 let public_key = [0u8; PUBLIC_KEY_SIZE];
319 let manifest = b"boot manifest";
320 let signature = create_test_signature(manifest);
321
322 verify_boot_signature(&public_key, manifest, &signature);
324 }
325
326 #[test]
327 #[should_panic(expected = "Boot signature verification failed")]
328 fn test_boot_signature_invalid_panics() {
329 let public_key = [0u8; PUBLIC_KEY_SIZE];
330 let manifest = b"boot manifest";
331 let wrong_manifest = b"wrong manifest";
332 let signature = create_test_signature(wrong_manifest);
333
334 verify_boot_signature(&public_key, manifest, &signature);
336 }
337
338 #[test]
339 #[should_panic(expected = "wrong length")]
340 fn test_wrong_public_key_length_panics() {
341 let bad_key = [0u8; 100]; let _ = SignatureVerifier::new(&bad_key);
343 }
344
345 #[test]
346 fn test_verify_result_to_kernel_error() {
347 assert_eq!(KernelError::from(VerifyResult::Invalid), KernelError::InvalidSignature);
348 assert_eq!(KernelError::from(VerifyResult::WrongLength), KernelError::InvalidSignature);
349 assert_eq!(KernelError::from(VerifyResult::HashMismatch), KernelError::InvalidSignature);
350 }
351
352 #[test]
353 fn test_compute_hash_deterministic() {
354 let data = b"test data for hashing";
355 let hash1 = SignatureVerifier::compute_hash(data);
356 let hash2 = SignatureVerifier::compute_hash(data);
357
358 assert_eq!(hash1, hash2);
359 }
360
361 #[test]
362 fn test_compute_hash_different_inputs() {
363 let data1 = b"input one";
364 let data2 = b"input two";
365
366 let hash1 = SignatureVerifier::compute_hash(data1);
367 let hash2 = SignatureVerifier::compute_hash(data2);
368
369 assert_ne!(hash1, hash2);
370 }
371}