diff options
Diffstat (limited to 'src/git/commit.rs')
-rw-r--r-- | src/git/commit.rs | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/src/git/commit.rs b/src/git/commit.rs new file mode 100644 index 0000000..cb4a516 --- /dev/null +++ b/src/git/commit.rs @@ -0,0 +1,46 @@ +// Copyright © 2022 Kim Altintop <kim@eagain.io> +// SPDX-License-Identifier: GPL-2.0-only WITH openvpn-openssl-exception + +use crate::ssh; + +const SSHSIG_NAMESPACE: &str = "git"; + +pub fn commit_signed<'a, S>( + signer: &mut S, + repo: &'a git2::Repository, + msg: impl AsRef<str>, + tree: &git2::Tree<'a>, + parents: &[&git2::Commit<'a>], +) -> crate::Result<git2::Oid> +where + S: crate::keys::Signer + ?Sized, +{ + let aut = repo.signature()?; + let buf = repo.commit_create_buffer(&aut, &aut, msg.as_ref(), tree, parents)?; + let sig = { + let hash = ssh::HashAlg::Sha512; + let data = ssh::SshSig::signed_data(SSHSIG_NAMESPACE, hash, &buf)?; + let sig = signer.sign(&data)?; + ssh::SshSig::new(signer.ident().key_data(), SSHSIG_NAMESPACE, hash, sig)? + .to_pem(ssh::LineEnding::LF)? + }; + let oid = repo.commit_signed( + buf.as_str().expect("commit buffer to be utf8"), + sig.as_str(), + None, + )?; + + Ok(oid) +} + +pub fn verify_commit_signature( + repo: &git2::Repository, + oid: &git2::Oid, +) -> crate::Result<ssh::PublicKey> { + let (sig, data) = repo.extract_signature(oid, None)?; + let sig = ssh::SshSig::from_pem(&*sig)?; + let pk = ssh::PublicKey::from(sig.public_key().clone()); + pk.verify(SSHSIG_NAMESPACE, &data, &sig)?; + + Ok(pk) +} |