Skip to content

Commit

Permalink
Add method to get artifact hash for an entry (#1777)
Browse files Browse the repository at this point in the history
This can be used to get the entry's artifact hash without requiring
unmarshaling the type.

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
  • Loading branch information
haydentherapper committed Oct 19, 2023
1 parent 2143e33 commit b719942
Show file tree
Hide file tree
Showing 27 changed files with 208 additions and 3 deletions.
7 changes: 7 additions & 0 deletions pkg/types/alpine/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
return []pki.PublicKey{key}, nil
}

func (v V001Entry) ArtifactHash() (string, error) {
if v.AlpineModel.Package == nil || v.AlpineModel.Package.Hash == nil || v.AlpineModel.Package.Hash.Value == nil || v.AlpineModel.Package.Hash.Algorithm == nil {
return "", errors.New("alpine v0.0.1 entry not initialized")
}
return strings.ToLower(fmt.Sprintf("%s:%s", *v.AlpineModel.Package.Hash.Algorithm, *v.AlpineModel.Package.Hash.Value)), nil
}

func (v V001Entry) Insertable() (bool, error) {
if v.AlpineModel.Package == nil {
return false, fmt.Errorf("missing package entry")
Expand Down
9 changes: 9 additions & 0 deletions pkg/types/alpine/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package alpine
import (
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"os"
"reflect"
"testing"
Expand Down Expand Up @@ -177,6 +179,13 @@ func TestCrossFieldValidation(t *testing.T) {
if ok, err := ei.Insertable(); ok || err == nil {
t.Errorf("unexpected success calling Insertable on entry created from canonicalized content")
}
hash, err := ei.ArtifactHash()
expectedHash := sha256.Sum256(dataBytes)
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}
}

verifiers, err := v.Verifiers()
Expand Down
7 changes: 7 additions & 0 deletions pkg/types/cose/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
return []pki.PublicKey{key}, nil
}

func (v V001Entry) ArtifactHash() (string, error) {
if v.CoseObj.Data == nil || v.CoseObj.Data.PayloadHash == nil || v.CoseObj.Data.PayloadHash.Value == nil || v.CoseObj.Data.PayloadHash.Algorithm == nil {
return "", errors.New("cose v0.0.1 entry not initialized")
}
return strings.ToLower(fmt.Sprintf("%s:%s", *v.CoseObj.Data.PayloadHash.Algorithm, *v.CoseObj.Data.PayloadHash.Value)), nil
}

func (v V001Entry) Insertable() (bool, error) {
if len(v.CoseObj.Message) == 0 {
return false, errors.New("missing COSE Sign1 message")
Expand Down
7 changes: 7 additions & 0 deletions pkg/types/cose/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,13 @@ func TestV001Entry_Unmarshal(t *testing.T) {
if ok, err := ei.Insertable(); ok || err == nil {
t.Errorf("entry created from canonicalized entry should not also be insertable")
}
hash, err := ei.ArtifactHash()
expectedHash := sha256.Sum256([]byte("hello"))
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions pkg/types/dsse/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
return keys, nil
}

func (v V001Entry) ArtifactHash() (string, error) {
if v.DSSEObj.PayloadHash == nil || v.DSSEObj.PayloadHash.Algorithm == nil || v.DSSEObj.PayloadHash.Value == nil {
return "", errors.New("dsse v0.0.1 entry not initialized")
}
return strings.ToLower(fmt.Sprintf("%s:%s", *v.DSSEObj.PayloadHash.Algorithm, *v.DSSEObj.PayloadHash.Value)), nil
}

func (v V001Entry) Insertable() (bool, error) {
if v.DSSEObj.ProposedContent == nil {
return false, errors.New("missing proposed content")
Expand Down
8 changes: 8 additions & 0 deletions pkg/types/dsse/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,14 @@ func TestV001Entry_Unmarshal(t *testing.T) {
t.Errorf("index keys from hydrated object do not match those generated from canonicalized (and re-hydrated) object: %v %v", got, canonicalIndexKeys)
}

hash, err := canonicalV001.ArtifactHash()
expectedHash := sha256.Sum256([]byte(validPayload))
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}

return nil
}
if err := uv(); (err != nil) != tt.wantErr {
Expand Down
5 changes: 3 additions & 2 deletions pkg/types/entries.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ type EntryImpl interface {
Canonicalize(ctx context.Context) ([]byte, error) // marshal the canonical entry to be put into the tlog
Unmarshal(e models.ProposedEntry) error // unmarshal the abstract entry into the specific struct for this versioned type
CreateFromArtifactProperties(context.Context, ArtifactProperties) (models.ProposedEntry, error)
Verifiers() ([]pki.PublicKey, error)
Insertable() (bool, error) // denotes whether the entry that was unmarshalled has the writeOnly fields required to validate and insert into the log
Verifiers() ([]pki.PublicKey, error) // list of keys or certificates that can verify an entry's signature
ArtifactHash() (string, error) // hex-encoded artifact hash prefixed with hash name, e.g. sha256:abcdef
Insertable() (bool, error) // denotes whether the entry that was unmarshalled has the writeOnly fields required to validate and insert into the log
}

// EntryWithAttestationImpl specifies the behavior of a versioned type that also stores attestations
Expand Down
4 changes: 4 additions & 0 deletions pkg/types/hashedrekord/hashedrekord_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) {
return nil, nil
}

func (u UnmarshalFailsTester) ArtifactHash() (string, error) {
return "", nil
}

func TestRekordType(t *testing.T) {
// empty to start
if VersionMap.Count() != 0 {
Expand Down
7 changes: 7 additions & 0 deletions pkg/types/hashedrekord/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
return []pki.PublicKey{key}, nil
}

func (v V001Entry) ArtifactHash() (string, error) {
if v.HashedRekordObj.Data == nil || v.HashedRekordObj.Data.Hash == nil || v.HashedRekordObj.Data.Hash.Value == nil || v.HashedRekordObj.Data.Hash.Algorithm == nil {
return "", errors.New("hashedrekord v0.0.1 entry not initialized")
}
return strings.ToLower(fmt.Sprintf("%s:%s", *v.HashedRekordObj.Data.Hash.Algorithm, *v.HashedRekordObj.Data.Hash.Value)), nil
}

func (v V001Entry) Insertable() (bool, error) {
if v.HashedRekordObj.Signature == nil {
return false, errors.New("missing signature property")
Expand Down
13 changes: 13 additions & 0 deletions pkg/types/hashedrekord/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,13 @@ func TestCrossFieldValidation(t *testing.T) {
if !ok || err != nil {
t.Errorf("unexpected failure in testing insertable on valid entry: %v", err)
}

hash, err := v.ArtifactHash()
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:"+dataSHA {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}
}

b, err := v.Canonicalize(context.TODO())
Expand All @@ -313,6 +320,12 @@ func TestCrossFieldValidation(t *testing.T) {
if !ok || err != nil {
t.Errorf("unexpected failure in testing insertable on entry created from canonicalized content: %v", err)
}
hash, err := ei.ArtifactHash()
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:"+dataSHA {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}
}

verifiers, err := v.Verifiers()
Expand Down
7 changes: 7 additions & 0 deletions pkg/types/helm/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
return []pki.PublicKey{key}, nil
}

func (v V001Entry) ArtifactHash() (string, error) {
if v.HelmObj.Chart == nil || v.HelmObj.Chart.Hash == nil || v.HelmObj.Chart.Hash.Algorithm == nil || v.HelmObj.Chart.Hash.Value == nil {
return "", errors.New("helm v0.0.1 entry not initialized")
}
return strings.ToLower(fmt.Sprintf("%s:%s", *v.HelmObj.Chart.Hash.Algorithm, *v.HelmObj.Chart.Hash.Value)), nil
}

func (v V001Entry) Insertable() (bool, error) {
if v.HelmObj.PublicKey == nil {
return false, errors.New("missing public key property")
Expand Down
6 changes: 6 additions & 0 deletions pkg/types/helm/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ func TestCrossFieldValidation(t *testing.T) {
if ok, err := ei.Insertable(); ok || err == nil {
t.Errorf("unexpected success calling Insertable on entry created from canonicalized content")
}
hash, err := ei.ArtifactHash()
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:6dec7ea21e655d5796c1e214cfb75b73428b2abfa2e66c8f7bc64ff4a7b3b29f" {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}
}

verifiers, err := v.Verifiers()
Expand Down
7 changes: 7 additions & 0 deletions pkg/types/intoto/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
return []pki.PublicKey{key}, nil
}

func (v V001Entry) ArtifactHash() (string, error) {
if v.IntotoObj.Content == nil || v.IntotoObj.Content.PayloadHash == nil || v.IntotoObj.Content.PayloadHash.Algorithm == nil || v.IntotoObj.Content.PayloadHash.Value == nil {
return "", errors.New("hashedrekord v0.0.1 entry not initialized")
}
return strings.ToLower(fmt.Sprintf("%s:%s", *v.IntotoObj.Content.PayloadHash.Algorithm, *v.IntotoObj.Content.PayloadHash.Value)), nil
}

func (v V001Entry) Insertable() (bool, error) {
if v.IntotoObj.Content == nil {
return false, errors.New("missing content property")
Expand Down
8 changes: 8 additions & 0 deletions pkg/types/intoto/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,14 @@ func TestV001Entry_Unmarshal(t *testing.T) {
t.Errorf("index keys from hydrated object do not match those generated from canonicalized (and re-hydrated) object: %v %v", got, canonicalIndexKeys)
}

hash, err := canonicalV001.ArtifactHash()
expectedHash := sha256.Sum256([]byte(validPayload))
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}

verifiers, err := v.Verifiers()
if !tt.wantVerifierErr {
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions pkg/types/intoto/v0.0.2/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,13 @@ func (v V002Entry) Verifiers() ([]pki.PublicKey, error) {
return keys, nil
}

func (v V002Entry) ArtifactHash() (string, error) {
if v.IntotoObj.Content == nil || v.IntotoObj.Content.PayloadHash == nil || v.IntotoObj.Content.PayloadHash.Algorithm == nil || v.IntotoObj.Content.PayloadHash.Value == nil {
return "", errors.New("intoto v0.0.2 entry not initialized")
}
return strings.ToLower(fmt.Sprintf("%s:%s", *v.IntotoObj.Content.PayloadHash.Algorithm, *v.IntotoObj.Content.PayloadHash.Value)), nil
}

func (v V002Entry) Insertable() (bool, error) {
if v.IntotoObj.Content == nil {
return false, errors.New("missing content property")
Expand Down
8 changes: 8 additions & 0 deletions pkg/types/intoto/v0.0.2/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,14 @@ func TestV002Entry_Unmarshal(t *testing.T) {
t.Errorf("index keys from hydrated object do not match those generated from canonicalized (and re-hydrated) object: %v %v", got, canonicalIndexKeys)
}

hash, err := canonicalV002.ArtifactHash()
expectedHash := sha256.Sum256([]byte(validPayload))
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}

verifiers, err := v.Verifiers()
if !tt.wantVerifierErr {
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions pkg/types/jar/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
return []pki.PublicKey{key}, nil
}

func (v V001Entry) ArtifactHash() (string, error) {
if v.JARModel.Archive == nil || v.JARModel.Archive.Hash == nil || v.JARModel.Archive.Hash.Value == nil || v.JARModel.Archive.Hash.Algorithm == nil {
return "", errors.New("jar v0.0.1 entry not initialized")
}
return strings.ToLower(fmt.Sprintf("%s:%s", *v.JARModel.Archive.Hash.Algorithm, *v.JARModel.Archive.Hash.Value)), nil
}

func (v V001Entry) Insertable() (bool, error) {
if v.JARModel.Archive == nil {
return false, errors.New("missing archive property")
Expand Down
6 changes: 6 additions & 0 deletions pkg/types/jar/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==
if ok, err := ei.Insertable(); ok || err == nil {
t.Errorf("unexpected err from calling Insertable on entry created from canonicalized content")
}
hash, err := ei.ArtifactHash()
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:4a9d0ab4e10597497ed6c4617c983c35fa9e964e75cdd6f9fae3a0da1929acc6" {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}
}

verifiers, err := v.Verifiers()
Expand Down
7 changes: 7 additions & 0 deletions pkg/types/rekord/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
return []pki.PublicKey{key}, nil
}

func (v V001Entry) ArtifactHash() (string, error) {
if v.RekordObj.Data == nil || v.RekordObj.Data.Hash == nil || v.RekordObj.Data.Hash.Value == nil || v.RekordObj.Data.Hash.Algorithm == nil {
return "", errors.New("rekord v0.0.1 entry not initialized")
}
return strings.ToLower(fmt.Sprintf("%s:%s", *v.RekordObj.Data.Hash.Algorithm, *v.RekordObj.Data.Hash.Value)), nil
}

func (v V001Entry) Insertable() (bool, error) {
if v.RekordObj.Signature == nil {
return false, errors.New("missing signature property")
Expand Down
9 changes: 9 additions & 0 deletions pkg/types/rekord/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package rekord
import (
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"os"
"reflect"
"testing"
Expand Down Expand Up @@ -256,6 +258,13 @@ func TestCrossFieldValidation(t *testing.T) {
if ok, err := ei.Insertable(); ok || err == nil {
t.Errorf("unexpected success calling Insertable on entry created from canonicalized content")
}
hash, err := ei.ArtifactHash()
expectedHash := sha256.Sum256(dataBytes)
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}
}

verifiers, err := v.Verifiers()
Expand Down
13 changes: 13 additions & 0 deletions pkg/types/rfc3161/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/sigstore/rekor/pkg/pki"
"github.com/sigstore/rekor/pkg/types/rfc3161"
Expand Down Expand Up @@ -211,6 +212,18 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
return nil, errors.New("Verifiers() does not support rfc3161 entry type")
}

func (v V001Entry) ArtifactHash() (string, error) {
if v.Rfc3161Obj.Tsr == nil || v.Rfc3161Obj.Tsr.Content == nil {
return "", errors.New("rfc3161 v0.0.1 entry not initialized")
}
tsrDecoded, err := base64.StdEncoding.DecodeString(v.Rfc3161Obj.Tsr.Content.String())
if err != nil {
return "", err
}
h := sha256.Sum256(tsrDecoded)
return strings.ToLower(fmt.Sprintf("sha256:%s", hex.EncodeToString(h[:]))), nil
}

func (v V001Entry) Insertable() (bool, error) {
if v.Rfc3161Obj.Tsr == nil {
return false, errors.New("missing tsr property")
Expand Down
6 changes: 6 additions & 0 deletions pkg/types/rfc3161/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ func TestCrossFieldValidation(t *testing.T) {
if ok, err := ei.Insertable(); !ok || err != nil {
t.Errorf("unexpected error calling insertable on entry created from canonicalized content")
}
hash, err := ei.ArtifactHash()
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:6dbda791c778454d0baa96e1dec5fa2c50867fd22d119ebe75c60c513b254c91" {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/types/rpm/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
return []pki.PublicKey{key}, nil
}

func (v V001Entry) ArtifactHash() (string, error) {
if v.RPMModel.Package == nil || v.RPMModel.Package.Hash == nil || v.RPMModel.Package.Hash.Value == nil || v.RPMModel.Package.Hash.Algorithm == nil {
return "", errors.New("rpm v0.0.1 entry not initialized")
}
return strings.ToLower(fmt.Sprintf("%s:%s", *v.RPMModel.Package.Hash.Algorithm, *v.RPMModel.Package.Hash.Value)), nil
}

func (v V001Entry) Insertable() (bool, error) {
if v.RPMModel.PublicKey == nil {
return false, errors.New("missing publicKey property")
Expand Down
6 changes: 6 additions & 0 deletions pkg/types/rpm/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ func TestCrossFieldValidation(t *testing.T) {
if ok, err := ei.Insertable(); ok || err == nil {
t.Errorf("unexpected success calling Insertable on entry created from canonicalized content")
}
hash, err := ei.ArtifactHash()
if err != nil {
t.Errorf("unexpected failure with ArtifactHash: %v", err)
} else if hash != "sha256:c8b0bc59708d74f53aab0089ac587d5c348d6ead143dab9f6d9c4b48c973bfd8" {
t.Errorf("unexpected match with ArtifactHash: %s", hash)
}
}

verifiers, err := v.Verifiers()
Expand Down
4 changes: 4 additions & 0 deletions pkg/types/test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func (u BaseUnmarshalTester) NewEntry() EntryImpl {
return &BaseUnmarshalTester{}
}

func (u BaseUnmarshalTester) ArtifactHash() (string, error) {
return "", nil
}

func (u BaseUnmarshalTester) Verifiers() ([]pki.PublicKey, error) {
return nil, nil
}
Expand Down
Loading

0 comments on commit b719942

Please sign in to comment.