Skip to content

Commit

Permalink
Add fuzz tests for bundle, tlog and verify packages (#272)
Browse files Browse the repository at this point in the history
Signed-off-by: Adam Korczynski <adam@adalogics.com>
  • Loading branch information
AdamKorcz committed Aug 19, 2024
1 parent 1bcaee1 commit f9235ff
Show file tree
Hide file tree
Showing 3 changed files with 364 additions and 0 deletions.
59 changes: 59 additions & 0 deletions pkg/bundle/fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2024 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 bundle

import (
"testing"
)

/*
FuzzBundle creates a randomized bundle and
invokes three of its methods
*/
//nolint:errcheck
func FuzzBundle(f *testing.F) {
f.Fuzz(func(t *testing.T, bundleData []byte,
call1,
call2,
call3 int,
expectVersion string) {
var bundle Bundle
err := bundle.UnmarshalJSON(bundleData)
if err != nil {
t.Skip()
}
calls := []int{call1, call2, call3}
for _, call := range calls {
switch call % 8 {
case 0:
bundle.VerificationContent()
case 1:
bundle.HasInclusionPromise()
case 2:
bundle.HasInclusionProof()
case 3:
bundle.TlogEntries()
case 4:
bundle.SignatureContent()
case 5:
bundle.Envelope()
case 6:
bundle.Timestamps()
case 7:
bundle.MinVersion(expectVersion)
}
}
})
}
69 changes: 69 additions & 0 deletions pkg/tlog/fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2024 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 tlog

import (
"testing"

commonV1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
v1 "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1"
)

/*
FuzzParseEntry creates a randomized
TransparencyLogEntry and parses it
*/
func FuzzParseEntry(f *testing.F) {
f.Fuzz(func(_ *testing.T, proofTreeSize,
proofLogIndex,
tlEntryIntegratedTime,
tlEntryIndex int64,
proofRootHash,
proofHash1,
proofHash2,
proofHash3,
promiseSETimestamp,
tlEntryCanonicalizedBody,
logIdKeyId []byte,
kindVersion,
kindKind,
checkpointEnvelope string) {
//nolint:errcheck
ParseEntry(&v1.TransparencyLogEntry{
LogIndex: tlEntryIndex,
LogId: &commonV1.LogId{
KeyId: logIdKeyId,
},
KindVersion: &v1.KindVersion{
Kind: kindKind,
Version: kindVersion,
},
IntegratedTime: tlEntryIntegratedTime,
InclusionPromise: &v1.InclusionPromise{
SignedEntryTimestamp: promiseSETimestamp,
},
InclusionProof: &v1.InclusionProof{
LogIndex: proofLogIndex,
RootHash: proofRootHash,
TreeSize: proofTreeSize,
Hashes: [][]byte{proofHash1, proofHash2, proofHash3},
Checkpoint: &v1.Checkpoint{
Envelope: checkpointEnvelope,
},
},
CanonicalizedBody: tlEntryCanonicalizedBody,
})
})
}
236 changes: 236 additions & 0 deletions pkg/verify/fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
// Copyright 2024 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 verify_test

import (
"bytes"
"testing"

protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1"
"github.com/sigstore/sigstore-go/pkg/bundle"
"github.com/sigstore/sigstore-go/pkg/root"
"github.com/sigstore/sigstore-go/pkg/testing/ca"
"github.com/sigstore/sigstore-go/pkg/verify"
"google.golang.org/protobuf/encoding/protojson"
)

var FuzzSkipArtifactAndIdentitiesPolicy = verify.NewPolicy(verify.WithoutArtifactUnsafe(), verify.WithoutIdentitiesUnsafe())

/*
Tests VerifyTimestampAuthority with an entity that contains
a randomized email and statement
*/
func FuzzVerifyTimestampAuthorityWithoutThreshold(f *testing.F) {
f.Fuzz(func(t *testing.T, email string, statement []byte) {
virtualSigstore, err := ca.NewVirtualSigstore()
if err != nil {
t.Fatal(err)
}
entity, err := virtualSigstore.Attest(email,
"issuer",
statement)
if err != nil {
t.Skip()
}
//nolint:errcheck
verify.VerifyTimestampAuthority(entity, virtualSigstore)
})
}

/*
Tests VerifyTimestampAuthorityWithThreshold with an entity
that contains a randomized email, statement and a randomized
threshold
*/
func FuzzVerifyTimestampAuthorityWithThreshold(f *testing.F) {
f.Fuzz(func(t *testing.T, email string,
statement []byte,
threshold int) {
virtualSigstore, err := ca.NewVirtualSigstore()
if err != nil {
t.Fatal(err)
}
entity, err := virtualSigstore.Attest(email,
"issuer",
statement)
if err != nil {
t.Skip()
}
//nolint:errcheck
verify.VerifyTimestampAuthorityWithThreshold(entity,
virtualSigstore,
threshold)
})
}

/*
Tests VerifyArtifactTransparencyLog with an entity
that contains a randomized email and statement and
a randomized log threshold and integrated time
*/
func FuzzVerifyArtifactTransparencyLog(f *testing.F) {
f.Fuzz(func(t *testing.T, email string,
statement []byte,
logThreshold int,
trustIntegratedTime bool) {
virtualSigstore, err := ca.NewVirtualSigstore()
if err != nil {
t.Fatal(err)
}
entity, err := virtualSigstore.Attest(email,
"issuer",
statement)
if err != nil {
t.Skip()
}
//nolint:errcheck
verify.VerifyArtifactTransparencyLog(entity,
virtualSigstore,
logThreshold,
trustIntegratedTime,
false)
})
}

/*
Tests Verify with an entity that contains a randomized
email and statement and a randomized root
*/
func FuzzSignedEntityVerifier(f *testing.F) {
f.Fuzz(func(t *testing.T, trustedrootJSON,
bundleBytes []byte) {
trustedRoot, err := root.NewTrustedRootFromJSON(trustedrootJSON)
if err != nil || trustedRoot == nil {
t.Skip()
}
var b protobundle.Bundle
err = protojson.Unmarshal(bundleBytes, &b)
if err != nil {
t.Skip()
}
entity, err := bundle.NewBundle(&b)
if err != nil {
t.Skip()
}
v, err := verify.NewSignedEntityVerifier(trustedRoot,
verify.WithTransparencyLog(1),
verify.WithObserverTimestamps(1))
if err != nil {
t.Fatal(err)
}
//nolint:errcheck
v.Verify(entity, FuzzSkipArtifactAndIdentitiesPolicy)
})
}

/*
Tests VerifySignature with a sigContent and verificationsContent
from an entity that contains a randomized email and statement.
*/
func FuzzVerifySignatureWithoutArtifactOrDigest(f *testing.F) {
f.Fuzz(func(t *testing.T, email string, statement []byte) {
virtualSigstore, err := ca.NewVirtualSigstore()
if err != nil {
t.Fatal(err)
}
entity, err := virtualSigstore.Attest(email, "issuer", statement)
if err != nil {
t.Skip()
}
sigContent, err := entity.SignatureContent()
if err != nil {
t.Fatal(err)
}

verificationContent, err := entity.VerificationContent()
if err != nil {
t.Fatal(err)
}
//nolint:errcheck
verify.VerifySignature(sigContent, verificationContent, virtualSigstore)
})
}

/*
Tests VerifySignatureWithArtifact with a sigContent and
verificationsContent from an entity that contains a randomized
email and statement. The fuzzer also creates an artifact from
random bytes
*/
func FuzzVerifySignatureWithArtifactWithoutDigest(f *testing.F) {
f.Fuzz(func(t *testing.T, email string,
statement,
artifactBytes []byte) {
virtualSigstore, err := ca.NewVirtualSigstore()
if err != nil {
t.Fatal(err)
}
entity, err := virtualSigstore.Attest(email, "issuer", statement)
if err != nil {
t.Skip()
}
sigContent, err := entity.SignatureContent()
if err != nil {
t.Fatal(err)
}

verificationContent, err := entity.VerificationContent()
if err != nil {
t.Fatal(err)
}
artifact := bytes.NewReader(artifactBytes)
//nolint:errcheck
verify.VerifySignatureWithArtifact(sigContent,
verificationContent,
virtualSigstore,
artifact)
})
}

/*
Tests VerifySignatureWithArtifactDigest with a sigContent and
verificationsContent from an entity that contains a randomized
email and statement. The fuzzer also passes a digest from
random bytes and a random string for the algorithm
*/
func FuzzVerifySignatureWithArtifactDigest(f *testing.F) {
f.Fuzz(func(t *testing.T, email,
artifactDigestAlgorithm string,
statement, artifactDigest []byte) {
virtualSigstore, err := ca.NewVirtualSigstore()
if err != nil {
t.Fatal(err)
}
entity, err := virtualSigstore.Attest(email, "issuer", statement)
if err != nil {
t.Skip()
}
sigContent, err := entity.SignatureContent()
if err != nil {
t.Fatal(err)
}

verificationContent, err := entity.VerificationContent()
if err != nil {
t.Fatal(err)
}
//nolint:errcheck
verify.VerifySignatureWithArtifactDigest(sigContent,
verificationContent,
virtualSigstore,
artifactDigest,
artifactDigestAlgorithm)
})
}

0 comments on commit f9235ff

Please sign in to comment.