Skip to content

Commit

Permalink
Sign in-place
Browse files Browse the repository at this point in the history
  • Loading branch information
Kijewski committed Sep 15, 2023
1 parent c13fc90 commit af23321
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 30 deletions.
8 changes: 2 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,9 @@ jobs:
zipsign gen-key priv.key pub.key
tar czf Cargo.lock.tgz Cargo.lock
zipsign sign tar -o Cargo.lock.signed.tgz Cargo.lock.tgz priv.key
rm Cargo.lock.tgz
mv Cargo.lock.signed.tgz Cargo.lock.tgz
zipsign sign tar Cargo.lock.tgz priv.key
zipsign verify tar Cargo.lock.tgz pub.key
zip Cargo.lock.zip Cargo.lock
zipsign sign zip -o Cargo.lock.signed.zip Cargo.lock.zip priv.key
rm Cargo.lock.zip
mv Cargo.lock.signed.zip Cargo.lock.zip
zipsign sign zip Cargo.lock.zip priv.key
zipsign verify zip Cargo.lock.zip pub.key
97 changes: 97 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ default-members = [".", "api"]
base64 = "0.21"
clap = { version = "4", features = ["derive"] }
ed25519-dalek = { version = "2", features = ["digest"] }
normalize-path = "0.2"
pretty-error-debug = "0.3"
rand_core = { version = "0.6", features = ["getrandom"] }
tempfile = "3"
thiserror = "1"
zip = { version = "0.6", default-features = false }

Expand All @@ -30,8 +32,10 @@ features = ["verify-tar", "verify-zip", "sign-tar", "sign-zip"]
[dependencies]
clap.workspace = true
ed25519-dalek = { workspace = true, features = ["rand_core"] }
normalize-path.workspace = true
pretty-error-debug.workspace = true
rand_core.workspace = true
tempfile.workspace = true
thiserror.workspace = true
zipsign-api.workspace = true

Expand Down
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ cargo install --git https://github.com/Kijewski/zipsign
Cargo.lock

# Sign the ZIP file:
$ zipsign sign zip -o Cargo.lock.signed.zip Cargo.lock.zip priv.key
$ mv Cargo.lock.signed.zip Cargo.lock.zip
$ zipsign sign zip Cargo.lock.zip priv.key
$ unzip -l Cargo.lock.zip
Cargo.lock

Expand All @@ -48,8 +47,7 @@ cargo install --git https://github.com/Kijewski/zipsign
Cargo.lock
# Sign the .tar.gz file:
$ zipsign sign tar -o Cargo.lock.signed.tgz Cargo.lock.tgz priv.key
$ mv Cargo.lock.signed.tgz Cargo.lock.tgz
$ zipsign sign tar Cargo.lock.tgz priv.key
$ tar tzf Cargo.lock.tgz
Cargo.lock
Expand All @@ -74,7 +72,7 @@ Options:
### Sign a .zip or .tar.gz file
Usage: `zipsign sign [zip|tar] -o <SIGNED_FILE> <INPUT> <KEYS>...`
Usage: `zipsign sign [zip|tar] [-o <OUTPUT>] <INPUT> <KEYS>...`
Subcommands:
Expand All @@ -83,7 +81,7 @@ Subcommands:
Options:
* `-o`, `--output <OUTPUT>`: Signed file to generate
* `-o`, `--output <OUTPUT>`: Signed file to generate (if omitted, the input is overwritten)
* `-c`, `--context <CONTEXT>`: Arbitrary string used to salt the input, defaults to file name of `<INPUT>`
* `-f`, `--force`: Overwrite output file if it exists
Expand Down
42 changes: 24 additions & 18 deletions src/sign.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::fs::{File, OpenOptions};
use std::fs::{rename, File};
use std::io::Write;
use std::path::PathBuf;
use std::path::{Path, PathBuf};

use clap::{Args, Parser, Subcommand};
use normalize_path::NormalizePath;
use zipsign_api::prehash;
use zipsign_api::sign::{
copy_and_sign_tar, copy_and_sign_zip, gather_signature_data, read_signing_keys,
Expand Down Expand Up @@ -51,9 +52,9 @@ enum ArchiveKind {
struct CommonArgs {
/// Input file to sign
input: PathBuf,
/// Signed file to generate
/// Signed file to generate (if omitted, the input is overwritten)
#[arg(long, short = 'o')]
output: PathBuf,
output: Option<PathBuf>,
/// One or more files containing private keys
#[arg(required = true)]
keys: Vec<PathBuf>,
Expand All @@ -75,14 +76,16 @@ pub(crate) enum Error {
InputOpen(#[source] std::io::Error),
#[error("could not read input")]
InputRead(#[source] std::io::Error),
#[error("could not open or create output file")]
OutputOpen(#[source] std::io::Error),
#[error("could not rename output file")]
OutputRename(#[source] std::io::Error),
#[error("could not write to output")]
OutputWrite(#[source] std::io::Error),
#[error("could not read signing keys")]
ReadSigningKeys(#[from] ReadSigningKeysError),
#[error("could not copy and sign the input")]
Tar(#[from] SignTarError),
#[error("could not create temporary file in output directory")]
Tempfile(#[source] std::io::Error),
#[error("could not copy and sign the input")]
Zip(#[from] SignZipError),
}
Expand All @@ -95,28 +98,31 @@ pub(crate) fn main(args: Cli) -> Result<(), Error> {
let keys = args.keys.into_iter().map(File::open);
let keys = read_signing_keys(keys)?;

let mut input = File::open(&args.input).map_err(Error::InputOpen)?;
let mut output = OpenOptions::new()
.create(true)
.create_new(!args.force)
.read(true)
.write(true)
.truncate(true)
.open(&args.output)
.map_err(Error::OutputOpen)?;
let output_path = args.output.as_deref().unwrap_or(&args.input).normalize();
let output_dir = output_path.parent().unwrap_or(Path::new("."));
let mut output_file = tempfile::Builder::new()
.prefix(".zipsign.")
.suffix(".tmp")
.tempfile_in(output_dir)
.map_err(Error::Tempfile)?;

let mut input = File::open(&args.input).map_err(Error::InputOpen)?;
match kind {
ArchiveKind::Separate => {
let prehashed_message = prehash(&mut input).map_err(Error::InputRead)?;
let data = gather_signature_data(&keys, &prehashed_message, Some(context))?;
output.write_all(&data).map_err(Error::OutputWrite)?;
output_file.write_all(&data).map_err(Error::OutputWrite)?;
},
ArchiveKind::Zip => {
copy_and_sign_zip(&mut input, &mut output, &keys, Some(context))?;
copy_and_sign_zip(&mut input, &mut output_file, &keys, Some(context))?;
},
ArchiveKind::Tar => {
copy_and_sign_tar(&mut input, &mut output, &keys, Some(context))?;
copy_and_sign_tar(&mut input, &mut output_file, &keys, Some(context))?;
},
}
// drop input so it can be overwritten input=output
drop(input);

rename(output_file.into_temp_path(), output_path).map_err(Error::OutputRename)?;
Ok(())
}

0 comments on commit af23321

Please sign in to comment.