Initial signing support (#1345)

* Add CLI options

* Add manifest types

* Thread signature policy through to fetchers

* Thread signing section through from metadata

* Implement signing validation

* Clippy

* Attempt testing

* Yes and

* Why

* fmt

* Update crates/bin/src/args.rs

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* Update crates/binstalk-fetchers/src/gh_crate_meta.rs

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* Update crates/bin/src/args.rs

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* Update crates/binstalk-fetchers/src/signing.rs

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* Update crates/binstalk-fetchers/src/signing.rs

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* Update crates/binstalk-fetchers/src/signing.rs

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* Update crates/binstalk-fetchers/src/signing.rs

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* fixes

* Finish feature

* Document

* Include all fields in the signing.file template

* Readme document

* Review fixes

* Fail on non-utf8 sig

* Thank goodness for tests

* Run test in ci

* Add rsign2 commands

* Log utf8 error

* Update e2e-tests/signing.sh

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* Fix `e2e-tests/signing.sh` MacOS CI failure

Move the tls cert creation into `signing.sh` and sleep for 10s to wait
for https server to start.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Refactor e2e-tests-signing files

 - Use a tempdir generated by `mktemp` for all certificates-related
   files
 - Put other checked-in files into `e2e-tests/signing`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Fixed `e2e-tests-signing` connection err in MacOS CI

Wait for server to start up by trying to connect to it.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Fix `e2e-tests-signing` passing `-subj` to `openssl` on Windows

Use single quote instead of double quote to avoid automatic expansion
from bash

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Fix `e2e-tests-signing` waiting for server to startup

Remove `timeout` since it is not supported on MacOS.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Try to fix windows CI by setting `MSYS_NO_PATHCONV=1` on `openssl` cmds

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Fixed `e2e-tests-signing` on windows

By using double `//` for the value passed to option `-subj`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Fixed infinite loop in `signing/wait-for-server` on Windows

Pass `--ssl-revoke-best-effort` to prevent schannel from checking ssl
revocation status.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Add cap on retry attempt in `signing/wait-for-server.sh`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Let `singing/server.py` print output to stderr

so that we can see the error message there.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Fix running `signing/server.py` on MacOS CI

use `python3` since macos-latest still has python2 installed and
`python` is a symlink to `python2` there.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

---------

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Félix Saparelli 2023-09-23 16:02:56 +12:00 committed by GitHub
parent efbd20857b
commit 32beba507b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 723 additions and 150 deletions

View file

@ -0,0 +1,91 @@
use binstalk_downloader::download::DataVerifier;
use binstalk_types::cargo_toml_binstall::{PkgSigning, SigningAlgorithm};
use bytes::Bytes;
use minisign_verify::{PublicKey, Signature, StreamVerifier};
use tracing::{error, trace};
use crate::FetchError;
pub enum SignatureVerifier {
Noop,
Minisign(Box<MinisignVerifier>),
}
impl SignatureVerifier {
pub fn new(config: &PkgSigning, signature: &[u8]) -> Result<Self, FetchError> {
match config.algorithm {
SigningAlgorithm::Minisign => MinisignVerifier::new(config, signature)
.map(Box::new)
.map(Self::Minisign),
algorithm => Err(FetchError::UnsupportedSigningAlgorithm(algorithm)),
}
}
pub fn data_verifier(&self) -> Result<Box<dyn DataVerifier + '_>, FetchError> {
match self {
Self::Noop => Ok(Box::new(())),
Self::Minisign(v) => v.data_verifier(),
}
}
pub fn info(&self) -> Option<String> {
match self {
Self::Noop => None,
Self::Minisign(v) => Some(v.signature.trusted_comment().into()),
}
}
}
pub struct MinisignVerifier {
pubkey: PublicKey,
signature: Signature,
}
impl MinisignVerifier {
pub fn new(config: &PkgSigning, signature: &[u8]) -> Result<Self, FetchError> {
trace!(key=?config.pubkey, "parsing public key");
let pubkey = PublicKey::from_base64(&config.pubkey).map_err(|err| {
error!("Package public key is invalid: {err}");
FetchError::InvalidSignature
})?;
trace!(?signature, "parsing signature");
let signature = Signature::decode(std::str::from_utf8(signature).map_err(|err| {
error!(?signature, "Signature file is not UTF-8! {err}");
FetchError::InvalidSignature
})?)
.map_err(|err| {
error!("Signature file is invalid: {err}");
FetchError::InvalidSignature
})?;
Ok(Self { pubkey, signature })
}
pub fn data_verifier(&self) -> Result<Box<dyn DataVerifier + '_>, FetchError> {
self.pubkey
.verify_stream(&self.signature)
.map(|vs| Box::new(MinisignDataVerifier(vs)) as _)
.map_err(|err| {
error!("Failed to setup stream verifier: {err}");
FetchError::InvalidSignature
})
}
}
pub struct MinisignDataVerifier<'a>(StreamVerifier<'a>);
impl<'a> DataVerifier for MinisignDataVerifier<'a> {
fn update(&mut self, data: &Bytes) {
self.0.update(data);
}
fn validate(&mut self) -> bool {
if let Err(err) = self.0.finalize() {
error!("Failed to finalize signature verify: {err}");
false
} else {
true
}
}
}