aboutsummaryrefslogtreecommitdiff
path: root/object/signed
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-04-02 06:23:30 +0000
committerGravatar Runxi Yu2026-04-02 06:28:39 +0000
commita041d523de389b65b98a5373a8034041db2a8d83 (patch)
tree7b423dc735f463be616045f2c3c2095a7737aca7 /object/signed
parentresearch: Add dynamic pack resources (diff)
signatureNo signature
*: Remove
Diffstat (limited to 'object/signed')
-rw-r--r--object/signed/commit/commit.go15
-rw-r--r--object/signed/commit/doc.go6
-rw-r--r--object/signed/commit/integration_test.go138
-rw-r--r--object/signed/commit/parse.go107
-rw-r--r--object/signed/commit/payload_append.go11
-rw-r--r--object/signed/commit/signature_algorithms.go16
-rw-r--r--object/signed/commit/signature_append.go17
-rw-r--r--object/signed/commit/unit_test.go170
-rw-r--r--object/signed/doc.go7
-rw-r--r--object/signed/tag/doc.go3
-rw-r--r--object/signed/tag/integration_test.go139
-rw-r--r--object/signed/tag/parse.go143
-rw-r--r--object/signed/tag/payload_append.go11
-rw-r--r--object/signed/tag/signature_algorithms.go16
-rw-r--r--object/signed/tag/signature_append.go17
-rw-r--r--object/signed/tag/tag.go15
-rw-r--r--object/signed/tag/unit_test.go257
17 files changed, 0 insertions, 1088 deletions
diff --git a/object/signed/commit/commit.go b/object/signed/commit/commit.go
deleted file mode 100644
index cd0ff197..00000000
--- a/object/signed/commit/commit.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package signedcommit
-
-import objectid "codeberg.org/lindenii/furgit/object/id"
-
-// Commit represents the payload and signatures parsed from a raw comit object.
-type Commit struct {
- body []byte
- payload []byteRange
- signatures map[objectid.Algorithm][]byteRange
-}
-
-type byteRange struct {
- start int
- end int
-}
diff --git a/object/signed/commit/doc.go b/object/signed/commit/doc.go
deleted file mode 100644
index 91da6fa8..00000000
--- a/object/signed/commit/doc.go
+++ /dev/null
@@ -1,6 +0,0 @@
-// Package signedcommit extracts commit signing payloads and signatures from raw
-// commit object bodies.
-package signedcommit
-
-// TODO: Consider whether we want to fully copy the bytes into here.
-// The Append functions are a bit weird ergonomically.
diff --git a/object/signed/commit/integration_test.go b/object/signed/commit/integration_test.go
deleted file mode 100644
index 82b34b14..00000000
--- a/object/signed/commit/integration_test.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package signedcommit_test
-
-import (
- "bytes"
- "os"
- "os/exec"
- "path/filepath"
- "testing"
-
- "codeberg.org/lindenii/furgit/internal/testgit"
- objectid "codeberg.org/lindenii/furgit/object/id"
- signedcommit "codeberg.org/lindenii/furgit/object/signed/commit"
-)
-
-func setupSSHSignedCommit(
- t *testing.T,
- algo objectid.Algorithm,
-) (payload []byte, allowedSignersPath string, signaturePath string) {
- t.Helper()
-
- testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo})
-
- signDir := t.TempDir()
-
- signRoot, err := os.OpenRoot(signDir)
- if err != nil {
- t.Fatalf("os.OpenRoot(%q): %v", signDir, err)
- }
-
- t.Cleanup(func() { _ = signRoot.Close() })
-
- privateKeyPath := filepath.Join(signDir, "signing_key")
- allowedSignersPath = filepath.Join(signDir, "allowed_signers")
- signaturePath = filepath.Join(signDir, "commit.sig")
-
- cmd := exec.Command( //nolint:noctx
- "ssh-keygen",
- "-q",
- "-t", "ed25519",
- "-N", "",
- "-C", "runxiyu@umich.edu",
- "-f", privateKeyPath,
- ) //#nosec G204
-
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatalf("ssh-keygen generate failed: %v\n%s", err, out)
- }
-
- publicKey, err := signRoot.ReadFile("signing_key.pub")
- if err != nil {
- t.Fatalf("ReadFile(signing_key.pub): %v", err)
- }
-
- err = signRoot.WriteFile(
- "allowed_signers",
- append([]byte("runxiyu@umich.edu "), publicKey...),
- 0o600,
- )
- if err != nil {
- t.Fatalf("WriteFile(allowed_signers): %v", err)
- }
-
- testRepo.Run(t, "config", "gpg.format", "ssh")
- testRepo.Run(t, "config", "user.signingkey", privateKeyPath)
-
- testRepo.WriteFile(t, "file.txt", []byte("signed\n"), 0o644)
- testRepo.Run(t, "add", "file.txt")
- testRepo.Run(t, "commit", "-S", "-m", "signed commit")
-
- commitID := testRepo.RevParse(t, "HEAD^{commit}")
- body := testRepo.CatFile(t, "commit", commitID)
-
- commit, err := signedcommit.Parse(body)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
-
- signature, ok := commit.AppendSignature(nil, algo)
- if !ok {
- t.Fatalf("missing %s signature", algo)
- }
-
- err = signRoot.WriteFile("commit.sig", signature, 0o600)
- if err != nil {
- t.Fatalf("WriteFile(commit.sig): %v", err)
- }
-
- return commit.AppendPayload(nil), allowedSignersPath, signaturePath
-}
-
-func TestSSHSignedCommitIntegration(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- payload, allowedSignersPath, signaturePath := setupSSHSignedCommit(t, algo)
-
- cmd := exec.Command( //nolint:noctx
- "ssh-keygen",
- "-Y", "verify",
- "-n", "git",
- "-f", allowedSignersPath,
- "-I", "runxiyu@umich.edu",
- "-s", signaturePath,
- ) //#nosec G204
- cmd.Stdin = bytes.NewReader(payload)
-
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatalf("ssh-keygen verify failed: %v\n%s", err, out)
- }
- })
-}
-
-func TestSSHSignedCommitIntegrationRejectsTamperedPayload(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- payload, allowedSignersPath, signaturePath := setupSSHSignedCommit(t, algo)
- payload = append([]byte(nil), payload...)
- payload[len(payload)-2] ^= 1
-
- cmd := exec.Command( //nolint:noctx
- "ssh-keygen",
- "-Y", "verify",
- "-n", "git",
- "-f", allowedSignersPath,
- "-I", "runxiyu@umich.edu",
- "-s", signaturePath,
- ) //#nosec G204
- cmd.Stdin = bytes.NewReader(payload)
-
- out, err := cmd.CombinedOutput()
- if err == nil {
- t.Fatalf("ssh-keygen verify unexpectedly succeeded:\n%s", out)
- }
- })
-}
diff --git a/object/signed/commit/parse.go b/object/signed/commit/parse.go
deleted file mode 100644
index fa498093..00000000
--- a/object/signed/commit/parse.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package signedcommit
-
-import (
- "bytes"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
-)
-
-// Parse parses one raw commit object body for signature extraction.
-//
-// The returned Commit remains valid only while body remains unchanged.
-//
-// Labels: Deps-Borrowed, Life-Parent.
-func Parse(body []byte) (*Commit, error) {
- commit := &Commit{
- body: body,
- signatures: make(map[objectid.Algorithm][]byteRange),
- }
-
- payloadStart := 0
- i := 0
-
- for i < len(body) {
- lineStart := i
-
- rel := bytes.IndexByte(body[i:], '\n')
- next := len(body)
-
- lineEnd := len(body)
- if rel >= 0 {
- lineEnd = i + rel
- next = lineEnd + 1
- }
-
- line := body[lineStart:lineEnd]
- i = next
-
- if len(line) == 0 {
- commit.appendPayloadRange(payloadStart, len(body))
-
- return commit, nil
- }
-
- if line[0] == ' ' {
- continue
- }
-
- if !bytes.HasPrefix(line, []byte("gpgsig")) {
- continue
- }
-
- commit.appendPayloadRange(payloadStart, lineStart)
-
- key, valueStart, found := bytes.Cut(line, []byte{' '})
- if found {
- if algo, ok := objectid.ParseSignatureHeaderName(string(key)); ok {
- commit.signatures[algo] = append(commit.signatures[algo], byteRange{
- start: lineEnd - len(valueStart),
- end: next,
- })
- }
- }
-
- for i < len(body) {
- rel := bytes.IndexByte(body[i:], '\n')
- next = len(body)
-
- lineEnd = len(body)
- if rel >= 0 {
- lineEnd = i + rel
- next = lineEnd + 1
- }
-
- contStart := i
-
- cont := body[contStart:lineEnd]
- if len(cont) == 0 || cont[0] != ' ' {
- break
- }
-
- if found {
- if algo, ok := objectid.ParseSignatureHeaderName(string(key)); ok {
- commit.signatures[algo] = append(commit.signatures[algo], byteRange{
- start: contStart + 1,
- end: next,
- })
- }
- }
-
- i = next
- }
-
- payloadStart = i
- }
-
- commit.appendPayloadRange(payloadStart, len(body))
-
- return commit, nil
-}
-
-func (commit *Commit) appendPayloadRange(start, end int) {
- if start >= end {
- return
- }
-
- commit.payload = append(commit.payload, byteRange{start: start, end: end})
-}
diff --git a/object/signed/commit/payload_append.go b/object/signed/commit/payload_append.go
deleted file mode 100644
index c261910a..00000000
--- a/object/signed/commit/payload_append.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package signedcommit
-
-// AppendPayload appends the commit verification payload to dst, omitting all
-// embedded signature headers.
-func (commit *Commit) AppendPayload(dst []byte) []byte {
- for _, part := range commit.payload {
- dst = append(dst, commit.body[part.start:part.end]...)
- }
-
- return dst
-}
diff --git a/object/signed/commit/signature_algorithms.go b/object/signed/commit/signature_algorithms.go
deleted file mode 100644
index ac763706..00000000
--- a/object/signed/commit/signature_algorithms.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package signedcommit
-
-import objectid "codeberg.org/lindenii/furgit/object/id"
-
-// Algorithms returns the algorithms for which the commit carries signatures.
-func (commit *Commit) Algorithms() []objectid.Algorithm {
- var algorithms []objectid.Algorithm
-
- for _, algo := range objectid.SupportedAlgorithms() {
- if _, ok := commit.signatures[algo]; ok {
- algorithms = append(algorithms, algo)
- }
- }
-
- return algorithms
-}
diff --git a/object/signed/commit/signature_append.go b/object/signed/commit/signature_append.go
deleted file mode 100644
index 7f9144b7..00000000
--- a/object/signed/commit/signature_append.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package signedcommit
-
-import objectid "codeberg.org/lindenii/furgit/object/id"
-
-// AppendSignature appends the unfolded signature for algo to dst.
-func (commit *Commit) AppendSignature(dst []byte, algo objectid.Algorithm) ([]byte, bool) {
- signature, ok := commit.signatures[algo]
- if !ok {
- return dst, false
- }
-
- for _, part := range signature {
- dst = append(dst, commit.body[part.start:part.end]...)
- }
-
- return dst, true
-}
diff --git a/object/signed/commit/unit_test.go b/object/signed/commit/unit_test.go
deleted file mode 100644
index 88d4fa3b..00000000
--- a/object/signed/commit/unit_test.go
+++ /dev/null
@@ -1,170 +0,0 @@
-package signedcommit_test
-
-import (
- "slices"
- "testing"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
- signedcommit "codeberg.org/lindenii/furgit/object/signed/commit"
-)
-
-func TestParseUpstreamMultiplySignedCommit(t *testing.T) {
- t.Parallel()
-
- // t/t7510-signed-commit.sh
- body := []byte("" +
- "tree 0cfbf08886fca9a91cb753ec8734c84fcbe52c9f\n" +
- "parent 9da738312d24ef0a29be2c8c2b6fc5cf7085a293\n" +
- "author A U Thor <author@example.com> 1112912653 -0700\n" +
- "committer C O Mitter <committer@example.com> 1112912653 -0700\n" +
- "gpgsig -----BEGIN PGP SIGNATURE-----\n" +
- " \n" +
- " iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCX/uBDRYcY29tbWl0dGVy\n" +
- " QGV4YW1wbGUuY29tAAoJEBO29R7N3kMNd+8AoK1I8mhLHviPH+q2I5fIVgPsEtYC\n" +
- " AKCTqBh+VabJceXcGIZuF0Ry+udbBQ==\n" +
- " =tQ0N\n" +
- " -----END PGP SIGNATURE-----\n" +
- "gpgsig-sha256 -----BEGIN PGP SIGNATURE-----\n" +
- " \n" +
- " iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCX/uBIBYcY29tbWl0dGVy\n" +
- " QGV4YW1wbGUuY29tAAoJEBO29R7N3kMN/NEAn0XO9RYSBj2dFyozi0JKSbssYMtO\n" +
- " AJwKCQ1BQOtuwz//IjU8TiS+6S4iUw==\n" +
- " =pIwP\n" +
- " -----END PGP SIGNATURE-----\n" +
- "\n" +
- "second\n")
-
- commit, err := signedcommit.Parse(body)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
-
- gotPayload := string(commit.AppendPayload(nil))
-
- wantPayload := "" +
- "tree 0cfbf08886fca9a91cb753ec8734c84fcbe52c9f\n" +
- "parent 9da738312d24ef0a29be2c8c2b6fc5cf7085a293\n" +
- "author A U Thor <author@example.com> 1112912653 -0700\n" +
- "committer C O Mitter <committer@example.com> 1112912653 -0700\n" +
- "\n" +
- "second\n"
- if gotPayload != wantPayload {
- t.Fatalf("payload mismatch:\n got: %q\nwant: %q", gotPayload, wantPayload)
- }
-
- gotSHA1, ok := commit.AppendSignature(nil, objectid.AlgorithmSHA1)
- if !ok {
- t.Fatal("missing sha1 signature")
- }
-
- wantSHA1 := "" +
- "-----BEGIN PGP SIGNATURE-----\n" +
- "\n" +
- "iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCX/uBDRYcY29tbWl0dGVy\n" +
- "QGV4YW1wbGUuY29tAAoJEBO29R7N3kMNd+8AoK1I8mhLHviPH+q2I5fIVgPsEtYC\n" +
- "AKCTqBh+VabJceXcGIZuF0Ry+udbBQ==\n" +
- "=tQ0N\n" +
- "-----END PGP SIGNATURE-----\n"
- if string(gotSHA1) != wantSHA1 {
- t.Fatalf("sha1 signature mismatch:\n got: %q\nwant: %q", string(gotSHA1), wantSHA1)
- }
-
- gotSHA256, ok := commit.AppendSignature(nil, objectid.AlgorithmSHA256)
- if !ok {
- t.Fatal("missing sha256 signature")
- }
-
- wantSHA256 := "" +
- "-----BEGIN PGP SIGNATURE-----\n" +
- "\n" +
- "iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCX/uBIBYcY29tbWl0dGVy\n" +
- "QGV4YW1wbGUuY29tAAoJEBO29R7N3kMN/NEAn0XO9RYSBj2dFyozi0JKSbssYMtO\n" +
- "AJwKCQ1BQOtuwz//IjU8TiS+6S4iUw==\n" +
- "=pIwP\n" +
- "-----END PGP SIGNATURE-----\n"
- if string(gotSHA256) != wantSHA256 {
- t.Fatalf("sha256 signature mismatch:\n got: %q\nwant: %q", string(gotSHA256), wantSHA256)
- }
-
- gotAlgorithms := commit.Algorithms()
-
- wantAlgorithms := []objectid.Algorithm{
- objectid.AlgorithmSHA1,
- objectid.AlgorithmSHA256,
- }
- if !slices.Equal(gotAlgorithms, wantAlgorithms) {
- t.Fatalf("Algorithms() = %v, want %v", gotAlgorithms, wantAlgorithms)
- }
-}
-
-func TestParseStripsUnknownGpgsigHeadersFromPayload(t *testing.T) {
- t.Parallel()
-
- body := []byte("" +
- "tree deadbeef\n" +
- "gpgsig-future header\n" +
- " continued\n" +
- "\n" +
- "message\n")
-
- commit, err := signedcommit.Parse(body)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
-
- gotPayload := string(commit.AppendPayload(nil))
-
- wantPayload := "" +
- "tree deadbeef\n" +
- "\n" +
- "message\n"
- if gotPayload != wantPayload {
- t.Fatalf("payload mismatch:\n got: %q\nwant: %q", gotPayload, wantPayload)
- }
-
- if gotAlgorithms := commit.Algorithms(); len(gotAlgorithms) != 0 {
- t.Fatalf("Algorithms() = %v, want none", gotAlgorithms)
- }
-}
-
-func TestParseAllowsDuplicateSignatureHeaders(t *testing.T) {
- t.Parallel()
-
- body := []byte("" +
- "tree deadbeef\n" +
- "gpgsig one\n" +
- " two\n" +
- "gpgsig three\n" +
- " four\n" +
- "\n" +
- "message\n")
-
- commit, err := signedcommit.Parse(body)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
-
- gotPayload := string(commit.AppendPayload(nil))
-
- wantPayload := "" +
- "tree deadbeef\n" +
- "\n" +
- "message\n"
- if gotPayload != wantPayload {
- t.Fatalf("payload mismatch:\n got: %q\nwant: %q", gotPayload, wantPayload)
- }
-
- gotSignature, ok := commit.AppendSignature(nil, objectid.AlgorithmSHA1)
- if !ok {
- t.Fatal("missing sha1 signature")
- }
-
- wantSignature := "" +
- "one\n" +
- "two\n" +
- "three\n" +
- "four\n"
- if string(gotSignature) != wantSignature {
- t.Fatalf("signature mismatch:\n got: %q\nwant: %q", string(gotSignature), wantSignature)
- }
-}
diff --git a/object/signed/doc.go b/object/signed/doc.go
deleted file mode 100644
index fb6fc3f8..00000000
--- a/object/signed/doc.go
+++ /dev/null
@@ -1,7 +0,0 @@
-// Package signed encapsulates raw signed-object processing.
-//
-// Its subpackages extract verification payloads and embedded signatures from
-// raw commit and tag object bodies, without depending on the parsed
-// object models in [codeberg.org/lindenii/furgit/object/commit] and
-// [codeberg.org/lindenii/furgit/object/tag].
-package signed
diff --git a/object/signed/tag/doc.go b/object/signed/tag/doc.go
deleted file mode 100644
index 22b1098a..00000000
--- a/object/signed/tag/doc.go
+++ /dev/null
@@ -1,3 +0,0 @@
-// Package signedtag extracts tag signing payloads and signatures from raw tag
-// object bodies.
-package signedtag
diff --git a/object/signed/tag/integration_test.go b/object/signed/tag/integration_test.go
deleted file mode 100644
index af32aa02..00000000
--- a/object/signed/tag/integration_test.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package signedtag_test
-
-import (
- "bytes"
- "os"
- "os/exec"
- "path/filepath"
- "testing"
-
- "codeberg.org/lindenii/furgit/internal/testgit"
- objectid "codeberg.org/lindenii/furgit/object/id"
- signedtag "codeberg.org/lindenii/furgit/object/signed/tag"
-)
-
-func setupSSHSignedTag(
- t *testing.T,
- algo objectid.Algorithm,
-) (payload []byte, allowedSignersPath string, signaturePath string) {
- t.Helper()
-
- testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo})
-
- signDir := t.TempDir()
-
- signRoot, err := os.OpenRoot(signDir)
- if err != nil {
- t.Fatalf("os.OpenRoot(%q): %v", signDir, err)
- }
-
- t.Cleanup(func() { _ = signRoot.Close() })
-
- privateKeyPath := filepath.Join(signDir, "signing_key")
- allowedSignersPath = filepath.Join(signDir, "allowed_signers")
- signaturePath = filepath.Join(signDir, "tag.sig")
-
- cmd := exec.Command( //nolint:noctx
- "ssh-keygen",
- "-q",
- "-t", "ed25519",
- "-N", "",
- "-C", "runxiyu@umich.edu",
- "-f", privateKeyPath,
- ) //#nosec G204
-
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatalf("ssh-keygen generate failed: %v\n%s", err, out)
- }
-
- publicKey, err := signRoot.ReadFile("signing_key.pub")
- if err != nil {
- t.Fatalf("ReadFile(signing_key.pub): %v", err)
- }
-
- err = signRoot.WriteFile(
- "allowed_signers",
- append([]byte("runxiyu@umich.edu "), publicKey...),
- 0o600,
- )
- if err != nil {
- t.Fatalf("WriteFile(allowed_signers): %v", err)
- }
-
- testRepo.Run(t, "config", "gpg.format", "ssh")
- testRepo.Run(t, "config", "user.signingkey", privateKeyPath)
-
- testRepo.WriteFile(t, "file.txt", []byte("signed\n"), 0o644)
- testRepo.Run(t, "add", "file.txt")
- testRepo.Run(t, "commit", "-m", "base commit")
- testRepo.Run(t, "tag", "-s", "-m", "signed tag", "signed-tag")
-
- tagID := testRepo.RevParse(t, "signed-tag^{tag}")
- body := testRepo.CatFile(t, "tag", tagID)
-
- tag, err := signedtag.Parse(body, algo)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
-
- signature, ok := tag.AppendSignature(nil, algo)
- if !ok {
- t.Fatal("missing signature")
- }
-
- err = signRoot.WriteFile("tag.sig", signature, 0o600)
- if err != nil {
- t.Fatalf("WriteFile(tag.sig): %v", err)
- }
-
- return tag.AppendPayload(nil), allowedSignersPath, signaturePath
-}
-
-func TestSSHSignedTagIntegration(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- payload, allowedSignersPath, signaturePath := setupSSHSignedTag(t, algo)
-
- cmd := exec.Command( //nolint:noctx
- "ssh-keygen",
- "-Y", "verify",
- "-n", "git",
- "-f", allowedSignersPath,
- "-I", "runxiyu@umich.edu",
- "-s", signaturePath,
- ) //#nosec G204
- cmd.Stdin = bytes.NewReader(payload)
-
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatalf("ssh-keygen verify failed: %v\n%s", err, out)
- }
- })
-}
-
-func TestSSHSignedTagIntegrationRejectsTamperedPayload(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- payload, allowedSignersPath, signaturePath := setupSSHSignedTag(t, algo)
- payload = append([]byte(nil), payload...)
- payload[len(payload)-2] ^= 1
-
- cmd := exec.Command( //nolint:noctx
- "ssh-keygen",
- "-Y", "verify",
- "-n", "git",
- "-f", allowedSignersPath,
- "-I", "runxiyu@umich.edu",
- "-s", signaturePath,
- ) //#nosec G204
- cmd.Stdin = bytes.NewReader(payload)
-
- out, err := cmd.CombinedOutput()
- if err == nil {
- t.Fatalf("ssh-keygen verify unexpectedly succeeded:\n%s", out)
- }
- })
-}
diff --git a/object/signed/tag/parse.go b/object/signed/tag/parse.go
deleted file mode 100644
index b2061d3f..00000000
--- a/object/signed/tag/parse.go
+++ /dev/null
@@ -1,143 +0,0 @@
-package signedtag
-
-import (
- "bytes"
- "slices"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
-)
-
-var signatureBeginLines = [][]byte{ //nolint:gochecknoglobals
- []byte("-----BEGIN PGP SIGNATURE-----"),
- []byte("-----BEGIN PGP MESSAGE-----"),
- []byte("-----BEGIN SSH SIGNATURE-----"),
- []byte("-----BEGIN SIGNED MESSAGE-----"),
-}
-
-// Parse parses one raw tag object body for signature extraction.
-//
-// Git stores the signature for storageAlgo as an in-body ASCII-armored
-// trailer, and may store additional signatures for other algorithms in
-// gpgsig* headers.
-//
-// The returned Tag remains valid only while body remains unchanged.
-//
-// Labels: Deps-Borrowed, Life-Parent.
-func Parse(body []byte, storageAlgo objectid.Algorithm) (*Tag, error) {
- tag := &Tag{
- body: body,
- signatures: make(map[objectid.Algorithm][]byteRange),
- }
-
- signatureStart := len(body)
- for i := 0; i < len(body); {
- lineStart := i
- rel := bytes.IndexByte(body[i:], '\n')
- next := len(body)
-
- lineEnd := len(body)
- if rel >= 0 {
- lineEnd = i + rel
- next = lineEnd + 1
- }
-
- line := body[lineStart:lineEnd]
- if slices.ContainsFunc(signatureBeginLines, func(begin []byte) bool {
- return bytes.HasPrefix(line, begin)
- }) {
- signatureStart = lineStart
- }
-
- i = next
- }
-
- payloadStart := 0
-
- payloadEnd := signatureStart
- if signatureStart == len(body) {
- payloadEnd = len(body)
- }
-
- for i := 0; i < payloadEnd; {
- lineStart := i
- rel := bytes.IndexByte(body[i:payloadEnd], '\n')
- next := payloadEnd
-
- lineEnd := payloadEnd
- if rel >= 0 {
- lineEnd = i + rel
- next = lineEnd + 1
- }
-
- line := body[lineStart:lineEnd]
- i = next
-
- if len(line) == 0 {
- break
- }
-
- if line[0] == ' ' {
- continue
- }
-
- key, valueStart, found := bytes.Cut(line, []byte{' '})
- if !found {
- continue
- }
-
- algo, ok := objectid.ParseSignatureHeaderName(string(key))
- if !ok {
- continue
- }
-
- tag.appendPayloadRange(payloadStart, lineStart)
- tag.signatures[algo] = append(tag.signatures[algo], byteRange{
- start: lineEnd - len(valueStart),
- end: next,
- })
-
- for i < payloadEnd {
- rel := bytes.IndexByte(body[i:payloadEnd], '\n')
- next = payloadEnd
-
- lineEnd = payloadEnd
- if rel >= 0 {
- lineEnd = i + rel
- next = lineEnd + 1
- }
-
- cont := body[i:lineEnd]
- if len(cont) == 0 || cont[0] != ' ' {
- break
- }
-
- tag.signatures[algo] = append(tag.signatures[algo], byteRange{
- start: i + 1,
- end: next,
- })
-
- i = next
- }
-
- payloadStart = i
- }
-
- tag.appendPayloadRange(payloadStart, payloadEnd)
-
- if signatureStart != len(body) {
- tag.signatures[storageAlgo] = append(tag.signatures[storageAlgo], byteRange{
- start: signatureStart,
- end: len(body),
- })
- }
-
- return tag, nil
-}
-
-func (tag *Tag) appendPayloadRange(start, end int) {
- if start >= end {
- return
- }
-
- tag.payload = append(tag.payload, byteRange{start: start, end: end})
-}
diff --git a/object/signed/tag/payload_append.go b/object/signed/tag/payload_append.go
deleted file mode 100644
index dae29dd8..00000000
--- a/object/signed/tag/payload_append.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package signedtag
-
-// AppendPayload appends the tag verification payload to dst, omitting all
-// embedded signatures.
-func (tag *Tag) AppendPayload(dst []byte) []byte {
- for _, part := range tag.payload {
- dst = append(dst, tag.body[part.start:part.end]...)
- }
-
- return dst
-}
diff --git a/object/signed/tag/signature_algorithms.go b/object/signed/tag/signature_algorithms.go
deleted file mode 100644
index bc178bce..00000000
--- a/object/signed/tag/signature_algorithms.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package signedtag
-
-import objectid "codeberg.org/lindenii/furgit/object/id"
-
-// Algorithms returns the algorithms for which the tag carries signatures.
-func (tag *Tag) Algorithms() []objectid.Algorithm {
- var algorithms []objectid.Algorithm
-
- for _, algo := range objectid.SupportedAlgorithms() {
- if _, ok := tag.signatures[algo]; ok {
- algorithms = append(algorithms, algo)
- }
- }
-
- return algorithms
-}
diff --git a/object/signed/tag/signature_append.go b/object/signed/tag/signature_append.go
deleted file mode 100644
index 101816eb..00000000
--- a/object/signed/tag/signature_append.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package signedtag
-
-import objectid "codeberg.org/lindenii/furgit/object/id"
-
-// AppendSignature appends the signature for algo to dst.
-func (tag *Tag) AppendSignature(dst []byte, algo objectid.Algorithm) ([]byte, bool) {
- signature, ok := tag.signatures[algo]
- if !ok {
- return dst, false
- }
-
- for _, part := range signature {
- dst = append(dst, tag.body[part.start:part.end]...)
- }
-
- return dst, true
-}
diff --git a/object/signed/tag/tag.go b/object/signed/tag/tag.go
deleted file mode 100644
index 2ebf9369..00000000
--- a/object/signed/tag/tag.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package signedtag
-
-import objectid "codeberg.org/lindenii/furgit/object/id"
-
-// Tag represents the payload and signatures parsed from a raw tag object.
-type Tag struct {
- body []byte
- payload []byteRange
- signatures map[objectid.Algorithm][]byteRange
-}
-
-type byteRange struct {
- start int
- end int
-}
diff --git a/object/signed/tag/unit_test.go b/object/signed/tag/unit_test.go
deleted file mode 100644
index dd4ae66f..00000000
--- a/object/signed/tag/unit_test.go
+++ /dev/null
@@ -1,257 +0,0 @@
-package signedtag_test
-
-import (
- "testing"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
- signedtag "codeberg.org/lindenii/furgit/object/signed/tag"
-)
-
-func TestParseSignedTag(t *testing.T) {
- t.Parallel()
-
- body := []byte("" +
- "object 04b871796dc0420f8e7561a895b52484b701d51a\n" +
- "type commit\n" +
- "tag signedtag\n" +
- "tagger C O Mitter <committer@example.com> 1465981006 +0000\n" +
- "gpgsig-sha256 -----BEGIN PGP SIGNATURE-----\n" +
- " Version: GnuPG v1\n" +
- " \n" +
- " header-signature\n" +
- " -----END PGP SIGNATURE-----\n" +
- "\n" +
- "signed tag\n" +
- "\n" +
- "signed tag message body\n" +
- "-----BEGIN PGP SIGNATURE-----\n" +
- "Version: GnuPG v1\n" +
- "\n" +
- "body-signature\n" +
- "-----END PGP SIGNATURE-----\n")
-
- tag, err := signedtag.Parse(body, objectid.AlgorithmSHA1)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
-
- gotPayload := string(tag.AppendPayload(nil))
-
- wantPayload := "" +
- "object 04b871796dc0420f8e7561a895b52484b701d51a\n" +
- "type commit\n" +
- "tag signedtag\n" +
- "tagger C O Mitter <committer@example.com> 1465981006 +0000\n" +
- "\n" +
- "signed tag\n" +
- "\n" +
- "signed tag message body\n"
- if gotPayload != wantPayload {
- t.Fatalf("payload mismatch:\n got: %q\nwant: %q", gotPayload, wantPayload)
- }
-
- gotAlgorithms := tag.Algorithms()
- if len(gotAlgorithms) != 2 || gotAlgorithms[0] != objectid.AlgorithmSHA1 || gotAlgorithms[1] != objectid.AlgorithmSHA256 {
- t.Fatalf("algorithms mismatch: got %v", gotAlgorithms)
- }
-
- gotSignature, ok := tag.AppendSignature(nil, objectid.AlgorithmSHA1)
- if !ok {
- t.Fatal("missing sha1 signature")
- }
-
- wantSignature := "" +
- "-----BEGIN PGP SIGNATURE-----\n" +
- "Version: GnuPG v1\n" +
- "\n" +
- "body-signature\n" +
- "-----END PGP SIGNATURE-----\n"
- if string(gotSignature) != wantSignature {
- t.Fatalf("signature mismatch:\n got: %q\nwant: %q", string(gotSignature), wantSignature)
- }
-
- gotHeaderSignature, ok := tag.AppendSignature(nil, objectid.AlgorithmSHA256)
- if !ok {
- t.Fatal("missing sha256 signature")
- }
-
- wantHeaderSignature := "" +
- "-----BEGIN PGP SIGNATURE-----\n" +
- "Version: GnuPG v1\n" +
- "\n" +
- "header-signature\n" +
- "-----END PGP SIGNATURE-----\n"
- if string(gotHeaderSignature) != wantHeaderSignature {
- t.Fatalf("header signature mismatch:\n got: %q\nwant: %q", string(gotHeaderSignature), wantHeaderSignature)
- }
-}
-
-func TestParseHeaderOnlyTagStripsHeaderAndKeepsHeaderSignature(t *testing.T) {
- t.Parallel()
-
- body := []byte("" +
- "object deadbeef\n" +
- "type commit\n" +
- "tag signedtag\n" +
- "tagger T A Gger <tagger@example.com> 1465981006 +0000\n" +
- "gpgsig-sha256 header\n" +
- " continued\n" +
- "\n" +
- "message\n")
-
- tag, err := signedtag.Parse(body, objectid.AlgorithmSHA1)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
-
- gotPayload := string(tag.AppendPayload(nil))
-
- wantPayload := "" +
- "object deadbeef\n" +
- "type commit\n" +
- "tag signedtag\n" +
- "tagger T A Gger <tagger@example.com> 1465981006 +0000\n" +
- "\n" +
- "message\n"
- if gotPayload != wantPayload {
- t.Fatalf("payload mismatch:\n got: %q\nwant: %q", gotPayload, wantPayload)
- }
-
- gotSignature, ok := tag.AppendSignature(nil, objectid.AlgorithmSHA256)
- if !ok {
- t.Fatal("missing sha256 signature")
- }
-
- wantSignature := "" +
- "header\n" +
- "continued\n"
- if string(gotSignature) != wantSignature {
- t.Fatalf("signature mismatch:\n got: %q\nwant: %q", string(gotSignature), wantSignature)
- }
-
- if _, ok := tag.AppendSignature(nil, objectid.AlgorithmSHA1); ok {
- t.Fatal("unexpected sha1 signature")
- }
-}
-
-func TestParseKeepsUnknownHeaderSignatureTextInPayload(t *testing.T) {
- t.Parallel()
-
- body := []byte("" +
- "object deadbeef\n" +
- "type commit\n" +
- "tag signedtag\n" +
- "tagger T A Gger <tagger@example.com> 1465981006 +0000\n" +
- "gpgsig-future header\n" +
- " continued\n" +
- "\n" +
- "message line\n" +
- "-----BEGIN PGP SIGNATURE-----\n" +
- "body-signature\n" +
- "-----END PGP SIGNATURE-----\n")
-
- tag, err := signedtag.Parse(body, objectid.AlgorithmSHA1)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
-
- gotPayload := string(tag.AppendPayload(nil))
-
- wantPayload := "" +
- "object deadbeef\n" +
- "type commit\n" +
- "tag signedtag\n" +
- "tagger T A Gger <tagger@example.com> 1465981006 +0000\n" +
- "gpgsig-future header\n" +
- " continued\n" +
- "\n" +
- "message line\n"
- if gotPayload != wantPayload {
- t.Fatalf("payload mismatch:\n got: %q\nwant: %q", gotPayload, wantPayload)
- }
-}
-
-func TestParseKeepsMessageGpgsigTextInPayload(t *testing.T) {
- t.Parallel()
-
- body := []byte("" +
- "object deadbeef\n" +
- "type commit\n" +
- "tag signedtag\n" +
- "tagger T A Gger <tagger@example.com> 1465981006 +0000\n" +
- "\n" +
- "message line\n" +
- "gpgsig-future header\n" +
- " continued\n" +
- "-----BEGIN PGP SIGNATURE-----\n" +
- "body-signature\n" +
- "-----END PGP SIGNATURE-----\n")
-
- tag, err := signedtag.Parse(body, objectid.AlgorithmSHA1)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
-
- gotPayload := string(tag.AppendPayload(nil))
-
- wantPayload := "" +
- "object deadbeef\n" +
- "type commit\n" +
- "tag signedtag\n" +
- "tagger T A Gger <tagger@example.com> 1465981006 +0000\n" +
- "\n" +
- "message line\n" +
- "gpgsig-future header\n" +
- " continued\n"
- if gotPayload != wantPayload {
- t.Fatalf("payload mismatch:\n got: %q\nwant: %q", gotPayload, wantPayload)
- }
-}
-
-func TestParseUsesLastSignatureBeginByPrefix(t *testing.T) {
- t.Parallel()
-
- body := []byte("" +
- "object deadbeef\n" +
- "type commit\n" +
- "tag signedtag\n" +
- "tagger T A Gger <tagger@example.com> 1465981006 +0000\n" +
- "\n" +
- "message\n" +
- "-----BEGIN PGP SIGNATURE----- stray\n" +
- "still message\n" +
- "-----BEGIN PGP SIGNATURE----- trailing\n" +
- "body-signature\n")
-
- tag, err := signedtag.Parse(body, objectid.AlgorithmSHA1)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
-
- gotPayload := string(tag.AppendPayload(nil))
-
- wantPayload := "" +
- "object deadbeef\n" +
- "type commit\n" +
- "tag signedtag\n" +
- "tagger T A Gger <tagger@example.com> 1465981006 +0000\n" +
- "\n" +
- "message\n" +
- "-----BEGIN PGP SIGNATURE----- stray\n" +
- "still message\n"
- if gotPayload != wantPayload {
- t.Fatalf("payload mismatch:\n got: %q\nwant: %q", gotPayload, wantPayload)
- }
-
- gotSignature, ok := tag.AppendSignature(nil, objectid.AlgorithmSHA1)
- if !ok {
- t.Fatal("missing signature")
- }
-
- wantSignature := "" +
- "-----BEGIN PGP SIGNATURE----- trailing\n" +
- "body-signature\n"
- if string(gotSignature) != wantSignature {
- t.Fatalf("signature mismatch:\n got: %q\nwant: %q", string(gotSignature), wantSignature)
- }
-}