From 2fa464981cfe59ec0f13966947bf868053a7b4f5 Mon Sep 17 00:00:00 2001 From: pxp928 Date: Mon, 29 Aug 2022 11:26:55 -0400 Subject: [PATCH] added test to check for v001 blocking Signed-off-by: pxp928 --- cmd/rekor-cli/app/pflags_test.go | 5 + pkg/generated/restapi/embedded_spec.go | 9 +- pkg/types/alpine/v0.0.1/entry.go | 2 +- pkg/types/cose/v0.0.1/entry.go | 2 +- pkg/types/hashedrekord/v0.0.1/entry.go | 2 +- pkg/types/helm/v0.0.1/entry.go | 2 +- pkg/types/intoto/intoto.go | 6 + pkg/types/intoto/v0.0.1/entry.go | 2 +- .../intoto/v0.0.2/intoto_v0_0_2_schema.json | 3 +- pkg/types/rekord/v0.0.1/entry.go | 2 +- pkg/types/rpm/v0.0.1/entry.go | 2 +- pkg/types/tuf/v0.0.1/entry.go | 2 +- tests/e2e-test.sh | 2 +- tests/e2e_test.go | 106 ++++++++++++++++++ 14 files changed, 130 insertions(+), 17 deletions(-) diff --git a/cmd/rekor-cli/app/pflags_test.go b/cmd/rekor-cli/app/pflags_test.go index a6a769abe..c48efc3f9 100644 --- a/cmd/rekor-cli/app/pflags_test.go +++ b/cmd/rekor-cli/app/pflags_test.go @@ -762,6 +762,11 @@ func TestParseTypeFlag(t *testing.T) { { caseDesc: "explicit intoto v0.0.1", typeStr: "intoto:0.0.1", + expectSuccess: false, + }, + { + caseDesc: "explicit intoto v0.0.2", + typeStr: "intoto:0.0.2", expectSuccess: true, }, { diff --git a/pkg/generated/restapi/embedded_spec.go b/pkg/generated/restapi/embedded_spec.go index 77da71031..6744d7cee 100644 --- a/pkg/generated/restapi/embedded_spec.go +++ b/pkg/generated/restapi/embedded_spec.go @@ -1984,8 +1984,7 @@ func init() { "$ref": "#/definitions/IntotoV002SchemaContentEnvelopeSignaturesItems0" } } - }, - "writeOnly": true + } }, "hash": { "description": "Specifies the hash algorithm and value encompassing the entire signed envelope", @@ -2059,8 +2058,7 @@ func init() { "$ref": "#/definitions/IntotoV002SchemaContentEnvelopeSignaturesItems0" } } - }, - "writeOnly": true + } }, "IntotoV002SchemaContentEnvelopeSignaturesItems0": { "description": "a signature of the envelope's payload along with the public key for the signature", @@ -3355,8 +3353,7 @@ func init() { "$ref": "#/definitions/IntotoV002SchemaContentEnvelopeSignaturesItems0" } } - }, - "writeOnly": true + } }, "hash": { "description": "Specifies the hash algorithm and value encompassing the entire signed envelope", diff --git a/pkg/types/alpine/v0.0.1/entry.go b/pkg/types/alpine/v0.0.1/entry.go index db0050514..09da6c9e6 100644 --- a/pkg/types/alpine/v0.0.1/entry.go +++ b/pkg/types/alpine/v0.0.1/entry.go @@ -332,7 +332,7 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types } publicKeyBytes = append(publicKeyBytes, keyBytes) } else if len(publicKeyBytes) != 1 { - return nil, errors.New("only one public key byte must be provided") + return nil, errors.New("only one public key must be provided") } re.AlpineModel.PublicKey.Content = (*strfmt.Base64)(&publicKeyBytes[0]) diff --git a/pkg/types/cose/v0.0.1/entry.go b/pkg/types/cose/v0.0.1/entry.go index 4427ff76d..48b4296cb 100644 --- a/pkg/types/cose/v0.0.1/entry.go +++ b/pkg/types/cose/v0.0.1/entry.go @@ -326,7 +326,7 @@ func (v V001Entry) CreateFromArtifactProperties(_ context.Context, props types.A } publicKeyBytes = append(publicKeyBytes, keyBytes) } else if len(publicKeyBytes) != 1 { - return nil, errors.New("only one public key byte must be provided") + return nil, errors.New("only one public key must be provided") } kb := strfmt.Base64(publicKeyBytes[0]) diff --git a/pkg/types/hashedrekord/v0.0.1/entry.go b/pkg/types/hashedrekord/v0.0.1/entry.go index 0712b5939..74d6654e8 100644 --- a/pkg/types/hashedrekord/v0.0.1/entry.go +++ b/pkg/types/hashedrekord/v0.0.1/entry.go @@ -227,7 +227,7 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types } publicKeyBytes = append(publicKeyBytes, keyBytes) } else if len(publicKeyBytes) != 1 { - return nil, errors.New("only one public key byte must be provided") + return nil, errors.New("only one public key must be provided") } re.HashedRekordObj.Signature.PublicKey.Content = strfmt.Base64(publicKeyBytes[0]) diff --git a/pkg/types/helm/v0.0.1/entry.go b/pkg/types/helm/v0.0.1/entry.go index 4e5dd9242..000cb2c70 100644 --- a/pkg/types/helm/v0.0.1/entry.go +++ b/pkg/types/helm/v0.0.1/entry.go @@ -327,7 +327,7 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types } publicKeyBytes = append(publicKeyBytes, keyBytes) } else if len(publicKeyBytes) != 1 { - return nil, errors.New("only one public key byte must be provided") + return nil, errors.New("only one public key must be provided") } re.HelmObj.PublicKey.Content = (*strfmt.Base64)(&publicKeyBytes[0]) diff --git a/pkg/types/intoto/intoto.go b/pkg/types/intoto/intoto.go index e6f39ba55..81d2ceeaa 100644 --- a/pkg/types/intoto/intoto.go +++ b/pkg/types/intoto/intoto.go @@ -22,6 +22,7 @@ import ( "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/types" + "golang.org/x/exp/slices" ) const ( @@ -79,3 +80,8 @@ func (it BaseIntotoType) DefaultVersion() string { func (it BaseIntotoType) SupportedVersions() []string { return []string{"0.0.2"} } + +// IsSupportedVersion returns true if the version can be inserted into the log, and false if not +func (it *BaseIntotoType) IsSupportedVersion(proposedVersion string) bool { + return slices.Contains(it.SupportedVersions(), proposedVersion) +} diff --git a/pkg/types/intoto/v0.0.1/entry.go b/pkg/types/intoto/v0.0.1/entry.go index f2c2da866..438f08392 100644 --- a/pkg/types/intoto/v0.0.1/entry.go +++ b/pkg/types/intoto/v0.0.1/entry.go @@ -302,7 +302,7 @@ func (v V001Entry) CreateFromArtifactProperties(_ context.Context, props types.A } publicKeyBytes = append(publicKeyBytes, keyBytes) } else if len(publicKeyBytes) != 1 { - return nil, errors.New("only one public key byte must be provided") + return nil, errors.New("only one public key must be provided") } kb := strfmt.Base64(publicKeyBytes[0]) diff --git a/pkg/types/intoto/v0.0.2/intoto_v0_0_2_schema.json b/pkg/types/intoto/v0.0.2/intoto_v0_0_2_schema.json index 63f18bdb4..0008e46fb 100644 --- a/pkg/types/intoto/v0.0.2/intoto_v0_0_2_schema.json +++ b/pkg/types/intoto/v0.0.2/intoto_v0_0_2_schema.json @@ -49,8 +49,7 @@ } } }, - "required": ["payloadType", "signatures"], - "writeOnly": true + "required": ["payloadType", "signatures"] }, "hash": { "description": "Specifies the hash algorithm and value encompassing the entire signed envelope", diff --git a/pkg/types/rekord/v0.0.1/entry.go b/pkg/types/rekord/v0.0.1/entry.go index 9c160a3e6..95feb3ba4 100644 --- a/pkg/types/rekord/v0.0.1/entry.go +++ b/pkg/types/rekord/v0.0.1/entry.go @@ -401,7 +401,7 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types } publicKeyBytes = append(publicKeyBytes, keyBytes) } else if len(publicKeyBytes) != 1 { - return nil, errors.New("only one public key byte must be provided") + return nil, errors.New("only one public key must be provided") } re.RekordObj.Signature.PublicKey.Content = (*strfmt.Base64)(&publicKeyBytes[0]) diff --git a/pkg/types/rpm/v0.0.1/entry.go b/pkg/types/rpm/v0.0.1/entry.go index a754bce6a..1523a4297 100644 --- a/pkg/types/rpm/v0.0.1/entry.go +++ b/pkg/types/rpm/v0.0.1/entry.go @@ -352,7 +352,7 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types } publicKeyBytes = append(publicKeyBytes, keyBytes) } else if len(publicKeyBytes) != 1 { - return nil, errors.New("only one public key byte must be provided") + return nil, errors.New("only one public key must be provided") } re.RPMModel.PublicKey.Content = (*strfmt.Base64)(&publicKeyBytes[0]) diff --git a/pkg/types/tuf/v0.0.1/entry.go b/pkg/types/tuf/v0.0.1/entry.go index f50964860..8c3a9ff15 100644 --- a/pkg/types/tuf/v0.0.1/entry.go +++ b/pkg/types/tuf/v0.0.1/entry.go @@ -344,7 +344,7 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types rootBytes = append(rootBytes, keyBytes) } else if len(rootBytes) != 1 { - return nil, errors.New("only one root key byte must be provided") + return nil, errors.New("only one root key must be provided") } root := &data.Signed{} diff --git a/tests/e2e-test.sh b/tests/e2e-test.sh index 1e9b8e0cf..f930e4b41 100755 --- a/tests/e2e-test.sh +++ b/tests/e2e-test.sh @@ -18,7 +18,7 @@ set -e testdir=$(dirname "$0") echo "starting services" -docker-compose up -d --build +docker-compose up -d echo "building CLI and server" go build -o rekor-cli ./cmd/rekor-cli diff --git a/tests/e2e_test.go b/tests/e2e_test.go index 535497856..104ff2f8a 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -33,16 +33,19 @@ import ( "fmt" "io/ioutil" "net/http" + "net/url" "os" "os/exec" "path/filepath" "reflect" + "runtime" "strconv" "strings" "testing" "time" "golang.org/x/sync/errgroup" + "sigs.k8s.io/release-utils/version" "github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer" "github.com/go-openapi/strfmt" @@ -57,6 +60,7 @@ import ( "github.com/sigstore/rekor/pkg/sharding" "github.com/sigstore/rekor/pkg/signer" "github.com/sigstore/rekor/pkg/types" + _ "github.com/sigstore/rekor/pkg/types/intoto/v0.0.1" rekord "github.com/sigstore/rekor/pkg/types/rekord/v0.0.1" "github.com/sigstore/rekor/pkg/util" "github.com/sigstore/sigstore/pkg/cryptoutils" @@ -523,6 +527,10 @@ func TestIntoto(t *testing.T) { write(t, string(eb), attestationPath) write(t, ecdsaPub, pubKeyPath) + // ensure that we can't upload a intoto v0.0.1 entry + v001out := runCliErr(t, "upload", "--artifact", attestationPath, "--type", "intoto:0.0.1", "--public-key", pubKeyPath) + outputContains(t, v001out, "type intoto does not support version 0.0.1") + // If we do it twice, it should already exist out := runCli(t, "upload", "--artifact", attestationPath, "--type", "intoto", "--public-key", pubKeyPath) outputContains(t, out, "Created entry at") @@ -653,6 +661,10 @@ func TestIntotoMultiSig(t *testing.T) { write(t, ecdsaPub, ecdsapubKeyPath) write(t, pubKey, rsapubKeyPath) + // ensure that we can't upload a intoto v0.0.1 entry + v001out := runCliErr(t, "upload", "--artifact", attestationPath, "--type", "intoto:0.0.1", "--public-key", ecdsapubKeyPath, "--public-key", rsapubKeyPath) + outputContains(t, v001out, "type intoto does not support version 0.0.1") + // If we do it twice, it should already exist out := runCli(t, "upload", "--artifact", attestationPath, "--type", "intoto", "--public-key", ecdsapubKeyPath, "--public-key", rsapubKeyPath) outputContains(t, out, "Created entry at") @@ -697,6 +709,100 @@ func TestIntotoMultiSig(t *testing.T) { } +func TestIntotoBlockV001(t *testing.T) { + td := t.TempDir() + attestationPath := filepath.Join(td, "attestation.json") + pubKeyPath := filepath.Join(td, "pub.pem") + + // Get some random data so it's unique each run + d := randomData(t, 10) + id := base64.StdEncoding.EncodeToString(d) + + it := in_toto.ProvenanceStatement{ + StatementHeader: in_toto.StatementHeader{ + Type: in_toto.StatementInTotoV01, + PredicateType: slsa.PredicateSLSAProvenance, + Subject: []in_toto.Subject{ + { + Name: "foobar", + Digest: slsa.DigestSet{ + "foo": "bar", + }, + }, + }, + }, + Predicate: slsa.ProvenancePredicate{ + Builder: slsa.ProvenanceBuilder{ + ID: "foo" + id, + }, + }, + } + + b, err := json.Marshal(it) + if err != nil { + t.Fatal(err) + } + + pb, _ := pem.Decode([]byte(ecdsaPriv)) + priv, err := x509.ParsePKCS8PrivateKey(pb.Bytes) + if err != nil { + t.Fatal(err) + } + + s, err := signature.LoadECDSASigner(priv.(*ecdsa.PrivateKey), crypto.SHA256) + if err != nil { + t.Fatal(err) + } + + signer, err := dsse.NewEnvelopeSigner(&verifier{ + s: s, + }) + if err != nil { + t.Fatal(err) + } + + env, err := signer.SignPayload(in_toto.PayloadType, b) + if err != nil { + t.Fatal(err) + } + + eb, err := json.Marshal(env) + if err != nil { + t.Fatal(err) + } + + uaString := fmt.Sprintf("rekor-cli/%s (%s; %s)", version.GetVersionInfo().GitVersion, runtime.GOOS, runtime.GOARCH) + + write(t, string(eb), attestationPath) + write(t, ecdsaPub, pubKeyPath) + + rekorClient, err := client.GetRekorClient("http://localhost:3000", client.WithUserAgent(uaString)) + if err != nil { + t.Fatal(err) + } + var entry models.ProposedEntry + params := entries.NewCreateLogEntryParams() + params.SetTimeout(time.Duration(30) * time.Second) + + props := &types.ArtifactProperties{} + + props.ArtifactPath = &url.URL{Path: attestationPath} + + collectedKeys := []*url.URL{{Path: pubKeyPath}} + props.PublicKeyPaths = collectedKeys + + entry, err = types.NewProposedEntry(context.Background(), "intoto", "0.0.1", *props) + if err != nil { + t.Fatal(err) + } + params.SetProposedEntry(entry) + + _, err = rekorClient.Entries.CreateLogEntry(params) + if err == nil { + t.Fatal("insertion of v0.0.1 entry should fail") + } +} + func TestTimestampArtifact(t *testing.T) { var out string out = runCli(t, "upload", "--type", "rfc3161", "--artifact", "test.tsr")