Skip to content

Commit

Permalink
also hydrate payloadHash upon unmarshalling
Browse files Browse the repository at this point in the history
Signed-off-by: Bob Callaway <bcallaway@google.com>
  • Loading branch information
bobcallaway committed Aug 3, 2022
1 parent 0ea3c0f commit 4a93e33
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 56 deletions.
39 changes: 24 additions & 15 deletions pkg/types/intoto/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,11 @@ func (v V001Entry) IndexKeys() ([]string, error) {
}

// add digest base64-decoded payload inside of DSSE envelope
payloadBytes, err := base64.StdEncoding.DecodeString(v.env.Payload)
if err == nil {
payloadHash := sha256.Sum256(payloadBytes)
result = append(result, fmt.Sprintf("sha256:%s", strings.ToLower(hex.EncodeToString(payloadHash[:]))))
if v.IntotoObj.Content != nil && v.IntotoObj.Content.PayloadHash != nil {
payloadHash := strings.ToLower(fmt.Sprintf("%s:%s", swag.StringValue(v.IntotoObj.Content.PayloadHash.Algorithm), swag.StringValue(v.IntotoObj.Content.PayloadHash.Value)))
result = append(result, payloadHash)
} else {
log.Logger.Errorf("error decoding intoto payload to compute digest: %w", err)
log.Logger.Error("could not find payload digest to include in index keys")
}

switch v.env.PayloadType {
Expand Down Expand Up @@ -201,14 +200,12 @@ func (v *V001Entry) Canonicalize(ctx context.Context) ([]byte, error) {
Algorithm: v.IntotoObj.Content.Hash.Algorithm,
Value: v.IntotoObj.Content.Hash.Value,
},
PayloadHash: &models.IntotoV001SchemaContentPayloadHash{
Algorithm: v.IntotoObj.Content.PayloadHash.Algorithm,
Value: v.IntotoObj.Content.PayloadHash.Value,
},
},
}
if attKey, attValue := v.AttestationKeyValue(); attValue != nil {
canonicalEntry.Content.PayloadHash = &models.IntotoV001SchemaContentPayloadHash{
Algorithm: swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256),
Value: swag.String(strings.Replace(attKey, fmt.Sprintf("%s:", models.IntotoV001SchemaContentHashAlgorithmSha256), "", 1)),
}
}

itObj := models.Intoto{}
itObj.APIVersion = swag.String(APIVERSION)
Expand All @@ -235,13 +232,27 @@ func (v *V001Entry) validate() error {
if err := dsseVerifier.VerifySignature(strings.NewReader(v.IntotoObj.Content.Envelope), nil); err != nil {
return err
}
if err := json.Unmarshal([]byte(v.IntotoObj.Content.Envelope), &v.env); err != nil {
return err
}

attBytes, err := base64.StdEncoding.DecodeString(v.env.Payload)
if err != nil {
return err
}
// validation logic complete without errors, hydrate local object
attHash := sha256.Sum256(attBytes)
v.IntotoObj.Content.PayloadHash = &models.IntotoV001SchemaContentPayloadHash{
Algorithm: swag.String(models.IntotoV001SchemaContentPayloadHashAlgorithmSha256),
Value: swag.String(hex.EncodeToString(attHash[:])),
}

h := sha256.Sum256([]byte(v.IntotoObj.Content.Envelope))
v.IntotoObj.Content.Hash = &models.IntotoV001SchemaContentHash{
Algorithm: swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256),
Value: swag.String(hex.EncodeToString(h[:])),
}
return json.Unmarshal([]byte(v.IntotoObj.Content.Envelope), &v.env)
return nil
}

// AttestationKey returns the digest of the attestation that was uploaded, to be used to lookup the attestation from storage
Expand All @@ -260,9 +271,7 @@ func (v *V001Entry) AttestationKeyValue() (string, []byte) {
return "", nil
}
attBytes, _ := base64.StdEncoding.DecodeString(v.env.Payload)
attHash := sha256.Sum256(attBytes)
attKey := fmt.Sprintf("%s:%s", models.IntotoV001SchemaContentHashAlgorithmSha256, hex.EncodeToString(attHash[:]))
return attKey, attBytes
return v.AttestationKey(), attBytes
}

func (v V001Entry) CreateFromArtifactProperties(_ context.Context, props types.ArtifactProperties) (models.ProposedEntry, error) {
Expand Down
53 changes: 12 additions & 41 deletions pkg/types/intoto/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ func TestV001Entry_Unmarshal(t *testing.T) {
if v.IntotoObj.Content.Hash == nil || v.IntotoObj.Content.Hash.Algorithm != tt.it.Content.Hash.Algorithm || v.IntotoObj.Content.Hash.Value != tt.it.Content.Hash.Value {
return errors.New("missing envelope hash in validated object")
}

keysWanted := tt.additionalIndexKeys
if tt.it.PublicKey != nil {
h := sha256.Sum256(*tt.it.PublicKey)
Expand All @@ -256,7 +257,8 @@ func TestV001Entry_Unmarshal(t *testing.T) {
keysWanted = append(keysWanted, "sha256:"+payloadHash)
hashkey := strings.ToLower(fmt.Sprintf("%s:%s", *tt.it.Content.Hash.Algorithm, *tt.it.Content.Hash.Value))
keysWanted = append(keysWanted, hashkey)
if got, _ := v.IndexKeys(); !cmp.Equal(got, keysWanted, cmpopts.SortSlices(func(x, y string) bool { return x < y })) {
got, _ := v.IndexKeys()
if !cmp.Equal(got, keysWanted, cmpopts.SortSlices(func(x, y string) bool { return x < y })) {
t.Errorf("V001Entry.IndexKeys() = %v, want %v", got, keysWanted)
}
canonicalBytes, err := v.Canonicalize(context.Background())
Expand All @@ -280,6 +282,10 @@ func TestV001Entry_Unmarshal(t *testing.T) {
if canonicalV001.AttestationKey() != "" && *canonicalV001.IntotoObj.Content.PayloadHash.Value != payloadHash {
t.Errorf("payload hashes do not match post canonicalization: %v %v", canonicalV001.IntotoObj.Content.PayloadHash.Value, payloadHash)
}
canonicalIndexKeys, _ := canonicalV001.IndexKeys()
if !cmp.Equal(got, canonicalIndexKeys, cmpopts.SortSlices(func(x, y string) bool { return x < y })) {
t.Errorf("index keys from hydrated object do not match those generated from canonicalized (and re-hydrated) object: %v %v", got, canonicalIndexKeys)
}

return nil
}
Expand Down Expand Up @@ -347,13 +353,18 @@ func TestV001Entry_IndexKeys(t *testing.T) {
t.Fatal(err)
}
payload := base64.StdEncoding.EncodeToString(b)
payloadHash := sha256.Sum256(b)
v := V001Entry{
IntotoObj: models.IntotoV001Schema{
Content: &models.IntotoV001SchemaContent{
Hash: &models.IntotoV001SchemaContentHash{
Algorithm: swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256),
Value: swag.String(dataSHA),
},
PayloadHash: &models.IntotoV001SchemaContentPayloadHash{
Algorithm: swag.String(models.IntotoV001SchemaContentPayloadHashAlgorithmSha256),
Value: swag.String(hex.EncodeToString(payloadHash[:])),
},
},
},
env: dsse.Envelope{
Expand All @@ -374,43 +385,3 @@ func TestV001Entry_IndexKeys(t *testing.T) {
})
}
}

func TestIndexKeysNoContentHash(t *testing.T) {
statement := in_toto.Statement{
Predicate: "hello",
StatementHeader: in_toto.StatementHeader{
Subject: []in_toto.Subject{
{
Name: "myimage",
Digest: slsa.DigestSet{
"sha256": "mysha256digest",
},
},
},
},
}
b, err := json.Marshal(statement)
if err != nil {
t.Fatal(err)
}
payload := base64.StdEncoding.EncodeToString(b)
v := V001Entry{
env: dsse.Envelope{
Payload: payload,
PayloadType: in_toto.PayloadType,
},
}
sha := sha256.Sum256(b)
// Always start with the hash
want := []string{"sha256:" + hex.EncodeToString(sha[:])}
want = append(want, "sha256:mysha256digest")
got, err := v.IndexKeys()
if err != nil {
t.Fatal(err)
}
sort.Strings(got)
sort.Strings(want)
if !cmp.Equal(got, want) {
t.Errorf("V001Entry.IndexKeys() = %v, want %v", got, want)
}
}

0 comments on commit 4a93e33

Please sign in to comment.