diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f18af5b5..57ba33eb 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -25,3 +25,6 @@ jobs: - name: Unit Tests run: make unit-test + + - name: Live dependency tests + run: make e2e-test diff --git a/Makefile b/Makefile index 2e520032..d0772245 100644 --- a/Makefile +++ b/Makefile @@ -42,3 +42,8 @@ install-all: install-gitsign install-credential-cache .PHONY: unit-test unit-test: go test -v ./... + +# These tests use live dependencies, and may otherwise modify state. +.PHONY: e2e-test +e2e-test: + go test -tags e2e -v ./... diff --git a/internal/e2e/offline_test.go b/internal/e2e/offline_test.go new file mode 100644 index 00000000..97bb51df --- /dev/null +++ b/internal/e2e/offline_test.go @@ -0,0 +1,65 @@ +// Copyright 2023 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build e2e +// +build e2e + +package e2e + +import ( + "context" + "crypto/x509" + "testing" + + "github.com/sigstore/gitsign/internal/fulcio/fulcioroots" + "github.com/sigstore/gitsign/internal/git/gittest" + "github.com/sigstore/gitsign/pkg/git" + "github.com/sigstore/gitsign/pkg/rekor" + "github.com/sigstore/sigstore/pkg/tuf" +) + +func TestVerifyOffline(t *testing.T) { + ctx := context.Background() + + // Initialize to prod root. + tuf.Initialize(ctx, tuf.DefaultRemoteRoot, nil) + root, intermediate, err := fulcioroots.New(x509.NewCertPool(), fulcioroots.FromTUF(ctx)) + if err != nil { + t.Fatalf("error getting certificate root: %v", err) + } + + client, err := rekor.New("https://rekor.sigstore.dev") + if err != nil { + t.Fatal(err) + } + + commit := gittest.ParseCommit(t, "testdata/offline.commit") + body := gittest.MarshalCommitBody(t, commit) + sig := []byte(commit.PGPSignature) + + verifier, err := git.NewCertVerifier(git.WithRootPool(root), git.WithIntermediatePool(intermediate)) + if err != nil { + t.Fatal(err) + } + + cert, err := verifier.Verify(ctx, body, sig, true) + if err != nil { + t.Fatal(err) + } + tlog, err := client.VerifyInclusion(ctx, sig, cert) + if err != nil { + t.Fatal(err) + } + t.Log(*tlog.LogIndex) +} diff --git a/internal/e2e/testdata/offline.commit b/internal/e2e/testdata/offline.commit new file mode 100644 index 00000000..ee4fe0a4 --- /dev/null +++ b/internal/e2e/testdata/offline.commit @@ -0,0 +1,47 @@ +tree 045f683042529876c1fe28f97f416c1501ffa433 +parent 74f0d242677d95a477f953260a2686712846c619 +author Billy Lynch 1685981477 -0400 +committer Billy Lynch 1685981477 -0400 +gpgsig -----BEGIN SIGNED MESSAGE----- + MIIHPQYJKoZIhvcNAQcCoIIHLjCCByoCAQExDTALBglghkgBZQMEAgEwCwYJKoZI + hvcNAQcBoIIC0DCCAswwggJSoAMCAQICFAG6/a9VuUO5SlyJA02E3aCq+I7nMAoG + CCqGSM49BAMDMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2ln + c3RvcmUtaW50ZXJtZWRpYXRlMB4XDTIzMDYwNTE2MTExOVoXDTIzMDYwNTE2MjEx + OVowADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKMghfIq5VOfOhMrxqHFiu8c + 91EbkxLIDLL1kjdhbNS2EfXg7xH3Q789yMKGGWwh3PxMJ3+6tXYi62b2mWVYwOej + ggFxMIIBbTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYD + VR0OBBYEFLNvhRMNCI6GVLzZjAKPQHfG+H62MB8GA1UdIwQYMBaAFN/T6c9WJBGW + +ajY6ShVosYuGGQ/MCIGA1UdEQEB/wQYMBaBFGJpbGx5QGNoYWluZ3VhcmQuZGV2 + MCkGCisGAQQBg78wAQEEG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTArBgor + BgEEAYO/MAEIBB0MG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTCBiQYKKwYB + BAHWeQIEAgR7BHkAdwB1AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6O + AAABiIxTwqMAAAQDAEYwRAIgHi+WbGvSz/kRzolvZfTodQZWomPXXVzV617mdESS + SzsCIG9lfwWn7Mh+m/EbdIIp7OxjA3av+ywcUDw1o/kSzegbMAoGCCqGSM49BAMD + A2gAMGUCMQDVOD6f+899Tiy7l+wominmzOPvkB2AZBr0OQ0JeEFeNRPuyBHrKF1l + UCupUEg9JsYCMCIR+qJqcKYkvDfrjQAnYXvuwc/lSZeLlQWCzNcZzACv14IcjklM + GA7DgiYJ6aL9tTGCBDMwggQvAgEBME8wNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2 + MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUCFAG6/a9VuUO5SlyJA02E + 3aCq+I7nMAsGCWCGSAFlAwQCAaBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEw + HAYJKoZIhvcNAQkFMQ8XDTIzMDYwNTE2MTExOVowLwYJKoZIhvcNAQkEMSIEIFVL + lVMl0NAe/AWmTBlo1LsuuVEnTnqXvagu9a1+USZ5MAoGCCqGSM49BAMCBEcwRQIg + MvJRYH8YjGI6aKjuj2BIvKtXauKmmfnTw6ftFHKHd7ICIQCtvl/bIvRutgXs2aIE + nLMhBKbUH7L3yIxCXXioSlMbbaGCAwowggMGBgorBgEEAYO/MAMBMYIC9gSCAvII + /9TuChIiCiDA0j1q1AaXP5VZ87otHKAfhBR9j/xbhEXCJPmLlZGAHRoVCgxoYXNo + ZWRyZWtvcmQSBTAuMC4xIKiS+KMGKkgKRjBEAiA2urRGPSYHNU7xitI+aOApUJy1 + NoYOC+AhkrypnjFpEQIgf8+9b5Dyrut5SiCLZa9XdbyI3TjEIAFtOkpZtVObzrEy + 3wQImMbwCBIgIwe35eP4Z02VSBqLyIBE1vGiNv+XuvMirTgfBSZKntsYmcbwCCIg + b8pcUOF3RAEn3Ky+i8xIkB35UCyvB9HLrnXBAbeNXSYiIDBOHEdPTzANJeEaYkQs + DHM9bIr0t1XLZY7buhOssc5HIiDIVqC3K3WpKXE5SzsayoO0znmjPcRJlswzcNNn + AR4KACIglPzBfGEElradbmop8hj8wjnhiC8SQEjpcSKPyiuNbyciIIffDga3d73Q + vvvgiTxtfGbEWjsVtYsZDrBsUtbvF7knIiA1tbjz90bJjXQVCOY8Q9SBJ09haNvU + gD4uolKhxpw1/SIg4XF+XqpJWXICWkRlRyHWQSx1Fc7Dc7HG4tF9k9nb9EUiIP4p + dv5jdzDOGD+/6oOodk2cCq4ukQkrI29bfF/p9UPFIiCtcSyYQk3g8ShNTxRLipW1 + 0iwYHUwKJGUY56miIL32Qyr+AQr7AXJla29yLnNpZ3N0b3JlLmRldiAtIDI2MDU3 + MzY2NzA5NzI3OTQ3NDYKMTg2MjEyMDkKSXdlMzVlUDRaMDJWU0JxTHlJQkUxdkdp + TnYrWHV2TWlyVGdmQlNaS250cz0KVGltZXN0YW1wOiAxNjg1OTgxNDgwMTg3Mzc4 + MzQ5CgrigJQgcmVrb3Iuc2lnc3RvcmUuZGV2IHdOSTlhakJFQWlBTTE2enROTGtN + azRtUzNqWW02TGVKLy9CdFhkV3VXZEpjd1JQMWtLeXYwUUlnSXB1Zm15MWVHNExF + TGh5RjJXbVJmVHdXbldXaGJnMzlxeE5IWWpEY0x6dz0K + -----END SIGNED MESSAGE----- + +Mon Jun 5 12:11:17 EDT 2023 diff --git a/internal/git/gittest/testing.go b/internal/git/gittest/testing.go new file mode 100644 index 00000000..fcf41037 --- /dev/null +++ b/internal/git/gittest/testing.go @@ -0,0 +1,67 @@ +// Copyright 2023 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package gittest + +import ( + "io" + "os" + "testing" + + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/storage/memory" +) + +func ParseCommit(t *testing.T, path string) *object.Commit { + raw, err := os.ReadFile(path) + if err != nil { + t.Fatalf("error reading input: %v", err) + } + + storage := memory.NewStorage() + obj := storage.NewEncodedObject() + obj.SetType(plumbing.CommitObject) + w, err := obj.Writer() + if err != nil { + t.Fatalf("error getting git object writer: %v", err) + } + if _, err := w.Write(raw); err != nil { + t.Fatalf("error writing git commit: %v", err) + } + + c, err := object.DecodeCommit(storage, obj) + if err != nil { + t.Fatalf("error decoding commit: %v", err) + } + return c +} + +func MarshalCommitBody(t *testing.T, commit *object.Commit) []byte { + t.Helper() + storage := memory.NewStorage() + obj := storage.NewEncodedObject() + if err := commit.EncodeWithoutSignature(obj); err != nil { + t.Fatal(err) + } + r, err := obj.Reader() + if err != nil { + t.Fatal(err) + } + body, err := io.ReadAll(r) + if err != nil { + t.Fatal(err) + } + + return body +} diff --git a/pkg/rekor/rekor.go b/pkg/rekor/rekor.go index 311a464f..6d5a39e4 100644 --- a/pkg/rekor/rekor.go +++ b/pkg/rekor/rekor.go @@ -280,7 +280,7 @@ func (c *Client) VerifyInclusion(ctx context.Context, sig []byte, cert *x509.Cer // Get HashedRekord body from the signature. // We are assuming here that the signature has already been authenticated against the // cert, so it is okay to rely the precomputed checksum in the SignerInfo. - message, err := si.GetMessageDigestAttribute() + message, err := si.SignedAttrs.MarshaledForVerification() if err != nil { return nil, err }