1use log::*;
2use std::io::{BufReader, BufWriter, prelude::*};
3
4use crate::ED25519_PK_ID;
5use crate::SIGNATURE_VERSION;
6use crate::SIGNATURE_WASM_MODULE_CONTENT_TYPE;
7use crate::error::*;
8use crate::wasm_module::*;
9
10pub const SIGNATURE_SECTION_HEADER_NAME: &str = "signature";
11pub const SIGNATURE_SECTION_DELIMITER_NAME: &str = "signature_delimiter";
12
13pub const MAX_HASHES: usize = 64;
14pub const MAX_SIGNATURES: usize = 256;
15pub const MAX_CERTIFICATES: usize = 16;
17
18#[derive(PartialEq, Debug, Clone, Eq)]
19pub struct SignatureForHashes {
20 pub key_id: Option<Vec<u8>>,
21 pub alg_id: u8,
22 pub signature: Vec<u8>,
23 pub certificate_chain: Option<Vec<Vec<u8>>>,
27}
28
29#[derive(PartialEq, Debug, Clone, Eq)]
30pub struct SignedHashes {
31 pub hashes: Vec<Vec<u8>>,
32 pub signatures: Vec<SignatureForHashes>,
33}
34
35#[derive(PartialEq, Debug, Clone, Eq)]
36pub struct SignatureData {
37 pub specification_version: u8,
38 pub content_type: u8,
39 pub hash_function: u8,
40 pub signed_hashes_set: Vec<SignedHashes>,
41}
42
43impl SignatureForHashes {
44 pub fn serialize(&self) -> Result<Vec<u8>, WSError> {
45 let mut writer = BufWriter::new(Vec::new());
46 if let Some(key_id) = &self.key_id {
47 varint::put_slice(&mut writer, key_id)?;
48 } else {
49 varint::put(&mut writer, 0)?;
50 }
51 writer.write_all(&[self.alg_id])?;
52 varint::put_slice(&mut writer, &self.signature)?;
53
54 if let Some(cert_chain) = &self.certificate_chain {
56 varint::put(&mut writer, cert_chain.len() as _)?;
57 for cert in cert_chain {
58 varint::put_slice(&mut writer, cert)?;
59 }
60 } else {
61 varint::put(&mut writer, 0)?; }
63
64 writer
65 .into_inner()
66 .map_err(|e| WSError::IOError(std::io::Error::other(format!("buffer flush failed: {}", e))))
67 }
68
69 pub fn deserialize(bin: impl AsRef<[u8]>) -> Result<Self, WSError> {
70 let mut reader = BufReader::new(bin.as_ref());
71 let key_id = varint::get_slice(&mut reader)?;
72 let key_id = if key_id.is_empty() {
73 None
74 } else {
75 Some(key_id)
76 };
77 let mut alg_id = [0u8; 1];
78 reader.read_exact(&mut alg_id)?;
79 let alg_id = alg_id[0];
80 if alg_id != ED25519_PK_ID {
81 debug!("Unsupported algorithm: {:02x}", alg_id);
82 return Err(WSError::ParseError);
83 }
84 let signature = varint::get_slice(&mut reader)?;
85
86 let certificate_chain = if let Ok(cert_count) = varint::get32(&mut reader) {
88 if cert_count as usize > MAX_CERTIFICATES {
89 debug!(
90 "Too many certificates: {} (max: {})",
91 cert_count, MAX_CERTIFICATES
92 );
93 return Err(WSError::TooManyCertificates(MAX_CERTIFICATES));
94 }
95 if cert_count > 0 {
96 let mut certs = Vec::with_capacity(cert_count as usize);
97 for _ in 0..cert_count {
98 if let Ok(cert) = varint::get_slice(&mut reader) {
99 certs.push(cert);
100 }
101 }
102 Some(certs)
103 } else {
104 None
105 }
106 } else {
107 None
108 };
109
110 Ok(Self {
111 key_id,
112 alg_id,
113 signature,
114 certificate_chain,
115 })
116 }
117}
118
119impl SignedHashes {
120 pub fn serialize(&self) -> Result<Vec<u8>, WSError> {
121 let mut writer = BufWriter::new(Vec::new());
122 varint::put(&mut writer, self.hashes.len() as _)?;
123 for hash in &self.hashes {
124 writer.write_all(hash)?;
125 }
126 varint::put(&mut writer, self.signatures.len() as _)?;
127 for signature in &self.signatures {
128 varint::put_slice(&mut writer, &signature.serialize()?)?;
129 }
130 writer
131 .into_inner()
132 .map_err(|e| WSError::IOError(std::io::Error::other(format!("buffer flush failed: {}", e))))
133 }
134
135 pub fn deserialize(bin: impl AsRef<[u8]>) -> Result<Self, WSError> {
136 let mut reader = BufReader::new(bin.as_ref());
137 let hashes_count = varint::get32(&mut reader)? as _;
138 if hashes_count > MAX_HASHES {
139 debug!("Too many hashes: {} (max: {})", hashes_count, MAX_HASHES);
140 return Err(WSError::TooManyHashes(MAX_HASHES));
141 }
142 let mut hashes = Vec::with_capacity(hashes_count);
143 for _ in 0..hashes_count {
144 let mut hash = vec![0; 32];
145 reader.read_exact(&mut hash)?;
146 hashes.push(hash);
147 }
148 let signatures_count = varint::get32(&mut reader)? as _;
149 if signatures_count > MAX_SIGNATURES {
150 debug!(
151 "Too many signatures: {} (max: {})",
152 signatures_count, MAX_SIGNATURES
153 );
154 return Err(WSError::TooManySignatures(MAX_SIGNATURES));
155 }
156 let mut signatures = Vec::with_capacity(signatures_count);
157 for _ in 0..signatures_count {
158 let bin = varint::get_slice(&mut reader)?;
159 if let Ok(signature) = SignatureForHashes::deserialize(bin) {
160 signatures.push(signature);
161 }
162 }
163 Ok(Self { hashes, signatures })
164 }
165}
166
167impl SignatureData {
168 pub fn serialize(&self) -> Result<Vec<u8>, WSError> {
169 let mut writer = BufWriter::new(Vec::new());
170 varint::put(&mut writer, self.specification_version as _)?;
171 varint::put(&mut writer, self.content_type as _)?;
172 varint::put(&mut writer, self.hash_function as _)?;
173 varint::put(&mut writer, self.signed_hashes_set.len() as _)?;
174 for signed_hashes in &self.signed_hashes_set {
175 varint::put_slice(&mut writer, &signed_hashes.serialize()?)?;
176 }
177 writer
178 .into_inner()
179 .map_err(|e| WSError::IOError(std::io::Error::other(format!("buffer flush failed: {}", e))))
180 }
181
182 pub fn deserialize(bin: impl AsRef<[u8]>) -> Result<Self, WSError> {
183 let mut reader = BufReader::new(bin.as_ref());
184 let specification_version = varint::get7(&mut reader)?;
185 if specification_version != SIGNATURE_VERSION {
186 debug!(
187 "Unsupported specification version: {:02x}",
188 specification_version
189 );
190 return Err(WSError::ParseError);
191 }
192 let content_type = varint::get7(&mut reader)?;
193 if content_type != SIGNATURE_WASM_MODULE_CONTENT_TYPE {
194 debug!("Unsupported content type: {:02x}", content_type);
195 return Err(WSError::ParseError);
196 }
197 let hash_function = varint::get7(&mut reader)?;
198 let signed_hashes_count = varint::get32(&mut reader)? as _;
199 if signed_hashes_count > MAX_HASHES {
200 debug!(
201 "Too many hashes: {} (max: {})",
202 signed_hashes_count, MAX_HASHES
203 );
204 return Err(WSError::TooManyHashes(MAX_HASHES));
205 }
206 let mut signed_hashes_set = Vec::with_capacity(signed_hashes_count);
207 for _ in 0..signed_hashes_count {
208 let bin = varint::get_slice(&mut reader)?;
209 let signed_hashes = SignedHashes::deserialize(bin)?;
210 signed_hashes_set.push(signed_hashes);
211 }
212 Ok(Self {
213 specification_version,
214 content_type,
215 hash_function,
216 signed_hashes_set,
217 })
218 }
219}
220
221pub fn new_delimiter_section() -> Result<Section, WSError> {
222 let mut custom_payload = vec![0u8; 16];
223 getrandom::fill(&mut custom_payload)
224 .map_err(|_| WSError::InternalError("RNG error".to_string()))?;
225 Ok(Section::Custom(CustomSection::new(
226 SIGNATURE_SECTION_DELIMITER_NAME.to_string(),
227 custom_payload,
228 )))
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234
235 #[test]
236 fn test_signature_for_hashes_serialize_no_key_id() {
237 let sig = SignatureForHashes {
238 key_id: None,
239 alg_id: ED25519_PK_ID,
240 signature: vec![1, 2, 3, 4],
241 certificate_chain: None,
242 };
243 let serialized = sig.serialize().unwrap();
244 assert!(!serialized.is_empty());
245 assert_eq!(serialized[0], 0);
247 }
248
249 #[test]
250 fn test_signature_for_hashes_serialize_with_key_id() {
251 let sig = SignatureForHashes {
252 key_id: Some(vec![10, 20, 30]),
253 alg_id: ED25519_PK_ID,
254 signature: vec![1, 2, 3, 4],
255 certificate_chain: None,
256 };
257 let serialized = sig.serialize().unwrap();
258 assert!(!serialized.is_empty());
259 }
260
261 #[test]
262 fn test_signature_for_hashes_deserialize() {
263 let original = SignatureForHashes {
264 key_id: Some(vec![5, 6, 7]),
265 alg_id: ED25519_PK_ID,
266 signature: vec![11, 22, 33, 44],
267 certificate_chain: None,
268 };
269 let serialized = original.serialize().unwrap();
270 let deserialized = SignatureForHashes::deserialize(&serialized).unwrap();
271 assert_eq!(deserialized, original);
272 }
273
274 #[test]
275 fn test_signature_for_hashes_roundtrip_no_key_id() {
276 let original = SignatureForHashes {
277 key_id: None,
278 alg_id: ED25519_PK_ID,
279 signature: vec![100, 101, 102],
280 certificate_chain: None,
281 };
282 let serialized = original.serialize().unwrap();
283 let deserialized = SignatureForHashes::deserialize(&serialized).unwrap();
284 assert_eq!(deserialized.key_id, None);
285 assert_eq!(deserialized.alg_id, original.alg_id);
286 assert_eq!(deserialized.signature, original.signature);
287 }
288
289 #[test]
290 fn test_signed_hashes_serialize() {
291 let signed = SignedHashes {
292 hashes: vec![vec![1; 32], vec![2; 32]],
293 signatures: vec![SignatureForHashes {
294 key_id: None,
295 alg_id: ED25519_PK_ID,
296 signature: vec![9, 8, 7],
297 certificate_chain: None,
298 }],
299 };
300 let serialized = signed.serialize().unwrap();
301 assert!(!serialized.is_empty());
302 }
303
304 #[test]
305 fn test_signed_hashes_deserialize() {
306 let original = SignedHashes {
307 hashes: vec![vec![42; 32]],
308 signatures: vec![SignatureForHashes {
309 key_id: Some(vec![1, 2]),
310 alg_id: ED25519_PK_ID,
311 signature: vec![3, 4, 5],
312 certificate_chain: None,
313 }],
314 };
315 let serialized = original.serialize().unwrap();
316 let deserialized = SignedHashes::deserialize(&serialized).unwrap();
317 assert_eq!(deserialized.hashes.len(), 1);
318 assert_eq!(deserialized.hashes[0], vec![42; 32]);
319 assert_eq!(deserialized.signatures.len(), 1);
320 }
321
322 #[test]
323 fn test_signed_hashes_too_many_hashes() {
324 let mut buf = Vec::new();
326 varint::put(&mut buf, (MAX_HASHES + 1) as u64).unwrap();
327 let result = SignedHashes::deserialize(&buf);
328 assert!(result.is_err());
329 assert!(matches!(result.unwrap_err(), WSError::TooManyHashes(_)));
330 }
331
332 #[test]
333 fn test_signed_hashes_too_many_signatures() {
334 let mut buf = Vec::new();
336 varint::put(&mut buf, 1u64).unwrap(); buf.extend_from_slice(&[0u8; 32]); varint::put(&mut buf, (MAX_SIGNATURES + 1) as u64).unwrap();
341
342 let result = SignedHashes::deserialize(&buf);
343 assert!(result.is_err());
344 assert!(matches!(result.unwrap_err(), WSError::TooManySignatures(_)));
345 }
346
347 #[test]
348 fn test_signature_for_hashes_too_many_certificates() {
349 let mut buf = Vec::new();
351 varint::put(&mut buf, 0u64).unwrap(); buf.push(ED25519_PK_ID); varint::put_slice(&mut buf, &[1, 2, 3, 4]).unwrap(); varint::put(&mut buf, (MAX_CERTIFICATES + 1) as u64).unwrap();
357
358 let result = SignatureForHashes::deserialize(&buf);
359 assert!(result.is_err());
360 assert!(matches!(
361 result.unwrap_err(),
362 WSError::TooManyCertificates(_)
363 ));
364 }
365
366 #[test]
367 fn test_signature_for_hashes_extreme_certificate_count() {
368 let mut buf = Vec::new();
370 varint::put(&mut buf, 0u64).unwrap(); buf.push(ED25519_PK_ID); varint::put_slice(&mut buf, &[1, 2, 3, 4]).unwrap(); varint::put(&mut buf, 0xFFFF_FFFFu64).unwrap(); let result = SignatureForHashes::deserialize(&buf);
378 assert!(result.is_err());
379 assert!(matches!(
380 result.unwrap_err(),
381 WSError::TooManyCertificates(_)
382 ));
383 }
384
385 #[test]
386 fn test_signature_data_serialize() {
387 let data = SignatureData {
388 specification_version: SIGNATURE_VERSION,
389 content_type: SIGNATURE_WASM_MODULE_CONTENT_TYPE,
390 hash_function: 0x01,
391 signed_hashes_set: vec![SignedHashes {
392 hashes: vec![vec![99; 32]],
393 signatures: vec![],
394 }],
395 };
396 let serialized = data.serialize().unwrap();
397 assert!(!serialized.is_empty());
398 }
399
400 #[test]
401 fn test_signature_data_deserialize() {
402 let original = SignatureData {
403 specification_version: SIGNATURE_VERSION,
404 content_type: SIGNATURE_WASM_MODULE_CONTENT_TYPE,
405 hash_function: 0x01,
406 signed_hashes_set: vec![SignedHashes {
407 hashes: vec![vec![55; 32]],
408 signatures: vec![SignatureForHashes {
409 key_id: None,
410 alg_id: ED25519_PK_ID,
411 signature: vec![1, 2, 3],
412 certificate_chain: None,
413 }],
414 }],
415 };
416 let serialized = original.serialize().unwrap();
417 let deserialized = SignatureData::deserialize(&serialized).unwrap();
418 assert_eq!(
419 deserialized.specification_version,
420 original.specification_version
421 );
422 assert_eq!(deserialized.content_type, original.content_type);
423 assert_eq!(deserialized.hash_function, original.hash_function);
424 assert_eq!(deserialized.signed_hashes_set.len(), 1);
425 }
426
427 #[test]
428 fn test_signature_data_roundtrip() {
429 let original = SignatureData {
430 specification_version: SIGNATURE_VERSION,
431 content_type: SIGNATURE_WASM_MODULE_CONTENT_TYPE,
432 hash_function: 0x02,
433 signed_hashes_set: vec![
434 SignedHashes {
435 hashes: vec![vec![1; 32], vec![2; 32]],
436 signatures: vec![SignatureForHashes {
437 key_id: Some(vec![10, 11]),
438 alg_id: ED25519_PK_ID,
439 signature: vec![20, 21, 22],
440 certificate_chain: None,
441 }],
442 },
443 SignedHashes {
444 hashes: vec![vec![3; 32]],
445 signatures: vec![],
446 },
447 ],
448 };
449
450 let serialized = original.serialize().unwrap();
451 let deserialized = SignatureData::deserialize(&serialized).unwrap();
452
453 assert_eq!(deserialized, original);
454 }
455
456 #[test]
457 fn test_new_delimiter_section() {
458 let section = new_delimiter_section().unwrap();
459 assert!(section.is_signature_delimiter());
460
461 if let Section::Custom(custom) = section {
462 assert_eq!(custom.name(), SIGNATURE_SECTION_DELIMITER_NAME);
463 assert_eq!(custom.payload().len(), 16);
464 } else {
465 panic!("Expected custom section");
466 }
467 }
468
469 #[test]
470 fn test_new_delimiter_sections_are_unique() {
471 let section1 = new_delimiter_section().unwrap();
472 let section2 = new_delimiter_section().unwrap();
473
474 assert_ne!(section1.payload(), section2.payload());
476 }
477}