Skip to content

Commit

Permalink
Refactor Statement to custom type
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Gillis <gillis.andrew@gmail.com>
  • Loading branch information
gillisandrew committed Nov 1, 2024
1 parent 4f3ea5e commit ed182c3
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 53 deletions.
5 changes: 2 additions & 3 deletions pkg/bundle/signature_content.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package bundle
import (
"encoding/base64"

in_toto "github.com/in-toto/attestation/go/v1"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
"github.com/sigstore/sigstore-go/pkg/verify"
"google.golang.org/protobuf/encoding/protojson"
Expand Down Expand Up @@ -51,12 +50,12 @@ type Envelope struct {
*dsse.Envelope
}

func (e *Envelope) Statement() (*in_toto.Statement, error) {
func (e *Envelope) Statement() (*verify.Statement, error) {
if e.PayloadType != IntotoMediaType {
return nil, ErrUnsupportedMediaType
}

var statement in_toto.Statement
var statement verify.Statement
raw, err := e.DecodeB64Payload()
if err != nil {
return nil, ErrDecodingB64
Expand Down
3 changes: 1 addition & 2 deletions pkg/verify/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"errors"
"time"

in_toto "github.com/in-toto/attestation/go/v1"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
protocommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
"github.com/sigstore/sigstore-go/pkg/root"
Expand Down Expand Up @@ -86,7 +85,7 @@ type MessageSignatureContent interface {

type EnvelopeContent interface {
RawEnvelope() *dsse.Envelope
Statement() (*in_toto.Statement, error)
Statement() (*Statement, error)
}

// BaseSignedEntity is a helper struct that implements all the interfaces
Expand Down
20 changes: 9 additions & 11 deletions pkg/verify/signature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ import (
"fmt"
"testing"

"github.com/in-toto/in-toto-golang/in_toto"
"github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common"
in_toto "github.com/in-toto/attestation/go/v1"
"github.com/sigstore/sigstore-go/pkg/testing/ca"
"github.com/sigstore/sigstore-go/pkg/verify"
"github.com/stretchr/testify/assert"
Expand All @@ -34,7 +33,7 @@ var SkipArtifactAndIdentitiesPolicy = verify.NewPolicy(verify.WithoutArtifactUns
func TestSignatureVerifier(t *testing.T) {
virtualSigstore, err := ca.NewVirtualSigstore()
assert.NoError(t, err)

statement := []byte(`{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"customFoo","subject":[{"name":"subject","digest":{"sha256":"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"}}],"predicate":{}}`)
entity, err := virtualSigstore.Attest("foo@example.com", "issuer", statement)
assert.NoError(t, err)
Expand Down Expand Up @@ -121,17 +120,17 @@ func TestTooManySubjects(t *testing.T) {
virtualSigstore, err := ca.NewVirtualSigstore()
assert.NoError(t, err)

tooManySubjectsStatement := in_toto.Statement{}
tooManySubjectsStatement := verify.Statement{}
for i := 0; i < 1025; i++ {
tooManySubjectsStatement.Subject = append(tooManySubjectsStatement.Subject, in_toto.Subject{
tooManySubjectsStatement.Subject = append(tooManySubjectsStatement.Subject, &in_toto.ResourceDescriptor{
Name: fmt.Sprintf("subject-%d", i),
Digest: map[string]string{
"sha256": "", // actual content of digest does not matter for this test
},
})
}

tooManySubjectsStatementBytes, err := json.Marshal(tooManySubjectsStatement)
tooManySubjectsStatementBytes, err := json.Marshal(&tooManySubjectsStatement)
assert.NoError(t, err)

tooManySubjectsEntity, err := virtualSigstore.Attest("foo@example.com", "issuer", tooManySubjectsStatementBytes)
Expand All @@ -149,19 +148,18 @@ func TestTooManyDigests(t *testing.T) {
virtualSigstore, err := ca.NewVirtualSigstore()
assert.NoError(t, err)

tooManyDigestsStatement := in_toto.Statement{}
tooManyDigestsStatement.Subject = []in_toto.Subject{
tooManyDigestsStatement := verify.Statement{}
tooManyDigestsStatement.Subject = []*in_toto.ResourceDescriptor{
{
Name: fmt.Sprintf("subject"),
Digest: make(common.DigestSet),
Digest: map[string]string{"sha512": ""},
},
}
tooManyDigestsStatement.Subject[0].Digest["sha512"] = "" // verifier requires that at least one known hash algorithm is present in the digest map
for i := 0; i < 32; i++ {
tooManyDigestsStatement.Subject[0].Digest[fmt.Sprintf("digest-%d", i)] = ""
}

tooManySubjectsStatementBytes, err := json.Marshal(tooManyDigestsStatement)
tooManySubjectsStatementBytes, err := json.Marshal(&tooManyDigestsStatement)
assert.NoError(t, err)

tooManySubjectsEntity, err := virtualSigstore.Attest("foo@example.com", "issuer", tooManySubjectsStatementBytes)
Expand Down
46 changes: 9 additions & 37 deletions pkg/verify/signed_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package verify
import (
"crypto/x509"
"encoding/asn1"
"encoding/json"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -218,7 +217,7 @@ func (c *VerifierConfig) Validate() error {

type VerificationResult struct {
MediaType string `json:"mediaType"`
Statement *in_toto.Statement `json:"statement,omitempty"`
Statement *Statement `json:"statement,omitempty"`
Signature *SignatureVerificationResult `json:"signature,omitempty"`
VerifiedTimestamps []TimestampVerificationResult `json:"verifiedTimestamps"`
VerifiedIdentity *CertificateIdentity `json:"verifiedIdentity,omitempty"`
Expand All @@ -241,43 +240,16 @@ func NewVerificationResult() *VerificationResult {
}
}

// verificationResultRawStatement is a helper struct to marshal/unmarshal
// It is used because in_toto.Statement is a protobuf message and we want to
// store it as a raw message so we can use protojson to marshal/unmarshal it
//
// See https://github.com/in-toto/attestation/issues/363
type verificationResultRawStatement struct {
MediaType string `json:"mediaType"`
Statement json.RawMessage `json:"statement,omitempty"`
Signature *SignatureVerificationResult `json:"signature,omitempty"`
VerifiedTimestamps []TimestampVerificationResult `json:"verifiedTimestamps"`
VerifiedIdentity *CertificateIdentity `json:"verifiedIdentity,omitempty"`
type Statement struct {
in_toto.Statement
}

func (b *VerificationResult) MarshalJSON() ([]byte, error) {
statement, err := protojson.Marshal(b.Statement)
if err != nil {
return nil, err
}
return json.Marshal(&verificationResultRawStatement{
MediaType: b.MediaType,
Statement: statement,
Signature: b.Signature,
VerifiedTimestamps: b.VerifiedTimestamps,
VerifiedIdentity: b.VerifiedIdentity,
})
}

func (b *VerificationResult) UnmarshalJSON(data []byte) error {
var aux verificationResultRawStatement
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
b.MediaType = aux.MediaType
b.Signature = aux.Signature
b.VerifiedTimestamps = aux.VerifiedTimestamps
b.VerifiedIdentity = aux.VerifiedIdentity
return protojson.Unmarshal(aux.Statement, b.Statement)
func (s *Statement) MarshalJSON() ([]byte, error) {
return protojson.Marshal(&s.Statement)
}

func (s *Statement) UnmarshalJSON(data []byte) error {
return protojson.Unmarshal(data, s)
}

type PolicyOption func(*PolicyConfig) error
Expand Down
39 changes: 39 additions & 0 deletions pkg/verify/signed_entity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import (
"encoding/hex"
"encoding/json"

in_toto "github.com/in-toto/attestation/go/v1"
"github.com/sigstore/sigstore-go/pkg/testing/data"
"github.com/sigstore/sigstore-go/pkg/verify"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/types/known/structpb"
)

func TestSignedEntityVerifierInitialization(t *testing.T) {
Expand Down Expand Up @@ -422,3 +424,40 @@ func TestSigstoreBundle2Sig(t *testing.T) {
assert.True(t, errors.Is(err, verify.ErrDSSEInvalidSignatureCount))
assert.Nil(t, res)
}

func TestStatementSerializesToValidInTotoStatement(t *testing.T) {
// create instance of verify.Statement with dummy values
statement := verify.Statement{}
statement.Type = "https://in-toto.io/Statement/v0.1"
statement.PredicateType = "https://example.org/predicate"
statement.Subject = []*in_toto.ResourceDescriptor{
{
Name: "artifact-name",
Digest: map[string]string{
"sha256": "artifact-digest",
},
},
}
statement.Predicate = &structpb.Struct{
Fields: map[string]*structpb.Value{},
}

// marshal the statement to JSON
statementJSON, err := json.Marshal(&statement)
assert.NoError(t, err)
want := `
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicateType": "https://example.org/predicate",
"subject": [
{
"name": "artifact-name",
"digest": {
"sha256": "artifact-digest"
}
}
],
"predicate": {}
}`
assert.JSONEq(t, want, string(statementJSON))
}

0 comments on commit ed182c3

Please sign in to comment.