From 7443c6774a6a0b43ebf07c2f152c73d5ad40fd04 Mon Sep 17 00:00:00 2001 From: Frederick Kautz Date: Thu, 15 Dec 2022 23:28:48 -0800 Subject: [PATCH 1/3] feat: add gitbom support Signed-off-by: Frederick Kautz --- attestation/aws-iid/aws-iid_test.go | 2 +- attestation/file/file.go | 26 ++++++++++++ attestation/git/git.go | 5 ++- attestation/material/material.go | 3 +- attestation/oci/oci.go | 6 +-- attestation/oci/oci_test.go | 10 ++--- attestation/product/product.go | 7 ++-- attestation/scorecard/scorecard.go | 2 +- cryptoutil/digestset.go | 61 +++++++++++++++++++++++------ go.mod | 1 + go.sum | 2 + intoto/statement.go | 1 - policy/policy_test.go | 8 ++-- 13 files changed, 101 insertions(+), 33 deletions(-) diff --git a/attestation/aws-iid/aws-iid_test.go b/attestation/aws-iid/aws-iid_test.go index 012fe8ca..1c68afed 100644 --- a/attestation/aws-iid/aws-iid_test.go +++ b/attestation/aws-iid/aws-iid_test.go @@ -169,7 +169,7 @@ func TestAttestor_Subjects(t *testing.T) { imageid := sha256.Sum256([]byte("ami-5fb8c835")) digest := res["imageid:ami-5fb8c835"] - h := digest[crypto.SHA256] + h := digest[cryptoutil.DigestValue{Hash: crypto.SHA256}] h2 := hex.EncodeToString(imageid[:]) if h != h2 { t.Errorf("Expected %s, got %s", h, h2) diff --git a/attestation/file/file.go b/attestation/file/file.go index 4156aa9f..4b648c7f 100644 --- a/attestation/file/file.go +++ b/attestation/file/file.go @@ -20,6 +20,7 @@ import ( "os" "path/filepath" + "github.com/edwarnicke/gitoid" "github.com/testifysec/go-witness/cryptoutil" "github.com/testifysec/go-witness/log" ) @@ -79,6 +80,31 @@ func RecordArtifacts(basePath string, baseArtifacts map[string]cryptoutil.Digest return err } + fileReader, err := os.Open(path) + if err != nil { + return err + } + + goidSha1, err := gitoid.New(fileReader) + if err != nil { + return err + } + + goidSha256, err := gitoid.New(fileReader, gitoid.WithSha256()) + if err != nil { + return err + } + + artifact[cryptoutil.DigestValue{ + Hash: crypto.SHA1, + GitOID: true, + }] = goidSha1.URI() + + artifact[cryptoutil.DigestValue{ + Hash: crypto.SHA256, + GitOID: true, + }] = goidSha256.URI() + if shouldRecord(relPath, artifact, baseArtifacts) { artifacts[relPath] = artifact } diff --git a/attestation/git/git.go b/attestation/git/git.go index fdda8abb..de5b7636 100644 --- a/attestation/git/git.go +++ b/attestation/git/git.go @@ -116,7 +116,10 @@ func (a *Attestor) Subjects() map[string]cryptoutil.DigestSet { subjectName := fmt.Sprintf("commithash:%v", a.CommitHash) return map[string]cryptoutil.DigestSet{ subjectName: { - crypto.SHA1: a.CommitHash, + { + crypto.SHA1, + true, + }: a.CommitHash, }, } } diff --git a/attestation/material/material.go b/attestation/material/material.go index 869eeb85..f8eb2ac7 100644 --- a/attestation/material/material.go +++ b/attestation/material/material.go @@ -16,7 +16,7 @@ package material import ( "encoding/json" - + "github.com/edwarnicke/gitoid" "github.com/testifysec/go-witness/attestation" "github.com/testifysec/go-witness/attestation/file" "github.com/testifysec/go-witness/cryptoutil" @@ -45,6 +45,7 @@ type Option func(*Attestor) type Attestor struct { materials map[string]cryptoutil.DigestSet + gitoids map[string][]*gitoid.GitOID } func (a Attestor) Name() string { diff --git a/attestation/oci/oci.go b/attestation/oci/oci.go index 135c3fed..288f24ad 100644 --- a/attestation/oci/oci.go +++ b/attestation/oci/oci.go @@ -228,8 +228,8 @@ func (a *Attestor) parseMaifest(ctx *attestation.AttestationContext) error { func (a *Attestor) Subjects() map[string]cryptoutil.DigestSet { subj := make(map[string]cryptoutil.DigestSet) - subj[fmt.Sprintf("tardigest:%s", a.TarDigest[crypto.SHA256])] = a.TarDigest - subj[fmt.Sprintf("imageid:%s", a.ImageID[crypto.SHA256])] = a.ImageID + subj[fmt.Sprintf("tardigest:%s", a.TarDigest[cryptoutil.DigestValue{Hash: crypto.SHA256}])] = a.TarDigest + subj[fmt.Sprintf("imageid:%s", a.ImageID[cryptoutil.DigestValue{Hash: crypto.SHA256}])] = a.ImageID //image tags for _, tag := range a.ImageTags { hash, err := cryptoutil.CalculateDigestSetFromBytes([]byte(tag), a.hashes) @@ -242,7 +242,7 @@ func (a *Attestor) Subjects() map[string]cryptoutil.DigestSet { //diff ids for layer := range a.LayerDiffIDs { - subj[fmt.Sprintf("layerdiffid%02d:%s", layer, a.LayerDiffIDs[layer][crypto.SHA256])] = a.LayerDiffIDs[layer] + subj[fmt.Sprintf("layerdiffid%02d:%s", layer, a.LayerDiffIDs[layer][cryptoutil.DigestValue{Hash: crypto.SHA256}])] = a.LayerDiffIDs[layer] } return subj } diff --git a/attestation/oci/oci_test.go b/attestation/oci/oci_test.go index cb3e7194..70591093 100644 --- a/attestation/oci/oci_test.go +++ b/attestation/oci/oci_test.go @@ -117,8 +117,8 @@ func TestAttestor_Attest(t *testing.T) { err = ctx.RunAttestors() - require.Equal(t, imageID, a.ImageID[crypto.SHA256]) - require.Equal(t, diffID, a.LayerDiffIDs[0][crypto.SHA256]) + require.Equal(t, imageID, a.ImageID[cryptoutil.DigestValue{Hash: crypto.SHA256}]) + require.Equal(t, diffID, a.LayerDiffIDs[0][cryptoutil.DigestValue{Hash: crypto.SHA256}]) require.NoError(t, err) } @@ -157,9 +157,9 @@ func TestAttestor_Subjects(t *testing.T) { subj := a.Subjects() - require.Equal(t, imageID, subj[fmt.Sprintf("imageid:%s", imageID)][crypto.SHA256]) - require.Equal(t, diffID, subj[fmt.Sprintf("layerdiffid00:%s", diffID)][crypto.SHA256]) - require.Equal(t, tarDigest[crypto.SHA256], subj["tardigest:a996818fbcd6d8ae9214fb1f8b3c0cacee64fc8c937b749db0782c482c0575ac"][crypto.SHA256]) + require.Equal(t, imageID, subj[fmt.Sprintf("imageid:%s", imageID)][cryptoutil.DigestValue{Hash: crypto.SHA256}]) + require.Equal(t, diffID, subj[fmt.Sprintf("layerdiffid00:%s", diffID)][cryptoutil.DigestValue{Hash: crypto.SHA256}]) + require.Equal(t, tarDigest[cryptoutil.DigestValue{Hash: crypto.SHA256}], subj["tardigest:a996818fbcd6d8ae9214fb1f8b3c0cacee64fc8c937b749db0782c482c0575ac"][cryptoutil.DigestValue{Hash: crypto.SHA256}]) //require.Equal(t, tarDigest[crypto.SHA256], subj[fmt.Sprintf("tardigest:SHA256:%s", tarDigest)][crypto.SHA256]) diff --git a/attestation/product/product.go b/attestation/product/product.go index 7a0b88f4..d8dedc28 100644 --- a/attestation/product/product.go +++ b/attestation/product/product.go @@ -17,12 +17,11 @@ package product import ( "encoding/json" "fmt" - "net/http" - "os" - "github.com/testifysec/go-witness/attestation" "github.com/testifysec/go-witness/attestation/file" "github.com/testifysec/go-witness/cryptoutil" + "net/http" + "os" ) const ( @@ -63,12 +62,12 @@ func fromDigestMap(digestMap map[string]cryptoutil.DigestSet) map[string]attesta f.Close() } - defer f.Close() products[fileName] = attestation.Product{ MimeType: mimeType, Digest: digestSet, } } + return products } diff --git a/attestation/scorecard/scorecard.go b/attestation/scorecard/scorecard.go index 39b866f2..5a826872 100644 --- a/attestation/scorecard/scorecard.go +++ b/attestation/scorecard/scorecard.go @@ -136,7 +136,7 @@ func (a *Attestor) Subjects() map[string]cryptoutil.DigestSet { subj := make(map[string]cryptoutil.DigestSet) subj[commitSubj] = cryptoutil.DigestSet{ - crypto.SHA1: a.Scorecard.Repo.Commit, + cryptoutil.DigestValue{Hash: crypto.SHA1}: a.Scorecard.Repo.Commit, } ds, err := cryptoutil.CalculateDigestSetFromBytes([]byte(nameSubj), a.hashes) diff --git a/cryptoutil/digestset.go b/cryptoutil/digestset.go index dc67f0b8..d97ef70a 100644 --- a/cryptoutil/digestset.go +++ b/cryptoutil/digestset.go @@ -25,14 +25,42 @@ import ( ) var ( - hashNames = map[crypto.Hash]string{ - crypto.SHA256: "sha256", - crypto.SHA1: "sha1", - } - - hashesByName = map[string]crypto.Hash{ - "sha256": crypto.SHA256, - "sha1": crypto.SHA1, + hashNames = map[DigestValue]string{ + { + Hash: crypto.SHA256, + GitOID: false, + }: "sha256", + { + Hash: crypto.SHA1, + GitOID: false, + }: "sha1", + { + Hash: crypto.SHA256, + GitOID: true, + }: "gitoid:sha256", + { + Hash: crypto.SHA1, + GitOID: true, + }: "gitoid:sha1", + } + + hashesByName = map[string]DigestValue{ + "sha256": { + crypto.SHA256, + false, + }, + "sha1": { + crypto.SHA1, + false, + }, + "gitoid:sha256": { + crypto.SHA256, + true, + }, + "gitoid:sha1": { + crypto.SHA1, + true, + }, } ) @@ -42,10 +70,15 @@ func (e ErrUnsupportedHash) Error() string { return fmt.Sprintf("unsupported hash function: %v", string(e)) } -type DigestSet map[crypto.Hash]string +type DigestValue struct { + crypto.Hash + GitOID bool +} + +type DigestSet map[DigestValue]string func HashToString(h crypto.Hash) (string, error) { - if name, ok := hashNames[h]; ok { + if name, ok := hashNames[DigestValue{Hash: h}]; ok { return name, nil } @@ -54,7 +87,7 @@ func HashToString(h crypto.Hash) (string, error) { func HashFromString(name string) (crypto.Hash, error) { if hash, ok := hashesByName[name]; ok { - return hash, nil + return hash.Hash, nil } return crypto.Hash(0), ErrUnsupportedHash(name) @@ -125,7 +158,11 @@ func CalculateDigestSet(r io.Reader, hashes []crypto.Hash) (DigestSet, error) { } for hash, hashfunc := range hashfuncs { - digestSet[hash] = string(HexEncode(hashfunc.Sum(nil))) + digestValue := DigestValue{ + Hash: hash, + GitOID: false, + } + digestSet[digestValue] = string(HexEncode(hashfunc.Sum(nil))) } return digestSet, nil } diff --git a/go.mod b/go.mod index 2c7af591..f50161ca 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/digitorus/pkcs7 v0.0.0-20220704143225-a9c8106cbfc6 github.com/digitorus/timestamp v0.0.0-20220704143351-8225fba02d52 + github.com/edwarnicke/gitoid v0.0.0-20220710194850-1be5bfda1f9d github.com/go-git/go-git/v5 v5.4.2 github.com/open-policy-agent/opa v0.43.1 github.com/owenrumney/go-sarif v1.1.1 diff --git a/go.sum b/go.sum index 6bfb569b..1a9d9744 100644 --- a/go.sum +++ b/go.sum @@ -505,6 +505,8 @@ github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdf github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/edwarnicke/gitoid v0.0.0-20220710194850-1be5bfda1f9d h1:4l+Uq5zFWSagXgGFaKRRVWJrnlzeathyagWgYUltCgY= +github.com/edwarnicke/gitoid v0.0.0-20220710194850-1be5bfda1f9d/go.mod h1:WxWwA3EYuCQjlR5EBUX3uaTS8bh9BOa7BcqVREHQ0uQ= github.com/ekzhu/minhash-lsh v0.0.0-20171225071031-5c06ee8586a1 h1:/7G7q8SDJdrah5jDYqZI8pGFjSqiCzfSEO+NgqKCYX0= github.com/ekzhu/minhash-lsh v0.0.0-20171225071031-5c06ee8586a1/go.mod h1:yEtCVi+QamvzjEH4U/m6ZGkALIkF2xfQnFp0BcKmIOk= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= diff --git a/intoto/statement.go b/intoto/statement.go index a75b9d9d..ee84ff63 100644 --- a/intoto/statement.go +++ b/intoto/statement.go @@ -16,7 +16,6 @@ package intoto import ( "encoding/json" - "github.com/testifysec/go-witness/cryptoutil" ) diff --git a/policy/policy_test.go b/policy/policy_test.go index eb3f2747..fdd75ebf 100644 --- a/policy/policy_test.go +++ b/policy/policy_test.go @@ -130,7 +130,7 @@ deny[msg] { step1Collection := attestation.NewCollection("step1", []attestation.Attestor{commandRun}) step1CollectionJson, err := json.Marshal(&step1Collection) require.NoError(t, err) - intotoStatement, err := intoto.NewStatement(attestation.CollectionType, step1CollectionJson, map[string]cryptoutil.DigestSet{"dummy": {crypto.SHA256: "dummy"}}) + intotoStatement, err := intoto.NewStatement(attestation.CollectionType, step1CollectionJson, map[string]cryptoutil.DigestSet{"dummy": {cryptoutil.DigestValue{Hash: crypto.SHA256}: "dummy"}}) require.NoError(t, err) _, err = policy.Verify( @@ -220,8 +220,8 @@ func TestArtifacts(t *testing.T) { dummySha := "a1073968266a4ed65472a80ebcfd31f1955cfdf8f23d439b1df84d78ce05f7a9" path := "testfile" - mats := map[string]cryptoutil.DigestSet{path: {crypto.SHA256: dummySha}} - prods := map[string]attestation.Product{path: {Digest: cryptoutil.DigestSet{crypto.SHA256: dummySha}, MimeType: "application/text"}} + mats := map[string]cryptoutil.DigestSet{path: {cryptoutil.DigestValue{Hash: crypto.SHA256}: dummySha}} + prods := map[string]attestation.Product{path: {Digest: cryptoutil.DigestSet{cryptoutil.DigestValue{Hash: crypto.SHA256}: dummySha}, MimeType: "application/text"}} step1Collection := attestation.NewCollection("step1", []attestation.Attestor{DummyProducer{prods}}) step2Collection := attestation.NewCollection("step2", []attestation.Attestor{DummyMaterialer{mats}}) step1CollectionJson, err := json.Marshal(step1Collection) @@ -256,7 +256,7 @@ func TestArtifacts(t *testing.T) { ) assert.NoError(t, err) - mats[path][crypto.SHA256] = "badhash" + mats[path][cryptoutil.DigestValue{Hash: crypto.SHA256}] = "badhash" step2Collection = attestation.NewCollection("step2", []attestation.Attestor{DummyMaterialer{mats}}) step2CollectionJson, err = json.Marshal(step2Collection) require.NoError(t, err) From 9aa4d98c6b666565db1e0f937d581048ecdcb140 Mon Sep 17 00:00:00 2001 From: Frederick Kautz Date: Fri, 16 Dec 2022 21:07:22 -0800 Subject: [PATCH 2/3] chore: fix go vet Signed-off-by: Frederick Kautz --- attestation/git/git.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/attestation/git/git.go b/attestation/git/git.go index de5b7636..e74a6654 100644 --- a/attestation/git/git.go +++ b/attestation/git/git.go @@ -117,8 +117,8 @@ func (a *Attestor) Subjects() map[string]cryptoutil.DigestSet { return map[string]cryptoutil.DigestSet{ subjectName: { { - crypto.SHA1, - true, + Hash: crypto.SHA1, + GitOID: true, }: a.CommitHash, }, } From ef91f08911c1b3d8fb53f86cc502445d6274b22e Mon Sep 17 00:00:00 2001 From: Frederick Kautz Date: Fri, 16 Dec 2022 21:30:51 -0800 Subject: [PATCH 3/3] chore: fix up linter and format Signed-off-by: Frederick Kautz --- attestation/git/git.go | 2 +- attestation/material/material.go | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/attestation/git/git.go b/attestation/git/git.go index e74a6654..a64b48ff 100644 --- a/attestation/git/git.go +++ b/attestation/git/git.go @@ -117,7 +117,7 @@ func (a *Attestor) Subjects() map[string]cryptoutil.DigestSet { return map[string]cryptoutil.DigestSet{ subjectName: { { - Hash: crypto.SHA1, + Hash: crypto.SHA1, GitOID: true, }: a.CommitHash, }, diff --git a/attestation/material/material.go b/attestation/material/material.go index f8eb2ac7..58955143 100644 --- a/attestation/material/material.go +++ b/attestation/material/material.go @@ -16,7 +16,6 @@ package material import ( "encoding/json" - "github.com/edwarnicke/gitoid" "github.com/testifysec/go-witness/attestation" "github.com/testifysec/go-witness/attestation/file" "github.com/testifysec/go-witness/cryptoutil" @@ -45,7 +44,6 @@ type Option func(*Attestor) type Attestor struct { materials map[string]cryptoutil.DigestSet - gitoids map[string][]*gitoid.GitOID } func (a Attestor) Name() string {