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 = HEADER_SIZE + keys.len() * SIGNATURE_LENGTH;
82    if signature_bytes > BUF_LIMIT {
83        return Err(SignaturesError::TooManyKeys.into());
84    }
85
86    let mut header = [0; HEADER_SIZE];
87    header[..MAGIC_HEADER.len()].copy_from_slice(MAGIC_HEADER);
88    header[MAGIC_HEADER.len()..]
89        .copy_from_slice(&(keys.len() as SignatureCountLeInt).to_le_bytes());
90
91    let mut buf = Vec::with_capacity(signature_bytes);
92    buf.extend(header);
93    for (idx, key) in keys.iter().enumerate() {
94        let signature = key
95            .sign_prehashed(prehashed_message.0.clone(), context)
96            .map_err(|err| SignaturesError::Signature(err, idx))?;
97        buf.extend(signature.to_bytes());
98    }
99    Ok(buf)
100}