Skip to main content

zipsign_api/sign/
mod.rs

1//! Functions to sign a file
2
3#[cfg(feature = "sign-tar")]
4mod tar;
5#[cfg(feature = "sign-zip")]
6mod zip;
7
8use std::io::Read;
9
10#[cfg(feature = "sign-tar")]
11pub use self::tar::{SignTarError, copy_and_sign_tar};
12#[cfg(feature = "sign-zip")]
13pub use self::zip::{SignZipError, copy_and_sign_zip};
14use crate::constants::{BUF_LIMIT, HEADER_SIZE, MAGIC_HEADER, SignatureCountLeInt};
15use crate::{KEYPAIR_LENGTH, Prehash, SIGNATURE_LENGTH, SignatureError, SigningKey};
16
17crate::Error! {
18    /// An error returned by [`read_signing_keys()`]
19    pub struct ReadSigningKeysError(KeysError) {
20        #[error("input #{1} did not contain a valid key")]
21        Construct(#[source] ed25519_dalek::ed25519::Error, usize),
22        #[error("no signing keys provided")]
23        Empty,
24        #[error("could not read key in file #{1}")]
25        Read(#[source] std::io::Error, usize),
26    }
27}
28
29/// Read signing keys from an [`Iterator`] of [readable][Read] inputs
30pub fn read_signing_keys<I, R>(inputs: I) -> Result<Vec<SigningKey>, ReadSigningKeysError>
31where
32    I: IntoIterator<Item = std::io::Result<R>>,
33    R: Read,
34{
35    // read signing keys
36    let mut keys = inputs
37        .into_iter()
38        .enumerate()
39        .map(|(key_index, input)| {
40            let mut key = [0; KEYPAIR_LENGTH];
41            input
42                .and_then(|mut input| input.read_exact(&mut key))
43                .map_err(|err| KeysError::Read(err, key_index))?;
44            SigningKey::from_keypair_bytes(&key).map_err(|err| KeysError::Construct(err, key_index))
45        })
46        .collect::<Result<Vec<_>, _>>()?;
47    if keys.is_empty() {
48        return Err(KeysError::Empty.into());
49    }
50    keys.sort_by(|l, r| {
51        l.verifying_key()
52            .as_bytes()
53            .cmp(r.verifying_key().as_bytes())
54    });
55    Ok(keys)
56}
57
58crate::Error! {
59    /// An error returned by [`gather_signature_data()`]
60    pub struct GatherSignatureDataError(SignaturesError) {
61        #[error("no signing keys provided")]
62        Empty,
63        #[error("could not sign data with key #{1}")]
64        Signature(#[source] SignatureError, usize),
65        #[error("too many signing keys provided")]
66        TooManyKeys,
67    }
68}
69
70/// Sign a pre-hashed message with all provided signing keys, and return a signature block incl.
71/// a header
72pub fn gather_signature_data(
73    keys: &[SigningKey],
74    prehashed_message: &Prehash,
75    context: Option<&[u8]>,
76) -> Result<Vec<u8>, GatherSignatureDataError> {
77    if keys.is_empty() {
78        return Err(SignaturesError::Empty.into());
79    }
80
81    let signature_bytes = keys
82        .len()
83        .checked_mul(SIGNATURE_LENGTH)
84        .and_then(|s| s.checked_add(HEADER_SIZE))
85        .ok_or(SignaturesError::TooManyKeys)?;
86    if signature_bytes > BUF_LIMIT {
87        return Err(SignaturesError::TooManyKeys.into());
88    }
89
90    let mut header = [0; HEADER_SIZE];
91    header[..MAGIC_HEADER.len()].copy_from_slice(MAGIC_HEADER);
92    header[MAGIC_HEADER.len()..]
93        .copy_from_slice(&(keys.len() as SignatureCountLeInt).to_le_bytes());
94
95    let mut buf = Vec::with_capacity(signature_bytes);
96    buf.extend(header);
97    for (idx, key) in keys.iter().enumerate() {
98        let signature = key
99            .sign_prehashed(prehashed_message.0.clone(), context)
100            .map_err(|err| SignaturesError::Signature(err, idx))?;
101        buf.extend(signature.to_bytes());
102    }
103    Ok(buf)
104}