zipsign_api/verify/
mod.rs1#[cfg(feature = "verify-tar")]
4mod tar;
5#[cfg(feature = "verify-zip")]
6mod zip;
7
8use std::io::Read;
9
10#[cfg(feature = "verify-tar")]
11pub use self::tar::{VerifyTarError, verify_tar};
12#[cfg(feature = "verify-zip")]
13pub use self::zip::{VerifyZipError, verify_zip};
14use crate::constants::{BUF_LIMIT, HEADER_SIZE, MAGIC_HEADER, SignatureCountLeInt};
15use crate::{
16 PUBLIC_KEY_LENGTH, Prehash, SIGNATURE_LENGTH, Signature, SignatureError, VerifyingKey,
17};
18
19crate::Error! {
20 pub struct CollectKeysError(KeysError) {
22 #[error("the input was empty")]
23 Empty,
24 #[error("could not read key #{1}")]
25 Io(#[source] std::io::Error, usize),
26 #[error("input contained an illegal key at #{1}")]
27 Signature(#[source] SignatureError, usize),
28 }
29}
30
31pub fn collect_keys<K>(keys: K) -> Result<Vec<VerifyingKey>, CollectKeysError>
33where
34 K: IntoIterator<Item = std::io::Result<[u8; PUBLIC_KEY_LENGTH]>>,
35{
36 let keys = keys
37 .into_iter()
38 .enumerate()
39 .map(|(idx, key)| {
40 let key = key.map_err(|err| KeysError::Io(err, idx))?;
41 VerifyingKey::from_bytes(&key).map_err(|err| KeysError::Signature(err, idx))
42 })
43 .collect::<Result<Vec<_>, _>>()?;
44 if keys.is_empty() {
45 return Err(KeysError::Empty.into());
46 }
47 Ok(keys)
48}
49
50#[derive(Debug, Clone, Copy, thiserror::Error)]
52#[error("no matching key/signature pair found")]
53pub struct NoMatch;
54
55pub fn find_match(
58 keys: &[VerifyingKey],
59 signatures: &[Signature],
60 prehashed_message: &Prehash,
61 context: Option<&[u8]>,
62) -> Result<(usize, usize), NoMatch> {
63 for (key_idx, key) in keys.iter().enumerate() {
64 for (sig_idx, signature) in signatures.iter().enumerate() {
65 let is_ok = key
66 .verify_prehashed_strict(prehashed_message.0.clone(), context, signature)
67 .is_ok();
68 if is_ok {
69 return Ok((key_idx, sig_idx));
70 }
71 }
72 }
73 Err(NoMatch)
74}
75
76crate::Error! {
77 pub struct ReadSignaturesError(SignaturesError) {
79 #[error("the input contained no signatures")]
80 Empty,
81 #[error("could not read signatures")]
82 Read(#[source] std::io::Error),
83 #[error("the expected magic header was missing or corrupted")]
84 MagicHeader,
85 #[error("input contained an illegal signature at #{1}")]
86 Signature(#[source] SignatureError, usize),
87 }
88}
89
90pub fn read_signatures<I>(input: &mut I) -> Result<Vec<Signature>, ReadSignaturesError>
92where
93 I: ?Sized + Read,
94{
95 let mut header = [0; HEADER_SIZE];
96 input
97 .read_exact(&mut header)
98 .map_err(SignaturesError::Read)?;
99 if header[..MAGIC_HEADER.len()] != *MAGIC_HEADER {
100 return Err(SignaturesError::MagicHeader.into());
101 }
102
103 let signature_count = header[MAGIC_HEADER.len()..].try_into().unwrap();
104 let signature_count = SignatureCountLeInt::from_le_bytes(signature_count) as usize;
105 if signature_count == 0 {
106 return Err(SignaturesError::Empty.into());
107 }
108 let signature_bytes = signature_count * SIGNATURE_LENGTH;
109 if signature_bytes > BUF_LIMIT {
110 return Err(SignaturesError::MagicHeader.into());
111 }
112
113 let mut signatures = vec![0; signature_bytes];
114 input
115 .read_exact(&mut signatures)
116 .map_err(SignaturesError::Read)?;
117
118 let signatures = signatures
119 .chunks_exact(SIGNATURE_LENGTH)
120 .enumerate()
121 .map(|(idx, bytes)| {
122 Signature::from_slice(bytes).map_err(|err| SignaturesError::Signature(err, idx))
123 })
124 .collect::<Result<Vec<_>, _>>()?;
125
126 Ok(signatures)
127}