⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/pkg/format/
signature.rs

1//! Package signature structures
2//!
3//! Handles serialization and deserialization of cryptographic signatures
4//! used for package verification. Supports dual-signature scheme with
5//! Ed25519 (classical) and Dilithium/ML-DSA (post-quantum) signatures.
6//!
7//! Also defines the signature policy, trust levels, and trusted key ring
8//! used by the package manager during installation to decide whether a
9//! package's cryptographic signatures are acceptable.
10
11use alloc::vec::Vec;
12
13// ============================================================================
14// Trust Levels
15// ============================================================================
16
17/// Trust level assigned to a signing key.
18///
19/// Levels are ordered: `Untrusted < Community < Developer < Core`.
20/// The package manager's [`SignaturePolicy`] specifies a minimum trust level
21/// that the signing key must meet for installation to proceed.
22#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
23#[repr(u8)]
24pub enum TrustLevel {
25    /// Key is not trusted (default for unknown keys)
26    #[default]
27    Untrusted = 0,
28    /// Community-contributed key (third-party packages)
29    Community = 1,
30    /// Verified developer key
31    Developer = 2,
32    /// Core OS key (kernel, base system)
33    Core = 3,
34}
35
36// ============================================================================
37// Signature Policy
38// ============================================================================
39
40/// Policy controlling how the package manager enforces signature verification.
41///
42/// # Examples
43///
44/// ```ignore
45/// // Production: require both Ed25519 and Dilithium, minimum Developer trust
46/// let policy = SignaturePolicy::production();
47///
48/// // Development: skip all signature checks
49/// let policy = SignaturePolicy::development();
50/// ```
51#[derive(Debug, Clone)]
52pub struct SignaturePolicy {
53    /// When `true`, packages must have a valid Ed25519 signature from a
54    /// trusted key. When `false`, signature verification is skipped entirely.
55    pub require_signatures: bool,
56    /// Minimum trust level the signing key must have.
57    pub minimum_trust_level: TrustLevel,
58    /// When `true`, require a valid post-quantum (Dilithium/ML-DSA) signature
59    /// in addition to the Ed25519 signature.
60    pub require_post_quantum: bool,
61}
62
63impl SignaturePolicy {
64    /// Production policy: require Ed25519 signatures at Developer trust level.
65    /// Post-quantum (Dilithium) is optional until ecosystem matures.
66    pub fn production() -> Self {
67        Self {
68            require_signatures: true,
69            minimum_trust_level: TrustLevel::Developer,
70            require_post_quantum: false,
71        }
72    }
73
74    /// Development policy: no signature requirements.
75    pub fn development() -> Self {
76        Self {
77            require_signatures: false,
78            minimum_trust_level: TrustLevel::Untrusted,
79            require_post_quantum: false,
80        }
81    }
82}
83
84impl Default for SignaturePolicy {
85    fn default() -> Self {
86        Self::production()
87    }
88}
89
90// ============================================================================
91// Trusted Key Ring
92// ============================================================================
93
94/// A trusted Ed25519 public key with its SHA-256 fingerprint and trust level.
95#[derive(Debug, Clone)]
96pub struct TrustedKey {
97    /// Ed25519 public key (32 bytes)
98    pub public_key: [u8; 32],
99    /// SHA-256 fingerprint of `public_key` for human-readable identification
100    pub fingerprint: [u8; 32],
101    /// Trust level assigned to this key
102    pub trust_level: TrustLevel,
103}
104
105/// Collection of trusted Ed25519 signing keys.
106///
107/// The package manager iterates over these keys when verifying a package
108/// signature, accepting the first key whose Ed25519 verification succeeds.
109#[derive(Debug, Clone)]
110pub struct TrustedKeyRing {
111    keys: Vec<TrustedKey>,
112}
113
114impl TrustedKeyRing {
115    /// Create an empty key ring.
116    pub fn new() -> Self {
117        Self { keys: Vec::new() }
118    }
119
120    /// Create a key ring pre-populated with the built-in test key.
121    ///
122    /// The built-in key is a deterministic test key for development.
123    /// Production builds MUST replace this with keys from a real key ceremony.
124    pub fn with_builtin_keys() -> Self {
125        let mut ring = Self::new();
126
127        // Deterministic test key derived from "VeridianOS-PKG-KEY"
128        let mut pk = [0u8; 32];
129        let seed: &[u8; 18] = b"VeridianOS-PKG-KEY";
130        for (i, byte) in pk.iter_mut().enumerate() {
131            *byte = seed[i % seed.len()].wrapping_add(i as u8);
132        }
133
134        let fp = crate::crypto::hash::sha256(&pk);
135        ring.add_key(TrustedKey {
136            public_key: pk,
137            fingerprint: *fp.as_bytes(),
138            trust_level: TrustLevel::Core,
139        });
140
141        ring
142    }
143
144    /// Add a trusted key to the ring.
145    pub fn add_key(&mut self, key: TrustedKey) {
146        self.keys.push(key);
147    }
148
149    /// Find the first key whose public key bytes match.
150    pub fn find_key(&self, public_key: &[u8; 32]) -> Option<&TrustedKey> {
151        self.keys.iter().find(|k| &k.public_key == public_key)
152    }
153
154    /// Find a key by its SHA-256 fingerprint.
155    pub fn find_by_fingerprint(&self, fingerprint: &[u8; 32]) -> Option<&TrustedKey> {
156        self.keys.iter().find(|k| &k.fingerprint == fingerprint)
157    }
158
159    /// Remove keys matching the given fingerprint.
160    pub fn remove_key(&mut self, fingerprint: &[u8; 32]) {
161        self.keys.retain(|k| &k.fingerprint != fingerprint);
162    }
163
164    /// Iterate over all trusted keys.
165    pub fn keys(&self) -> &[TrustedKey] {
166        &self.keys
167    }
168}
169
170impl Default for TrustedKeyRing {
171    fn default() -> Self {
172        Self::new()
173    }
174}
175
176// ============================================================================
177// Package Signatures (serialization)
178// ============================================================================
179
180/// Package signature section
181#[derive(Debug)]
182pub struct PackageSignatures {
183    /// Ed25519 signature (64 bytes)
184    pub ed25519_sig: [u8; 64],
185    /// Dilithium signature (variable size)
186    pub dilithium_sig: Vec<u8>,
187}
188
189impl PackageSignatures {
190    /// Serialize signatures to bytes
191    pub fn to_bytes(&self) -> Vec<u8> {
192        let mut bytes = Vec::new();
193
194        // Ed25519 signature
195        bytes.extend_from_slice(&self.ed25519_sig);
196
197        // Dilithium signature length (u32)
198        let dil_len = self.dilithium_sig.len() as u32;
199        bytes.extend_from_slice(&dil_len.to_le_bytes());
200
201        // Dilithium signature
202        bytes.extend_from_slice(&self.dilithium_sig);
203
204        bytes
205    }
206
207    /// Deserialize signatures from bytes
208    pub fn from_bytes(data: &[u8]) -> Result<Self, crate::error::KernelError> {
209        if data.len() < 68 {
210            // 64 (Ed25519) + 4 (length)
211            return Err(crate::error::KernelError::InvalidArgument {
212                name: "signature_data",
213                value: "data too short (need >= 68 bytes)",
214            });
215        }
216
217        // Extract Ed25519 signature
218        let mut ed25519_sig = [0u8; 64];
219        ed25519_sig.copy_from_slice(&data[0..64]);
220
221        // Extract Dilithium signature length
222        let dil_len = u32::from_le_bytes([data[64], data[65], data[66], data[67]]) as usize;
223
224        if data.len() < 68 + dil_len {
225            return Err(crate::error::KernelError::InvalidArgument {
226                name: "signature_data",
227                value: "invalid Dilithium signature length",
228            });
229        }
230
231        // Extract Dilithium signature
232        let dilithium_sig = data[68..68 + dil_len].to_vec();
233
234        Ok(Self {
235            ed25519_sig,
236            dilithium_sig,
237        })
238    }
239}