diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 95d153fc..12e261e0 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -43,7 +43,7 @@ jobs: check-latest: true # will use the latest release available for ko - - uses: imjasonh/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 - uses: chainguard-dev/actions/goimports@dacf41f3472c33979cfd49bca5b503236be57de0 # main diff --git a/.github/workflows/kind-cluster-image-policy-no-tuf.yaml b/.github/workflows/kind-cluster-image-policy-no-tuf.yaml index abe3cca4..8036b11c 100644 --- a/.github/workflows/kind-cluster-image-policy-no-tuf.yaml +++ b/.github/workflows/kind-cluster-image-policy-no-tuf.yaml @@ -100,12 +100,12 @@ jobs: check-latest: true # will use the latest release available for ko - - uses: imjasonh/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 - uses: imranismail/setup-kustomize@2ba527d4d055ab63514ba50a99456fc35684947f # v2.1.0 - name: Install yq - uses: mikefarah/yq@9adde1ac14bb283b8955d2b0d567bcaf3c69e639 # v4.42.1 + uses: mikefarah/yq@c35ec752e38ea0c096d3c44e13cfc0797ac394d8 # v4.43.1 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@main diff --git a/.github/workflows/kind-cluster-image-policy-resync-period.yaml b/.github/workflows/kind-cluster-image-policy-resync-period.yaml index f234e02f..bdc4ccb0 100644 --- a/.github/workflows/kind-cluster-image-policy-resync-period.yaml +++ b/.github/workflows/kind-cluster-image-policy-resync-period.yaml @@ -100,12 +100,12 @@ jobs: check-latest: true # will use the latest release available for ko - - uses: imjasonh/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 - uses: imranismail/setup-kustomize@2ba527d4d055ab63514ba50a99456fc35684947f # v2.1.0 - name: Install yq - uses: mikefarah/yq@9adde1ac14bb283b8955d2b0d567bcaf3c69e639 # v4.42.1 + uses: mikefarah/yq@c35ec752e38ea0c096d3c44e13cfc0797ac394d8 # v4.43.1 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@main diff --git a/.github/workflows/kind-cluster-image-policy-trustroot.yaml b/.github/workflows/kind-cluster-image-policy-trustroot.yaml index e246b8d7..052b1b46 100644 --- a/.github/workflows/kind-cluster-image-policy-trustroot.yaml +++ b/.github/workflows/kind-cluster-image-policy-trustroot.yaml @@ -105,12 +105,12 @@ jobs: check-latest: true # will use the latest release available for ko - - uses: imjasonh/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 - uses: imranismail/setup-kustomize@2ba527d4d055ab63514ba50a99456fc35684947f # v2.1.0 - name: Install yq - uses: mikefarah/yq@9adde1ac14bb283b8955d2b0d567bcaf3c69e639 # v4.42.1 + uses: mikefarah/yq@c35ec752e38ea0c096d3c44e13cfc0797ac394d8 # v4.43.1 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@main diff --git a/.github/workflows/kind-cluster-image-policy-tsa.yaml b/.github/workflows/kind-cluster-image-policy-tsa.yaml index e93f593a..3218e2cf 100644 --- a/.github/workflows/kind-cluster-image-policy-tsa.yaml +++ b/.github/workflows/kind-cluster-image-policy-tsa.yaml @@ -100,12 +100,12 @@ jobs: check-latest: true # will use the latest release available for ko - - uses: imjasonh/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 - uses: imranismail/setup-kustomize@2ba527d4d055ab63514ba50a99456fc35684947f # v2.1.0 - name: Install yq - uses: mikefarah/yq@9adde1ac14bb283b8955d2b0d567bcaf3c69e639 # v4.42.1 + uses: mikefarah/yq@c35ec752e38ea0c096d3c44e13cfc0797ac394d8 # v4.43.1 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@main diff --git a/.github/workflows/kind-cluster-image-policy.yaml b/.github/workflows/kind-cluster-image-policy.yaml index 17561ba6..3843fe7f 100644 --- a/.github/workflows/kind-cluster-image-policy.yaml +++ b/.github/workflows/kind-cluster-image-policy.yaml @@ -114,12 +114,12 @@ jobs: check-latest: true # will use the latest release available for ko - - uses: imjasonh/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 - uses: imranismail/setup-kustomize@2ba527d4d055ab63514ba50a99456fc35684947f # v2.1.0 - name: Install yq - uses: mikefarah/yq@9adde1ac14bb283b8955d2b0d567bcaf3c69e639 # v4.42.1 + uses: mikefarah/yq@c35ec752e38ea0c096d3c44e13cfc0797ac394d8 # v4.43.1 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@main diff --git a/.github/workflows/kind-e2e-cosigned.yaml b/.github/workflows/kind-e2e-cosigned.yaml index 89fc2515..0456501f 100644 --- a/.github/workflows/kind-e2e-cosigned.yaml +++ b/.github/workflows/kind-e2e-cosigned.yaml @@ -98,12 +98,12 @@ jobs: go-version-file: './go.mod' check-latest: true - - uses: imjasonh/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 - uses: imranismail/setup-kustomize@2ba527d4d055ab63514ba50a99456fc35684947f # v2.1.0 - name: Install yq - uses: mikefarah/yq@9adde1ac14bb283b8955d2b0d567bcaf3c69e639 # v4.42.1 + uses: mikefarah/yq@c35ec752e38ea0c096d3c44e13cfc0797ac394d8 # v4.43.1 - uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 diff --git a/.github/workflows/kind-e2e-trustroot-crd.yaml b/.github/workflows/kind-e2e-trustroot-crd.yaml index cea9517e..30eadce9 100644 --- a/.github/workflows/kind-e2e-trustroot-crd.yaml +++ b/.github/workflows/kind-e2e-trustroot-crd.yaml @@ -98,12 +98,12 @@ jobs: go-version-file: './go.mod' check-latest: true - - uses: imjasonh/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 - uses: imranismail/setup-kustomize@2ba527d4d055ab63514ba50a99456fc35684947f # v2.1.0 - name: Install yq - uses: mikefarah/yq@9adde1ac14bb283b8955d2b0d567bcaf3c69e639 # v4.42.1 + uses: mikefarah/yq@c35ec752e38ea0c096d3c44e13cfc0797ac394d8 # v4.43.1 - uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4f52bec0..356f1312 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -28,7 +28,7 @@ jobs: - uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 - - uses: anchore/sbom-action/download-syft@9fece9e20048ca9590af301449208b2b8861333b # v0.15.9 + - uses: anchore/sbom-action/download-syft@ab5d7b5f48981941c4c5d6bf33aeb98fe3bae38c # v0.15.10 - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 3a4fc04b..d796f8e4 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -57,7 +57,7 @@ jobs: - name: Run Go tests run: go test -covermode atomic -coverprofile coverage.txt $(go list ./... | grep -v third_party/) - name: Upload Coverage Report - uses: codecov/codecov-action@54bcd8715eee62d40e33596ef5e8f0f48dbbccab # v4.1.0 + uses: codecov/codecov-action@c16abc29c95fcf9174b58eb7e1abf4c866893bc8 # v4.1.1 with: env_vars: OS - name: Run Go tests w/ `-race` diff --git a/cmd/tester/main.go b/cmd/tester/main.go index 2bf800ec..583198e3 100644 --- a/cmd/tester/main.go +++ b/cmd/tester/main.go @@ -154,11 +154,13 @@ func main() { log.Fatal(err) } - c := &config.SigstoreKeys{} - c.ConvertFrom(context.Background(), tr.Spec.SigstoreKeys) - maps := make(map[string]config.SigstoreKeys, 0) + c, err := config.ConvertSigstoreKeys(context.Background(), tr.Spec.SigstoreKeys) + if err != nil { + log.Fatal(err) + } + maps := make(map[string]*config.SigstoreKeys, 0) - maps[tr.Name] = *c + maps[tr.Name] = c configCtx.SigstoreKeysConfig = &config.SigstoreKeysMap{SigstoreKeys: maps} ctx = config.ToContext(ctx, configCtx) diff --git a/go.mod b/go.mod index 96453b3f..e9520ea2 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.21 toolchain go1.21.1 require ( - github.com/aws/aws-sdk-go v1.51.6 - github.com/aws/aws-sdk-go-v2 v1.25.2 // indirect + github.com/aws/aws-sdk-go v1.51.12 + github.com/aws/aws-sdk-go-v2 v1.26.0 // indirect github.com/cenkalti/backoff/v3 v3.2.2 github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -31,7 +31,7 @@ require ( github.com/ryanuber/go-glob v1.0.0 github.com/sigstore/cosign/v2 v2.2.3 github.com/sigstore/rekor v1.3.5 - github.com/sigstore/sigstore v1.8.2 + github.com/sigstore/sigstore v1.8.3 github.com/stretchr/testify v1.9.0 github.com/theupdateframework/go-tuf v0.7.0 github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 @@ -40,8 +40,8 @@ require ( golang.org/x/net v0.22.0 golang.org/x/sys v0.18.0 // indirect golang.org/x/time v0.5.0 - google.golang.org/grpc v1.62.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/grpc v1.62.1 // indirect + google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.29.3 k8s.io/apimachinery v0.29.3 @@ -51,7 +51,7 @@ require ( knative.dev/hack v0.0.0-20231016131700-2c938d4918da knative.dev/hack/schema v0.0.0-20221024013916-9d2ae47c16b2 knative.dev/pkg v0.0.0-20231101193506-b09d4f2a2845 - sigs.k8s.io/release-utils v0.7.7 + sigs.k8s.io/release-utils v0.8.0 sigs.k8s.io/yaml v1.4.0 ) @@ -61,26 +61,27 @@ require ( github.com/docker/docker v26.0.0+incompatible github.com/docker/go-connections v0.5.0 github.com/go-jose/go-jose/v3 v3.0.3 + github.com/sigstore/protobuf-specs v0.3.1 github.com/sigstore/scaffolding v0.6.17 - github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.2 - github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.2 - github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.2 + github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.3 + github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.3 + github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.3 github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.2 github.com/spf13/viper v1.18.2 gopkg.in/go-jose/go-jose.v2 v2.6.3 ) require ( - cloud.google.com/go/compute v1.23.4 // indirect + cloud.google.com/go/compute v1.24.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.6 // indirect - cloud.google.com/go/kms v1.15.7 // indirect + cloud.google.com/go/kms v1.15.8 // indirect contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d // indirect contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect cuelang.org/go v0.7.0 // indirect github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 // indirect @@ -111,20 +112,20 @@ require ( github.com/alibabacloud-go/tea-xml v1.1.3 // indirect github.com/aliyun/credentials-go v1.3.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go-v2/config v1.27.4 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.4 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.9 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.9 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.24.7 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.21.6 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.2 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.29.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.20.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.28.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 // indirect github.com/aws/smithy-go v1.20.1 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -184,7 +185,7 @@ require ( github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.1 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/hashicorp/vault/api v1.12.0 // indirect @@ -247,8 +248,8 @@ require ( github.com/yashtewari/glob-intersection v0.2.0 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect @@ -259,17 +260,17 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/oauth2 v0.17.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.16.1 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/api v0.167.0 // indirect + google.golang.org/api v0.171.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 337db571..7b900656 100644 --- a/go.sum +++ b/go.sum @@ -21,16 +21,16 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw= -cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= -cloud.google.com/go/kms v1.15.7 h1:7caV9K3yIxvlQPAcaFffhlT7d1qpxjB1wHBtjWa13SM= -cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= +cloud.google.com/go/kms v1.15.8 h1:szIeDCowID8th2i8XE4uRev5PMxQFqW+JjwYxL9h6xs= +cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -57,8 +57,8 @@ github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 h1:c4k2FIYIh4xtwqrQwV0Ct1v5+ehlNXj5NI/MWVsiTkQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2/go.mod h1:5FDJtLEO/GxwNgUxbwrY3LP0pEoThTQJtk2oysdXHxM= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= @@ -161,20 +161,20 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.51.6 h1:Ld36dn9r7P9IjU8WZSaswQ8Y/XUCRpewim5980DwYiU= -github.com/aws/aws-sdk-go v1.51.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.25.2 h1:/uiG1avJRgLGiQM9X3qJM8+Qa6KRGK5rRPuXE0HUM+w= -github.com/aws/aws-sdk-go-v2 v1.25.2/go.mod h1:Evoc5AsmtveRt1komDwIsjHFyrP5tDuF1D1U+6z6pNo= -github.com/aws/aws-sdk-go-v2/config v1.27.4 h1:AhfWb5ZwimdsYTgP7Od8E9L1u4sKmDW2ZVeLcf2O42M= -github.com/aws/aws-sdk-go-v2/config v1.27.4/go.mod h1:zq2FFXK3A416kiukwpsd+rD4ny6JC7QSkp4QdN1Mp2g= -github.com/aws/aws-sdk-go-v2/credentials v1.17.4 h1:h5Vztbd8qLppiPwX+y0Q6WiwMZgpd9keKe2EAENgAuI= -github.com/aws/aws-sdk-go-v2/credentials v1.17.4/go.mod h1:+30tpwrkOgvkJL1rUZuRLoxcJwtI/OkeBLYnHxJtVe0= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2 h1:AK0J8iYBFeUk2Ax7O8YpLtFsfhdOByh2QIkHmigpRYk= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2/go.mod h1:iRlGzMix0SExQEviAyptRWRGdYNo3+ufW/lCzvKVTUc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2 h1:bNo4LagzUKbjdxE0tIcR9pMzLR2U/Tgie1Hq1HQ3iH8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2/go.mod h1:wRQv0nN6v9wDXuWThpovGQjqF1HFdcgWjporw14lS8k= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2 h1:EtOU5jsPdIQNP+6Q2C5e3d65NKT1PeCiQk+9OdzO12Q= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2/go.mod h1:tyF5sKccmDz0Bv4NrstEr+/9YkSPJHrcO7UsUKf7pWM= +github.com/aws/aws-sdk-go v1.51.12 h1:DvuhIHZXwnjaR1/Gu19gUe1EGPw4J0qSJw4Qs/5PA8g= +github.com/aws/aws-sdk-go v1.51.12/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.26.0 h1:/Ce4OCiM3EkpW7Y+xUnfAFpchU78K7/Ug01sZni9PgA= +github.com/aws/aws-sdk-go-v2 v1.26.0/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I= +github.com/aws/aws-sdk-go-v2/config v1.27.9 h1:gRx/NwpNEFSk+yQlgmk1bmxxvQ5TyJ76CWXs9XScTqg= +github.com/aws/aws-sdk-go-v2/config v1.27.9/go.mod h1:dK1FQfpwpql83kbD873E9vz4FyAxuJtR22wzoXn3qq0= +github.com/aws/aws-sdk-go-v2/credentials v1.17.9 h1:N8s0/7yW+h8qR8WaRlPQeJ6czVMNQVNtNdUqf6cItao= +github.com/aws/aws-sdk-go-v2/credentials v1.17.9/go.mod h1:446YhIdmSV0Jf/SLafGZalQo+xr2iw7/fzXGDPTU1yQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 h1:af5YzcLf80tv4Em4jWVD75lpnOHSBkPUZxZfGkrI3HI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 h1:0ScVK/4qZ8CIW0k8jOeFVsyS/sAiXpYxRBLolMkuLQM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4/go.mod h1:84KyjNZdHC6QZW08nfHI6yZgPd+qRgaWcYsyLUo3QY8= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 h1:sHmMWWX5E7guWEFQ9SVo6A3S4xpPrWnd77a6y4WM6PU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4/go.mod h1:WjpDrhWisWOIoS9n3nk67A3Ll1vfULJ9Kq6h29HTD48= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/service/ecr v1.24.7 h1:3iaT/LnGV6jNtbBkvHZDlzz7Ky3wMHDJAyFtGd5GUJI= @@ -183,16 +183,16 @@ github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.21.6 h1:h+r5/diSwztgKgxUrntt6A github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.21.6/go.mod h1:7+5MHFC52LC85xKCjCuWDHmIncOOvWnll10OT9EAN/g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.2 h1:5ffmXjPtwRExp1zc7gENLgCPyHFbhEPwVTkTiH9niSk= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.2/go.mod h1:Ru7vg1iQ7cR4i7SZ/JTLYN9kaXtbL69UdgG0OQWQxW0= -github.com/aws/aws-sdk-go-v2/service/kms v1.29.1 h1:OdjJjUWFlMZLAMl54ASxIpZdGEesY4BH3/c0HAPSFdI= -github.com/aws/aws-sdk-go-v2/service/kms v1.29.1/go.mod h1:Cbx2uxEX0bAB7SlSY+ys05ZBkEb8IbmuAOcGVmDfJFs= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.1 h1:utEGkfdQ4L6YW/ietH7111ZYglLJvS+sLriHJ1NBJEQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.1/go.mod h1:RsYqzYr2F2oPDdpy+PdhephuZxTfjHQe7SOBcZGoAU8= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1 h1:9/GylMS45hGGFCcMrUZDVayQE1jYSIN6da9jo7RAYIw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1/go.mod h1:YjAPFn4kGFqKC54VsHs5fn5B6d+PCY2tziEa3U/GB5Y= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.1 h1:3I2cBEYgKhrWlwyZgfpSO2BpaMY1LHPqXYk/QGlu2ew= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.1/go.mod h1:uQ7YYKZt3adCRrdCBREm1CD3efFLOUNH77MrUCvx5oA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 h1:b+E7zIUHMmcB4Dckjpkapoy47W6C9QBv/zoUP+Hn8Kc= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6/go.mod h1:S2fNV0rxrP78NhPbCZeQgY8H9jdDMeGtwcfZIRxzBqU= +github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= +github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 h1:mnbuWHOcM70/OFUlZZ5rcdfA8PflGXXiefU/O+1S3+8= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.3/go.mod h1:5HFu51Elk+4oRBZVxmHrSds5jFXmFj8C3w7DVF2gnrs= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 h1:uLq0BKatTmDzWa/Nu4WO0M1AaQDaPpwTKAeByEc6WFM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3/go.mod h1:b+qdhjnxj8GSR6t5YfphOffeoQSQ1KmpoVVuBn+PWxs= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 h1:J/PpTf/hllOjx8Xu9DMflff3FajfLxqM5+tepvVXmxg= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.5/go.mod h1:0ih0Z83YDH/QeQ6Ori2yGE2XvWYv/Xm+cZc01LC6oK0= github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw= github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M= @@ -236,8 +236,6 @@ github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUK github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= @@ -296,8 +294,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc= @@ -482,8 +478,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.12.1 h1:9F8GV9r9ztXyAi00gsMQHNoF51xPZm8uj1dpYt2ZETM= -github.com/googleapis/gax-go/v2 v2.12.1/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -721,18 +717,20 @@ github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= github.com/sigstore/cosign/v2 v2.2.3 h1:WX7yawI+EXu9h7S5bZsfYCbB9XW6Jc43ctKy/NoOSiA= github.com/sigstore/cosign/v2 v2.2.3/go.mod h1:WpMn4MBt0cI23GdHsePwO4NxhX1FOz1ITGB3ALUjFaI= +github.com/sigstore/protobuf-specs v0.3.1 h1:9aJQrPq7iRDSLBNg//zsP7tAzxdHnD1sA+1FyCCrkrQ= +github.com/sigstore/protobuf-specs v0.3.1/go.mod h1:HfkcPi5QXteuew4+c5ONz8vYQ8aOH//ZTQ3gg0X8ZUA= github.com/sigstore/rekor v1.3.5 h1:QoVXcS7NppKY+rpbEFVHr4evGDZBBSh65X0g8PXoUkQ= github.com/sigstore/rekor v1.3.5/go.mod h1:CWqOk/fmnPwORQmm7SyDgB54GTJizqobbZ7yOP1lvw8= github.com/sigstore/scaffolding v0.6.17 h1:60P4/x/PdIj7SjzhEgEDefrnDcHAKzztF/RXddjZGQ8= github.com/sigstore/scaffolding v0.6.17/go.mod h1:jTrLu0YmR5pfQDBieDpn97GSqAPHBAvgjzk8iUNGVjo= -github.com/sigstore/sigstore v1.8.2 h1:0Ttjcn3V0fVQXlYq7+oHaaHkGFIt3ywm7SF4JTU/l8c= -github.com/sigstore/sigstore v1.8.2/go.mod h1:CHVcSyknCcjI4K2ZhS1SI28r0tcQyBlwtALG536x1DY= -github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.2 h1:e0EtUcE7cqWBxxME7h6upA3EA0IR3EOE3F1t+WHOdTc= -github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.2/go.mod h1:07qBxPjI9bsgdQRiBz27Ai+gl6hgr//vwXMZzTX87Us= -github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.2 h1:Fgt4dC9OozkLEtMO6JYfFgqNdSDG1y1uAdiJgrtZYN4= -github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.2/go.mod h1:BT+jh/GK55djPRHqTYu937eq29Zzusf1t0qVbrcn4Aw= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.2 h1:aX6hLH5v3JdOQJJ6+uCMmeDjcwyfQMLmXKJVl6HtzAg= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.2/go.mod h1:OEFPub6XKsX6Fl/PpeIpQTsukG3I0CFWb9saHINV72U= +github.com/sigstore/sigstore v1.8.3 h1:G7LVXqL+ekgYtYdksBks9B38dPoIsbscjQJX/MGWkA4= +github.com/sigstore/sigstore v1.8.3/go.mod h1:mqbTEariiGA94cn6G3xnDiV6BD8eSLdL/eA7bvJ0fVs= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.3 h1:LTfPadUAo+PDRUbbdqbeSl2OuoFQwUFTnJ4stu+nwWw= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.3/go.mod h1:QV/Lxlxm0POyhfyBtIbTWxNeF18clMlkkyL9mu45y18= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.3 h1:xgbPRCr2npmmsuVVteJqi/ERw9+I13Wou7kq0Yk4D8g= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.3/go.mod h1:G4+I83FILPX6MtnoaUdmv/bRGEVtR3JdLeJa/kXdk/0= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.3 h1:vDl2fqPT0h3D/k6NZPlqnKFd1tz3335wm39qjvpZNJc= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.3/go.mod h1:9uOJXbXEXj+M6QjMKH5PaL5WDMu43rHfbIMgXzA8eKI= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.2 h1:hRC8sGPQtnTcoOqWbCNAvLpW1pHL4CQl7FT55IrEof8= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.2/go.mod h1:frWJBbYRRHnbLE9h1fH349Mde84NZh6hDrnKqhPgMNU= github.com/sigstore/timestamp-authority v1.2.2 h1:X4qyutnCQqJ0apMewFyx+3t7Tws00JQ/JonBiu3QvLE= @@ -822,10 +820,10 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 h1:P+/g8GpuJGYbOp2tAdKrIPUX9JO02q8Q0YNlHolpibA= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0/go.mod h1:tIKj3DbO8N9Y2xo52og3irLsPI4GW02DSMtrVgNMgxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 h1:doUP+ExOpH3spVTLS0FcWGLnQrPct/hD/bCPbDRUEAU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= @@ -967,8 +965,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1148,8 +1146,8 @@ google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.167.0 h1:CKHrQD1BLRii6xdkatBDXyKzM0mkawt2QP+H3LtPmSE= -google.golang.org/api v0.167.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= +google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= +google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1189,12 +1187,12 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU= -google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= +google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= +google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1208,8 +1206,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1295,8 +1293,8 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/release-utils v0.7.7 h1:JKDOvhCk6zW8ipEOkpTGDH/mW3TI+XqtPp16aaQ79FU= -sigs.k8s.io/release-utils v0.7.7/go.mod h1:iU7DGVNi3umZJ8q6aHyUFzsDUIaYwNnNKGHo3YE5E3s= +sigs.k8s.io/release-utils v0.8.0 h1:iiyzoALmcPhcrA4Xkb73GHBwoyDfqkS6DItSixaeSJs= +sigs.k8s.io/release-utils v0.8.0/go.mod h1:GWU37J2Srptpc4TvU3yllZORPf0xoH3zk4YPjbWoMtg= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/hack/gentestdata/gentestdata.go b/hack/gentestdata/gentestdata.go index 15013867..4390023d 100644 --- a/hack/gentestdata/gentestdata.go +++ b/hack/gentestdata/gentestdata.go @@ -1,10 +1,10 @@ -// Copyright 2024 The Sigstore Authors +// 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 +// 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, @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/x509" "crypto/x509/pkix" - "encoding/json" "encoding/pem" "flag" "log" @@ -35,8 +34,10 @@ import ( "github.com/sigstore/cosign/v2/pkg/cosign" "github.com/sigstore/policy-controller/pkg/apis/config" testing "github.com/sigstore/policy-controller/pkg/reconciler/testing/v1alpha1" + pbcommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" "github.com/sigstore/scaffolding/pkg/repo" "github.com/sigstore/sigstore/pkg/cryptoutils" + "google.golang.org/protobuf/encoding/protojson" ) // This program generates test data for the trustroot reconciler. @@ -76,7 +77,23 @@ func main() { log.Fatal(err) } - marshalledEntryFromMirrorFS, tufRepo, rootJSON, err := genTUFRepo(sigstoreKeysMap) + tufRepo, rootJSON, err := genTUFRepo(map[string][]byte{ + "rekor.pem": []byte(sigstoreKeysMap["rekor"]), + "ctfe.pem": []byte(sigstoreKeysMap["ctfe"]), + "fulcio.pem": []byte(sigstoreKeysMap["fulcio"]), + }) + if err != nil { + log.Fatal(err) + } + + tufRepoWithTrustedRootJSON, rootJSONWithTrustedRootJSON, err := genTUFRepo(map[string][]byte{ + "trusted_root.json": marshalledEntry, + }) + if err != nil { + log.Fatal(err) + } + + marshalledEntryFromMirrorFS, err := genTrustedRoot(sigstoreKeysMap) if err != nil { log.Fatal(err) } @@ -91,6 +108,8 @@ func main() { mustWriteFile("marshalledEntryFromMirrorFS.json", marshalledEntryFromMirrorFS) mustWriteFile("tufRepo.tar", tufRepo) mustWriteFile("root.json", rootJSON) + mustWriteFile("tufRepoWithTrustedRootJSON.tar", tufRepoWithTrustedRootJSON) + mustWriteFile("rootWithTrustedRootJSON.json", rootJSONWithTrustedRootJSON) } func mustWriteFile(path string, data []byte) { @@ -169,79 +188,100 @@ func genCertChain(keyUsage x509.KeyUsage) [][]byte { func genTrustRoot(sigstoreKeysMap map[string]string) (marshalledEntry []byte, err error) { trustRoot := testing.NewTrustRoot("test-trustroot", testing.WithSigstoreKeys(sigstoreKeysMap)) - sigstoreKeys := &config.SigstoreKeys{} - sigstoreKeys.ConvertFrom(context.Background(), trustRoot.Spec.SigstoreKeys) + sigstoreKeys, err := config.ConvertSigstoreKeys(context.Background(), trustRoot.Spec.SigstoreKeys) + if err != nil { + return nil, err + } err = populateLogIDs(sigstoreKeys) if err != nil { return nil, err } - return json.MarshalIndent(sigstoreKeys, "", " ") + return []byte(protojson.Format(sigstoreKeys)), nil } func populateLogIDs(sigstoreKeys *config.SigstoreKeys) error { - for i := range sigstoreKeys.TLogs { - logID, err := genLogID(sigstoreKeys.TLogs[i].PublicKey) + for i := range sigstoreKeys.Tlogs { + logID, err := genLogID(sigstoreKeys.Tlogs[i].PublicKey.RawBytes) if err != nil { return err } - sigstoreKeys.TLogs[i].LogID = logID + sigstoreKeys.Tlogs[i].LogId = &config.LogID{KeyId: []byte(logID)} } - for i := range sigstoreKeys.CTLogs { - logID, err := genLogID(sigstoreKeys.CTLogs[i].PublicKey) + for i := range sigstoreKeys.Ctlogs { + logID, err := genLogID(sigstoreKeys.Ctlogs[i].PublicKey.RawBytes) if err != nil { return err } - sigstoreKeys.CTLogs[i].LogID = logID + sigstoreKeys.Ctlogs[i].LogId = &config.LogID{KeyId: []byte(logID)} } return nil } func genLogID(pkBytes []byte) (string, error) { - pk, err := cryptoutils.UnmarshalPEMToPublicKey(pkBytes) + pk, err := x509.ParsePKIXPublicKey(pkBytes) if err != nil { return "", err } return cosign.GetTransparencyLogID(pk) } -func genTUFRepo(sigstoreKeysMap map[string]string) ([]byte, []byte, []byte, error) { - files := map[string][]byte{} - files["rekor.pem"] = []byte(sigstoreKeysMap["rekor"]) - files["ctfe.pem"] = []byte(sigstoreKeysMap["ctfe"]) - files["fulcio.pem"] = []byte(sigstoreKeysMap["fulcio"]) - +func genTUFRepo(files map[string][]byte) ([]byte, []byte, error) { defer os.RemoveAll(path.Join(os.TempDir(), "tuf")) // TODO: Update scaffolding to use os.MkdirTemp and remove this ctx := context.Background() local, dir, err := repo.CreateRepo(ctx, files) if err != nil { - return nil, nil, nil, err + return nil, nil, err } meta, err := local.GetMeta() if err != nil { - return nil, nil, nil, err + return nil, nil, err } rootJSON, ok := meta["root.json"] if !ok { - return nil, nil, nil, err + return nil, nil, err } var compressed bytes.Buffer if err := repo.CompressFS(os.DirFS(dir), &compressed, map[string]bool{"keys": true, "staged": true}); err != nil { - return nil, nil, nil, err + return nil, nil, err + } + return compressed.Bytes(), rootJSON, nil +} + +func genTrustedRoot(sigstoreKeysMap map[string]string) ([]byte, error) { + tlogKey, _, err := config.DeserializePublicKey([]byte(sigstoreKeysMap["rekor"])) + if err != nil { + return nil, err + } + ctlogKey, _, err := config.DeserializePublicKey([]byte(sigstoreKeysMap["ctfe"])) + if err != nil { + return nil, err + } + certChain, err := config.DeserializeCertChain([]byte(sigstoreKeysMap["fulcio"])) + if err != nil { + return nil, err } trustRoot := &config.SigstoreKeys{ - CertificateAuthorities: []config.CertificateAuthority{{CertChain: []byte(sigstoreKeysMap["fulcio"])}}, - TLogs: []config.TransparencyLogInstance{{PublicKey: []byte(sigstoreKeysMap["rekor"])}}, - CTLogs: []config.TransparencyLogInstance{{PublicKey: []byte(sigstoreKeysMap["ctfe"])}}, + CertificateAuthorities: []*config.CertificateAuthority{{ + CertChain: certChain, + ValidFor: &config.TimeRange{ + Start: &config.Timestamp{}, + }, + }}, + Tlogs: []*config.TransparencyLogInstance{{ + HashAlgorithm: pbcommon.HashAlgorithm_SHA2_256, + PublicKey: tlogKey, + }}, + Ctlogs: []*config.TransparencyLogInstance{{ + HashAlgorithm: pbcommon.HashAlgorithm_SHA2_256, + PublicKey: ctlogKey, + }}, } err = populateLogIDs(trustRoot) if err != nil { - return nil, nil, nil, err - } - trustRootBytes, err := json.MarshalIndent(trustRoot, "", " ") - if err != nil { - return nil, nil, nil, err + return nil, err } - return trustRootBytes, compressed.Bytes(), rootJSON, nil + trustRootBytes := []byte(protojson.Format(trustRoot)) + return trustRootBytes, nil } diff --git a/pkg/apis/config/sigstore_keys.go b/pkg/apis/config/sigstore_keys.go index 519b8ef6..b391bd69 100644 --- a/pkg/apis/config/sigstore_keys.go +++ b/pkg/apis/config/sigstore_keys.go @@ -17,12 +17,21 @@ package config import ( "context" - "encoding/json" + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rsa" + "encoding/pem" "fmt" + "github.com/sigstore/cosign/v2/pkg/cosign" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" + pbcommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" + pbtrustroot "github.com/sigstore/protobuf-specs/gen/pb-go/trustroot/v1" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/types/known/timestamppb" corev1 "k8s.io/api/core/v1" - "knative.dev/pkg/apis" "sigs.k8s.io/yaml" ) @@ -33,81 +42,26 @@ const ( SigstoreKeysConfigName = "config-sigstore-keys" ) -// Note that these are 1:1 mapped to public API SigstoreKeys. Reasoning -// being that we may choose to serialize these differently, or use the protos -// that are defined upstream, so want to keep the public/private distinction, so -// that we can change things independend of breaking the API. Time will tell -// if this is the right call, but we can always reunify them later if we so -// want. -// TODO(vaikas): See about replacing these with the protos here once they land -// and see how easy it is to replace with protos instead of our custom defs -// above. -// https://github.com/sigstore/protobuf-specs/pull/5 -// And in particular: https://github.com/sigstore/protobuf-specs/pull/5/files#diff-b1f89b7fd3eb27b519380b092a2416f893a96fbba3f8c90cfa767e7687383ad4R70 - -// TransparencyLogInstance describes the immutable parameters from a -// transparency log. -// See https://www.rfc-editor.org/rfc/rfc9162.html#name-log-parameters -// for more details. -// The incluced parameters are the minimal set required to identify a log, -// and verify an inclusion promise. -type TransparencyLogInstance struct { - BaseURL apis.URL `json:"baseURL"` - HashAlgorithm string `json:"hashAlgorithm"` - // PEM encoded public key - PublicKey []byte `json:"publicKey"` - LogID string `json:"logID"` -} - -type DistinguishedName struct { - Organization string `json:"organization"` - CommonName string `json:"commonName"` -} - -type CertificateAuthority struct { - // The root certificate MUST be self-signed, and so the subject and - // issuer are the same. - Subject DistinguishedName `json:"subject"` - // The URI at which the CA can be accessed. - URI apis.URL `json:"uri"` - // The certificate chain for this CA. - // CertChain is in PEM format. - CertChain []byte `json:"certChain"` - - // TODO(vaikas): How to best represent this - // The time the *entire* chain was valid. This is at max the - // longest interval when *all* certificates in the chain where valid, - // but it MAY be shorter. - // dev.sigstore.common.v1.TimeRange valid_for = 4; -} +// Type aliases for types from protobuf-specs. TODO: Consider just importing +// the protobuf-specs types directly from each package as needed. // SigstoreKeys contains all the necessary Keys and Certificates for validating // against a specific instance of Sigstore. -// TODO(vaikas): See about replacing these with the protos here once they land -// and see how easy it is to replace with protos instead of our custom defs -// above. -// https://github.com/sigstore/protobuf-specs/pull/5 -// And in particular: https://github.com/sigstore/protobuf-specs/pull/5/files#diff-b1f89b7fd3eb27b519380b092a2416f893a96fbba3f8c90cfa767e7687383ad4R70 -// Well, not the multi-root, but one instance of that is exactly the -// SigstoreKeys. -type SigstoreKeys struct { - // Trusted certificate authorities (e.g Fulcio). - CertificateAuthorities []CertificateAuthority `json:"certificateAuthorities,omitempty"` - // Rekor log specifications - TLogs []TransparencyLogInstance `json:"tLogs,omitempty"` - // Certificate Transparency Log - CTLogs []TransparencyLogInstance `json:"ctLogs,omitempty"` - // Trusted timestamping authorities - TimeStampAuthorities []CertificateAuthority `json:"timestampAuthorities"` -} +type SigstoreKeys = pbtrustroot.TrustedRoot +type CertificateAuthority = pbtrustroot.CertificateAuthority +type TransparencyLogInstance = pbtrustroot.TransparencyLogInstance +type DistinguishedName = pbcommon.DistinguishedName +type LogID = pbcommon.LogId +type TimeRange = pbcommon.TimeRange +type Timestamp = timestamppb.Timestamp type SigstoreKeysMap struct { - SigstoreKeys map[string]SigstoreKeys + SigstoreKeys map[string]*SigstoreKeys } // NewSigstoreKeysFromMap creates a map of SigstoreKeys to use for validation. func NewSigstoreKeysFromMap(data map[string]string) (*SigstoreKeysMap, error) { - ret := make(map[string]SigstoreKeys, len(data)) + ret := make(map[string]*SigstoreKeys, len(data)) // Spin through the ConfigMap. Each entry will have a serialized form of // necessary validation keys in the form of SigstoreKeys. for k, v := range data { @@ -123,7 +77,7 @@ func NewSigstoreKeysFromMap(data map[string]string) (*SigstoreKeysMap, error) { if err := parseSigstoreKeys(v, sigstoreKeys); err != nil { return nil, fmt.Errorf("failed to parse the entry %q : %q : %w", k, v, err) } - ret[k] = *sigstoreKeys + ret[k] = sigstoreKeys } return &SigstoreKeysMap{SigstoreKeys: ret}, nil } @@ -133,56 +87,187 @@ func NewSigstoreKeysFromConfigMap(config *corev1.ConfigMap) (*SigstoreKeysMap, e return NewSigstoreKeysFromMap(config.Data) } -func parseSigstoreKeys(entry string, out interface{}) error { +func parseSigstoreKeys(entry string, out *pbtrustroot.TrustedRoot) error { j, err := yaml.YAMLToJSON([]byte(entry)) if err != nil { return fmt.Errorf("config's value could not be converted to JSON: %w : %s", err, entry) } - return json.Unmarshal(j, &out) + return protojson.Unmarshal(j, out) } -// ConvertFrom takes a source and converts into a SigstoreKeys suitable +// ConvertSigstoreKeys takes a source and converts into a SigstoreKeys suitable // for serialization into a ConfigMap entry. -func (sk *SigstoreKeys) ConvertFrom(_ context.Context, source *v1alpha1.SigstoreKeys) { - sk.CertificateAuthorities = make([]CertificateAuthority, len(source.CertificateAuthorities)) +func ConvertSigstoreKeys(_ context.Context, source *v1alpha1.SigstoreKeys) (sk *SigstoreKeys, err error) { + sk = &SigstoreKeys{} + sk.MediaType = "application/vnd.dev.sigstore.trustedroot+json;version=0.1" + sk.CertificateAuthorities = make([]*pbtrustroot.CertificateAuthority, len(source.CertificateAuthorities)) for i := range source.CertificateAuthorities { - sk.CertificateAuthorities[i] = ConvertCertificateAuthority(source.CertificateAuthorities[i]) + sk.CertificateAuthorities[i], err = ConvertCertificateAuthority(source.CertificateAuthorities[i]) + if err != nil { + return nil, fmt.Errorf("failed to convert certificate authority: %w", err) + } } - sk.TLogs = make([]TransparencyLogInstance, len(source.TLogs)) + sk.Tlogs = make([]*pbtrustroot.TransparencyLogInstance, len(source.TLogs)) for i := range source.TLogs { - sk.TLogs[i] = ConvertTransparencyLogInstance(source.TLogs[i]) + sk.Tlogs[i], err = ConvertTransparencyLogInstance(source.TLogs[i]) + if err != nil { + return nil, fmt.Errorf("failed to convert transparency log instance: %w", err) + } } - sk.CTLogs = make([]TransparencyLogInstance, len(source.CTLogs)) + sk.Ctlogs = make([]*pbtrustroot.TransparencyLogInstance, len(source.CTLogs)) for i := range source.CTLogs { - sk.CTLogs[i] = ConvertTransparencyLogInstance(source.CTLogs[i]) + sk.Ctlogs[i], err = ConvertTransparencyLogInstance(source.CTLogs[i]) + if err != nil { + return nil, fmt.Errorf("failed to convert ct log instance: %w", err) + } } - sk.TimeStampAuthorities = make([]CertificateAuthority, len(source.TimeStampAuthorities)) + sk.TimestampAuthorities = make([]*pbtrustroot.CertificateAuthority, len(source.TimeStampAuthorities)) for i := range source.TimeStampAuthorities { - sk.TimeStampAuthorities[i] = ConvertCertificateAuthority(source.TimeStampAuthorities[i]) + sk.TimestampAuthorities[i], err = ConvertCertificateAuthority(source.TimeStampAuthorities[i]) + if err != nil { + return nil, fmt.Errorf("failed to convert timestamp authority: %w", err) + } } + return sk, nil } // ConvertCertificateAuthority converts public into private CertificateAuthority -func ConvertCertificateAuthority(source v1alpha1.CertificateAuthority) CertificateAuthority { - return CertificateAuthority{ - Subject: DistinguishedName{ +func ConvertCertificateAuthority(source v1alpha1.CertificateAuthority) (*pbtrustroot.CertificateAuthority, error) { + certChain, err := DeserializeCertChain(source.CertChain) + if err != nil { + return nil, err + } + return &pbtrustroot.CertificateAuthority{ + Subject: &pbcommon.DistinguishedName{ Organization: source.Subject.Organization, CommonName: source.Subject.CommonName, }, - URI: *source.URI.DeepCopy(), - CertChain: source.CertChain, - } + Uri: source.URI.String(), + CertChain: certChain, + ValidFor: &pbcommon.TimeRange{ + Start: ×tamppb.Timestamp{ + Seconds: 0, // TODO: Add support for time range to v1alpha1.CertificateAuthority + }, + }, + }, nil } // ConvertTransparencyLogInstance converts public into private // TransparencyLogInstance. -func ConvertTransparencyLogInstance(source v1alpha1.TransparencyLogInstance) TransparencyLogInstance { - return TransparencyLogInstance{ - BaseURL: *source.BaseURL.DeepCopy(), - HashAlgorithm: source.HashAlgorithm, - PublicKey: source.PublicKey, +func ConvertTransparencyLogInstance(source v1alpha1.TransparencyLogInstance) (*pbtrustroot.TransparencyLogInstance, error) { + pbpk, pk, err := DeserializePublicKey(source.PublicKey) + if err != nil { + return nil, err + } + logID, err := cosign.GetTransparencyLogID(pk) + if err != nil { + return nil, err + } + + return &pbtrustroot.TransparencyLogInstance{ + BaseUrl: source.BaseURL.String(), + HashAlgorithm: HashStringToHashAlgorithm(source.HashAlgorithm), + PublicKey: pbpk, + LogId: &pbcommon.LogId{ + KeyId: []byte(logID), + }, + }, nil +} + +func HashStringToHashAlgorithm(hash string) pbcommon.HashAlgorithm { + switch hash { + case "sha-256", "sha256": + return pbcommon.HashAlgorithm_SHA2_256 + case "sha-384", "sha384": + return pbcommon.HashAlgorithm_SHA2_384 + case "sha-512", "sha512": + return pbcommon.HashAlgorithm_SHA2_512 + default: + return pbcommon.HashAlgorithm_HASH_ALGORITHM_UNSPECIFIED } } + +func SerializeCertChain(certChain *pbcommon.X509CertificateChain) []byte { + var chain []byte + for _, cert := range certChain.Certificates { + bytes := cert.RawBytes + block := &pem.Block{ + Type: "CERTIFICATE", + Bytes: bytes, + } + chain = append(chain, pem.EncodeToMemory(block)...) + } + return chain +} + +func SerializePublicKey(publicKey *pbcommon.PublicKey) []byte { + block := &pem.Block{ + Type: "PUBLIC KEY", + Bytes: publicKey.RawBytes, + } + return pem.EncodeToMemory(block) +} + +func DeserializeCertChain(chain []byte) (*pbcommon.X509CertificateChain, error) { + var certs []*pbcommon.X509Certificate + var block *pem.Block + for len(chain) > 0 { + block, chain = pem.Decode(chain) + if block == nil { + return nil, fmt.Errorf("failed to decode certificate chain PEM") + } + certs = append(certs, &pbcommon.X509Certificate{RawBytes: block.Bytes}) + } + return &pbcommon.X509CertificateChain{Certificates: certs}, nil +} + +func DeserializePublicKey(publicKey []byte) (*pbcommon.PublicKey, crypto.PublicKey, error) { + block, _ := pem.Decode(publicKey) + if block == nil { + return nil, nil, fmt.Errorf("failed to decode public key") + } + pk, err := cryptoutils.UnmarshalPEMToPublicKey(publicKey) + if err != nil { + return nil, nil, fmt.Errorf("failed to unmarshal public key: %w", err) + } + var keyDetails pbcommon.PublicKeyDetails + switch k := pk.(type) { + case *ecdsa.PublicKey: + switch k.Curve { + case elliptic.P256(): + keyDetails = pbcommon.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256 + case elliptic.P384(): + keyDetails = pbcommon.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384 + case elliptic.P521(): + keyDetails = pbcommon.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512 + default: + keyDetails = pbcommon.PublicKeyDetails_PUBLIC_KEY_DETAILS_UNSPECIFIED + } + case *rsa.PublicKey: + switch k.Size() { + case 2048: + keyDetails = pbcommon.PublicKeyDetails_PKIX_RSA_PSS_2048_SHA256 + case 3072: + keyDetails = pbcommon.PublicKeyDetails_PKIX_RSA_PSS_3072_SHA256 + case 4096: + keyDetails = pbcommon.PublicKeyDetails_PKIX_RSA_PSS_4096_SHA256 + default: + keyDetails = pbcommon.PublicKeyDetails_PUBLIC_KEY_DETAILS_UNSPECIFIED + } + default: + keyDetails = pbcommon.PublicKeyDetails_PUBLIC_KEY_DETAILS_UNSPECIFIED + } + + return &pbcommon.PublicKey{ + RawBytes: block.Bytes, + KeyDetails: keyDetails, + ValidFor: &pbcommon.TimeRange{ + Start: ×tamppb.Timestamp{ + Seconds: 0, // TODO: Add support for time range to v1alpha.TransparencyLogInstance + }, + }, + }, pk, nil +} diff --git a/pkg/apis/config/sigstore_keys_test.go b/pkg/apis/config/sigstore_keys_test.go index d6e939b3..b2360e56 100644 --- a/pkg/apis/config/sigstore_keys_test.go +++ b/pkg/apis/config/sigstore_keys_test.go @@ -15,6 +15,8 @@ package config import ( + "bytes" + "encoding/pem" "testing" . "knative.dev/pkg/configmap/testing" @@ -23,45 +25,45 @@ import ( const ( rekorPublicKey = `-----BEGIN PUBLIC KEY----- - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7D2WvgqSzs9jpdJsOJ5Nl6xg8JXm - Nmo7M3bN7+dQddw9Ibc2R3SV8tzBZw0rST8FKcn4apJepcKM4qUpYUeNfw== - -----END PUBLIC KEY----- - ` +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7D2WvgqSzs9jpdJsOJ5Nl6xg8JXm +Nmo7M3bN7+dQddw9Ibc2R3SV8tzBZw0rST8FKcn4apJepcKM4qUpYUeNfw== +-----END PUBLIC KEY----- +` tsaCertChain = `-----BEGIN CERTIFICATE----- - MIIBzDCCAXKgAwIBAgIUfyGKDoFa7y6s/W1p1CiTmBRs1eAwCgYIKoZIzj0EAwIw - MDEOMAwGA1UEChMFbG9jYWwxHjAcBgNVBAMTFVRlc3QgVFNBIEludGVybWVkaWF0 - ZTAeFw0yMjExMDkyMDMxMzRaFw0zMTExMDkyMDM0MzRaMDAxDjAMBgNVBAoTBWxv - Y2FsMR4wHAYDVQQDExVUZXN0IFRTQSBUaW1lc3RhbXBpbmcwWTATBgcqhkjOPQIB - BggqhkjOPQMBBwNCAAR3KcDy9jwARX0rDvyr+MGGkG3n1OA0MU5+ZiDmgusFyk6U - 6bovKWVMfD8J8NTcJZE0RaYJr8/dE9kgcIIXlhMwo2owaDAOBgNVHQ8BAf8EBAMC - B4AwHQYDVR0OBBYEFHNn5R3b3MtUdSNrFO49Q6XDVSnkMB8GA1UdIwQYMBaAFNLS - 6gno7Om++Qt5zIa+H9o0HiT2MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqG - SM49BAMCA0gAMEUCIQCF0olohnvdUq6T7/wPk19Z5aQP/yxRTjCWYuhn/TCyHgIg - azV3air4GRZbN9bdYtcQ7JUAKq89GOhtFfl6kcoVUvU= - -----END CERTIFICATE----- - -----BEGIN CERTIFICATE----- - MIIB0jCCAXigAwIBAgIUXpBmYJFFaGW3cC8p6b/DHr1i8IowCgYIKoZIzj0EAwIw - KDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIx - MTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAwMQ4wDAYDVQQKEwVsb2NhbDEeMBwG - A1UEAxMVVGVzdCBUU0EgSW50ZXJtZWRpYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0D - AQcDQgAEKDPDRIwDS1ZCymub6yanCG5ma0qDjLpNonDvooSkRHEgU0TNibeJn6M+ - 5W608hCw8nwuucMbXQ41kNeuBeevyqN4MHYwDgYDVR0PAQH/BAQDAgEGMBMGA1Ud - JQQMMAoGCCsGAQUFBwMIMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNLS6gno - 7Om++Qt5zIa+H9o0HiT2MB8GA1UdIwQYMBaAFB1nvXpNK7AuQlbJ+ya6nPSqWi+T - MAoGCCqGSM49BAMCA0gAMEUCIGiwqCI29w7C4V8TltCsi728s5DtklCPySDASUSu - a5y5AiEA40Ifdlwf7Uj8q8NSD6Z4g/0js0tGNdLSUJ1do/WoN0s= - -----END CERTIFICATE----- - -----BEGIN CERTIFICATE----- - MIIBlDCCATqgAwIBAgIUYZx9sS14En7SuHDOJJP4IPopMjUwCgYIKoZIzj0EAwIw - KDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIx - MTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQG - A1UEAxMNVGVzdCBUU0EgUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAbB - B0SU8G75hVIUphChA4nfOwNWP347TjScIdsEPrKVn+/Y1HmmLHJDjSfn+xhEFoEk - 7jqgrqon48i4xbo7xAujQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD - AQH/MB0GA1UdDgQWBBQdZ716TSuwLkJWyfsmupz0qlovkzAKBggqhkjOPQQDAgNI - ADBFAiBe5P56foqmFcZAVpEeAOFZrAlEiq05CCpMNYh5EjLvmAIhAKNF6xIV5uFd - pSTJsAwzjW78CKQm7qol0uPmPPu6mNaw - -----END CERTIFICATE-----` +MIIBzDCCAXKgAwIBAgIUfyGKDoFa7y6s/W1p1CiTmBRs1eAwCgYIKoZIzj0EAwIw +MDEOMAwGA1UEChMFbG9jYWwxHjAcBgNVBAMTFVRlc3QgVFNBIEludGVybWVkaWF0 +ZTAeFw0yMjExMDkyMDMxMzRaFw0zMTExMDkyMDM0MzRaMDAxDjAMBgNVBAoTBWxv +Y2FsMR4wHAYDVQQDExVUZXN0IFRTQSBUaW1lc3RhbXBpbmcwWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAAR3KcDy9jwARX0rDvyr+MGGkG3n1OA0MU5+ZiDmgusFyk6U +6bovKWVMfD8J8NTcJZE0RaYJr8/dE9kgcIIXlhMwo2owaDAOBgNVHQ8BAf8EBAMC +B4AwHQYDVR0OBBYEFHNn5R3b3MtUdSNrFO49Q6XDVSnkMB8GA1UdIwQYMBaAFNLS +6gno7Om++Qt5zIa+H9o0HiT2MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqG +SM49BAMCA0gAMEUCIQCF0olohnvdUq6T7/wPk19Z5aQP/yxRTjCWYuhn/TCyHgIg +azV3air4GRZbN9bdYtcQ7JUAKq89GOhtFfl6kcoVUvU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB0jCCAXigAwIBAgIUXpBmYJFFaGW3cC8p6b/DHr1i8IowCgYIKoZIzj0EAwIw +KDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIx +MTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAwMQ4wDAYDVQQKEwVsb2NhbDEeMBwG +A1UEAxMVVGVzdCBUU0EgSW50ZXJtZWRpYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0D +AQcDQgAEKDPDRIwDS1ZCymub6yanCG5ma0qDjLpNonDvooSkRHEgU0TNibeJn6M+ +5W608hCw8nwuucMbXQ41kNeuBeevyqN4MHYwDgYDVR0PAQH/BAQDAgEGMBMGA1Ud +JQQMMAoGCCsGAQUFBwMIMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNLS6gno +7Om++Qt5zIa+H9o0HiT2MB8GA1UdIwQYMBaAFB1nvXpNK7AuQlbJ+ya6nPSqWi+T +MAoGCCqGSM49BAMCA0gAMEUCIGiwqCI29w7C4V8TltCsi728s5DtklCPySDASUSu +a5y5AiEA40Ifdlwf7Uj8q8NSD6Z4g/0js0tGNdLSUJ1do/WoN0s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBlDCCATqgAwIBAgIUYZx9sS14En7SuHDOJJP4IPopMjUwCgYIKoZIzj0EAwIw +KDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIx +MTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQG +A1UEAxMNVGVzdCBUU0EgUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAbB +B0SU8G75hVIUphChA4nfOwNWP347TjScIdsEPrKVn+/Y1HmmLHJDjSfn+xhEFoEk +7jqgrqon48i4xbo7xAujQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBQdZ716TSuwLkJWyfsmupz0qlovkzAKBggqhkjOPQQDAgNI +ADBFAiBe5P56foqmFcZAVpEeAOFZrAlEiq05CCpMNYh5EjLvmAIhAKNF6xIV5uFd +pSTJsAwzjW78CKQm7qol0uPmPPu6mNaw +-----END CERTIFICATE-----` ) func TestDefaultsSigstoreKeysConfigurationFromFile(t *testing.T) { @@ -71,21 +73,25 @@ func TestDefaultsSigstoreKeysConfigurationFromFile(t *testing.T) { t.Error("NewSigstoreKeysFromConfigMap(example) =", err) } sigstoreKeys := keysMap.SigstoreKeys["my-custom-sigstore-keys"] - got := sigstoreKeys.CertificateAuthorities[0].Subject.Organization - if got != "fulcio-organization" { - t.Errorf("Invalid organization, want foo got %s", got) + org := sigstoreKeys.CertificateAuthorities[0].Subject.Organization + if org != "fulcio-organization" { + t.Errorf("Invalid organization, want foo got %s", org) } // TODO: Validate the entire file, above spot checks are not enough, but // at least we can unmarshal. // Note that even though sigstoreKeys.TLog[0].PublicKey is base64 encoded // in the ConfigMap it gets decoded when we fetch it above, so we get the // PEM format for it directly. Same for tsaCertChain - got = string(sigstoreKeys.TLogs[0].PublicKey) - if got != rekorPublicKey { - t.Errorf("Invalid public key, want %s got %s", rekorPublicKey, got) + got := sigstoreKeys.Tlogs[0].PublicKey.RawBytes + block, _ := pem.Decode([]byte(rekorPublicKey)) + if !bytes.Equal(got, block.Bytes) { + t.Errorf("Invalid public key, want %s got %s", block.Bytes, got) } - got = string(sigstoreKeys.TimeStampAuthorities[0].CertChain) - if got != tsaCertChain { - t.Errorf("Invalid cert chain, want %s got %s", tsaCertChain, got) + certs := []byte(tsaCertChain) + for _, cert := range sigstoreKeys.TimestampAuthorities[0].CertChain.Certificates { + block, certs = pem.Decode(certs) + if !bytes.Equal(block.Bytes, cert.RawBytes) { + t.Errorf("Invalid cert chain, want %s got %s", cert.RawBytes, block.Bytes) + } } } diff --git a/pkg/apis/config/store_test.go b/pkg/apis/config/store_test.go index 4be73357..b9fe3101 100644 --- a/pkg/apis/config/store_test.go +++ b/pkg/apis/config/store_test.go @@ -21,6 +21,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/sigstore/cosign/v2/pkg/oci/remote" + "google.golang.org/protobuf/testing/protocmp" "k8s.io/apimachinery/pkg/api/resource" logtesting "knative.dev/pkg/logging/testing" @@ -28,6 +29,7 @@ import ( ) var ignoreStuff = cmp.Options{ + protocmp.Transform(), cmpopts.IgnoreUnexported(resource.Quantity{}), // Ignore functional remote options cmpopts.IgnoreTypes((remote.Option)(nil)), diff --git a/pkg/apis/config/testdata/config-sigstore-keys.yaml b/pkg/apis/config/testdata/config-sigstore-keys.yaml index 008f7ce2..52a14cb8 100644 --- a/pkg/apis/config/testdata/config-sigstore-keys.yaml +++ b/pkg/apis/config/testdata/config-sigstore-keys.yaml @@ -28,4 +28,5 @@ data: # # ################################ my-custom-sigstore-keys: |- - {"certificateAuthorities":[{"subject":{"organization":"fulcio-organization","commonName":"fulcio-common-name"},"uri":"https://fulcio.example.com","certChain":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCglNSUlGd3pDQ0E2dWdBd0lCQWdJSUs3eGIrcnFZNGdFd0RRWUpLb1pJaHZjTkFRRUxCUUF3ZmpFTU1Bb0dBMVVFCglCaE1EVlZOQk1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGhNUll3RkFZRFZRUUhFdzFUWVc0Z1JuSmhibU5wCgljMk52TVJZd0ZBWURWUVFKRXcwMU5EZ2dUV0Z5YTJWMElGTjBNUTR3REFZRFZRUVJFd1UxTnpJM05ERVpNQmNHCglBMVVFQ2hNUVRHbHVkWGdnUm05MWJtUmhkR2x2YmpBZUZ3MHlNakV5TURnd01qRTNOVEZhRncweU16RXlNRGd3CglNakUzTlRGYU1INHhEREFLQmdOVkJBWVRBMVZUUVRFVE1CRUdBMVVFQ0JNS1EyRnNhV1p2Y201cFlURVdNQlFHCglBMVVFQnhNTlUyRnVJRVp5WVc1amFYTmpiekVXTUJRR0ExVUVDUk1OTlRRNElFMWhjbXRsZENCVGRERU9NQXdHCglBMVVFRVJNRk5UY3lOelF4R1RBWEJnTlZCQW9URUV4cGJuVjRJRVp2ZFc1a1lYUnBiMjR3Z2dJaU1BMEdDU3FHCglTSWIzRFFFQkFRVUFBNElDRHdBd2dnSUtBb0lDQVFDMTQyRWpsZzJReEl3cE5qYmFlVy9mdDlzSDFUWFU2Q1dnCglic3ZWcDc3dlJnY2tTbnBNM1JUQy9nd0V3Skh0WCtHT1RyUDlybzZuRkpOM0czaGNGbmFNSExLZEdyb2Y5aUh1Cgkvdy9sWkx3UXpYelZUKzBaeVp4eXRIQVdHRkJ2bVlNNEozM2pINkRqOVB2cU9Od3RTQlNtWkJQYy9ILzhFdllzCglVenhQV3VraE90b3RTSDNWWERxWjRqbDk2TUxlMCs1ZzJXaTdNeFJYNDRYMVJpUFMxNGJhMUVTNTM4YlRoaGNRCgk0U01qM3VoYmRzQ0lrY203ZUY0RVkzcEVYUXBYRUVHblpHZndZZ1FyKzZjVDA3WmQvV0RNME5YM0t4SDZxUms5CglnRGpQbmZjTXVGYk9UYmZEL251dng2Rk5YNk9VcnpyWlNnbGtMdmNQSUJWT1c3TG40MUxBYjdhWG1iV0xGRUpuCgl1TG9vUHBZWXIrNk5obkZETkdwc0JLR0tyL2t2YlF5REtLc3QzQ0tqOW90UFMxMzYzbmk0MXFub0E3WVdTcXh3Cgl6NDE4NWRLS2MrWTd5dkpRc1JscjZxRzFzTkxPK2M3N2ZTUzVWWkltek5vekJjUmt1TEpGbFgrV0IwdXpnUVU1CglzNDVJWlcrZks5Mm5mdThNbUtqekhSK2lkeXI0T3lqUzBZU04zR01nYzBVUDdLNmhWcGhMZWRBcEZweWtCU0ZHCglVZ2lQWndyVCttR1NWZ21PWHE1bjFkUVRDRDE0bEVoMnF0My9yZmY4ek5jMENNQU5XeWJhTUdCR1E0YmhWVlhlCglSS1l4OXUyUFpqUHY1M3A3WWIvRENkcW5HRUR3L0hDQkRpQ3M0b1llNGRhRTM2eFVvanhEU20zRGFlTkc2OHo5CglSTDdnZlVqQXhRSURBUUFCbzBVd1F6QU9CZ05WSFE4QkFmOEVCQU1DQVFZd0VnWURWUjBUQVFIL0JBZ3dCZ0VCCgkvd0lCQVRBZEJnTlZIUTRFRmdRVWYrbGJOWDBXaDRoK1EwU1J0aFJLK0tmTGpxRXdEUVlKS29aSWh2Y05BUUVMCglCUUFEZ2dJQkFFaEpqYTBaU0t3WGNhT1hDWVJYVEUwNitKYnBlekk1TGV2QmhtYlJRSzc4OVJxMTBKZUFYYTdtCglFVG9SR2xHRkxIMnVEVDExbXNGS3lNM3Y2N0tsRTFTWVZjcUttQ2xZZklWRVlIM0xhMHVJKzlySFpuV2diNEJsCgl5MUI4d2JsS0p6aFlRRDlaNEgvZ3MrQkFzb1JYNVZvRnlJZ2tOQmsxcDNmdGFWQ2JrUXZTME9ZdFlzNWl3NGVLCgljSTcxL0lzVElUM1pwcGo5UjhJR3Nxd0xLZ3pmbnlOY0ZKZHorb2hjNlYyMlBqWk1FQkhDc0hQTzRhdjJMbFdLCgk1WTFmbEwrMmJxVHFibU8vYmpmWDB3NFoxRHVvalJjT1pGN1NINE8zUXUyWTcvNjlnSDdDcDBuaVZDbTV6K1M1CgkwMTFWNlB2TWpybWlFK3hWa3hMSGJZRWdvY2JGaGQ1RGNpTUNYcHZzdURab2phSTNGUkVtQnFpSWhLb2tpM3JiCgl3dUVseWE3OGJNd2taMWtycDc2bldzbzQ3LzArNTFpby9XcmlBZHIwY2ptem9uaG83UnFJRTNEQzc3Q0VNa2FnCgladktTbUwzc2ZmK1dOU3JuUGx6bksxOU5BMno0SW1XOU1zenFQckNUUUdQLy9CQnU3U2Ftem9mVk05ZjRQQUlyCglGVHBuVzZzR2RwQ3pQOEUwV1V1OUIrdmlLcnRmTS85c3huSTlXaGZKUGRyRVAwaVpXM3Zod3ZnUWJLYjVEMk9TCglVNG5yVm92NkJXci9CbmhRSzhJWG8xdHEzajhGQ1JJb2xlWE5oa3M0Z25rT2FEc1cyS3RWcXd0SzNpTzNCdlBiCglMNXcwZ2RMandNTGtlazcyeTYxWHF6NVd4WndOaGw1WWNtQkt1U3ZtVlNIdkE2OEJWU2JCCgktLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgk="}],"tLogs":[{"baseURL":"https://rekor.example.com","hashAlgorithm":"sha-256","publicKey":"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KCU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTdEMld2Z3FTenM5anBkSnNPSjVObDZ4ZzhKWG0KCU5tbzdNM2JONytkUWRkdzlJYmMyUjNTVjh0ekJadzByU1Q4RktjbjRhcEplcGNLTTRxVXBZVWVOZnc9PQoJLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCgk=","logID":"0bac0fddd0c15fbc46f8b1bf51c2b57676a9f262294fe13417d85602e73f392a"}],"ctLogs":[{"baseURL":"https://ctfe.example.com","hashAlgorithm":"sha-256","publicKey":"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KCU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRUp2Q0ppNzA3ZnY1dE1KMVUyVFZNWit1TzRkS0cKCWFFY3ZqbENrZ0JDS1hicmt1bVpWMG0wZFNsSzFWMWd4RWl5UTh5NmhrMU14Sk5lMkFaclpVdDdhNHc9PQoJLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCgk=","logID":"39d1c085f7d5f3fe7a0de9e52a3ead14186891e52a9269d90de7990a30b55083"}],"timestampAuthorities":[{"subject":{"organization":"tsa-organization","commonName":"tsa-common-name"},"uri":"https://tsa.example.com","certChain":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCglNSUlCekRDQ0FYS2dBd0lCQWdJVWZ5R0tEb0ZhN3k2cy9XMXAxQ2lUbUJSczFlQXdDZ1lJS29aSXpqMEVBd0l3CglNREVPTUF3R0ExVUVDaE1GYkc5allXd3hIakFjQmdOVkJBTVRGVlJsYzNRZ1ZGTkJJRWx1ZEdWeWJXVmthV0YwCglaVEFlRncweU1qRXhNRGt5TURNeE16UmFGdzB6TVRFeE1Ea3lNRE0wTXpSYU1EQXhEakFNQmdOVkJBb1RCV3h2CglZMkZzTVI0d0hBWURWUVFERXhWVVpYTjBJRlJUUVNCVWFXMWxjM1JoYlhCcGJtY3dXVEFUQmdjcWhrak9QUUlCCglCZ2dxaGtqT1BRTUJCd05DQUFSM0tjRHk5andBUlgwckR2eXIrTUdHa0czbjFPQTBNVTUrWmlEbWd1c0Z5azZVCgk2Ym92S1dWTWZEOEo4TlRjSlpFMFJhWUpyOC9kRTlrZ2NJSVhsaE13bzJvd2FEQU9CZ05WSFE4QkFmOEVCQU1DCglCNEF3SFFZRFZSME9CQllFRkhObjVSM2IzTXRVZFNOckZPNDlRNlhEVlNua01COEdBMVVkSXdRWU1CYUFGTkxTCgk2Z25vN09tKytRdDV6SWErSDlvMEhpVDJNQllHQTFVZEpRRUIvd1FNTUFvR0NDc0dBUVVGQndNSU1Bb0dDQ3FHCglTTTQ5QkFNQ0EwZ0FNRVVDSVFDRjBvbG9obnZkVXE2VDcvd1BrMTlaNWFRUC95eFJUakNXWXVobi9UQ3lIZ0lnCglhelYzYWlyNEdSWmJOOWJkWXRjUTdKVUFLcTg5R09odEZmbDZrY29WVXZVPQoJLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoJLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCglNSUlCMGpDQ0FYaWdBd0lCQWdJVVhwQm1ZSkZGYUdXM2NDOHA2Yi9ESHIxaThJb3dDZ1lJS29aSXpqMEVBd0l3CglLREVPTUF3R0ExVUVDaE1GYkc5allXd3hGakFVQmdOVkJBTVREVlJsYzNRZ1ZGTkJJRkp2YjNRd0hoY05Nakl4CglNVEE1TWpBeU9UTTBXaGNOTXpJeE1UQTVNakF6TkRNMFdqQXdNUTR3REFZRFZRUUtFd1ZzYjJOaGJERWVNQndHCglBMVVFQXhNVlZHVnpkQ0JVVTBFZ1NXNTBaWEp0WldScFlYUmxNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBECglBUWNEUWdBRUtEUERSSXdEUzFaQ3ltdWI2eWFuQ0c1bWEwcURqTHBOb25Edm9vU2tSSEVnVTBUTmliZUpuNk0rCgk1VzYwOGhDdzhud3V1Y01iWFE0MWtOZXVCZWV2eXFONE1IWXdEZ1lEVlIwUEFRSC9CQVFEQWdFR01CTUdBMVVkCglKUVFNTUFvR0NDc0dBUVVGQndNSU1BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZOTFM2Z25vCgk3T20rK1F0NXpJYStIOW8wSGlUMk1COEdBMVVkSXdRWU1CYUFGQjFudlhwTks3QXVRbGJKK3lhNm5QU3FXaStUCglNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJR2l3cUNJMjl3N0M0VjhUbHRDc2k3MjhzNUR0a2xDUHlTREFTVVN1CglhNXk1QWlFQTQwSWZkbHdmN1VqOHE4TlNENlo0Zy8wanMwdEdOZExTVUoxZG8vV29OMHM9CgktLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgktLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KCU1JSUJsRENDQVRxZ0F3SUJBZ0lVWVp4OXNTMTRFbjdTdUhET0pKUDRJUG9wTWpVd0NnWUlLb1pJemowRUF3SXcKCUtERU9NQXdHQTFVRUNoTUZiRzlqWVd3eEZqQVVCZ05WQkFNVERWUmxjM1FnVkZOQklGSnZiM1F3SGhjTk1qSXgKCU1UQTVNakF5T1RNMFdoY05Nekl4TVRBNU1qQXpORE0wV2pBb01RNHdEQVlEVlFRS0V3VnNiMk5oYkRFV01CUUcKCUExVUVBeE1OVkdWemRDQlVVMEVnVW05dmREQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJBYkIKCUIwU1U4Rzc1aFZJVXBoQ2hBNG5mT3dOV1AzNDdUalNjSWRzRVByS1ZuKy9ZMUhtbUxISkRqU2ZuK3hoRUZvRWsKCTdqcWdycW9uNDhpNHhibzd4QXVqUWpCQU1BNEdBMVVkRHdFQi93UUVBd0lCQmpBUEJnTlZIUk1CQWY4RUJUQUQKCUFRSC9NQjBHQTFVZERnUVdCQlFkWjcxNlRTdXdMa0pXeWZzbXVwejBxbG92a3pBS0JnZ3Foa2pPUFFRREFnTkkKCUFEQkZBaUJlNVA1NmZvcW1GY1pBVnBFZUFPRlpyQWxFaXEwNUNDcE1OWWg1RWpMdm1BSWhBS05GNnhJVjV1RmQKCXBTVEpzQXd6alc3OENLUW03cW9sMHVQbVBQdTZtTmF3CgktLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t"}]} + {"certificateAuthorities":[{"subject":{"organization":"fulcio-organization","commonName":"fulcio-common-name"},"uri":"https://fulcio.example.com","certChain":{"certificates":[{"rawBytes":"MIIFwzCCA6ugAwIBAgIIK7xb+rqY4gEwDQYJKoZIhvcNAQELBQAwfjEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRYwFAYDVQQJEw01NDggTWFya2V0IFN0MQ4wDAYDVQQREwU1NzI3NDEZMBcGA1UEChMQTGludXggRm91bmRhdGlvbjAeFw0yMjEyMDgwMjE3NTFaFw0yMzEyMDgwMjE3NTFaMH4xDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEWMBQGA1UECRMNNTQ4IE1hcmtldCBTdDEOMAwGA1UEERMFNTcyNzQxGTAXBgNVBAoTEExpbnV4IEZvdW5kYXRpb24wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC142Ejlg2QxIwpNjbaeW/ft9sH1TXU6CWgbsvVp77vRgckSnpM3RTC/gwEwJHtX+GOTrP9ro6nFJN3G3hcFnaMHLKdGrof9iHu/w/lZLwQzXzVT+0ZyZxytHAWGFBvmYM4J33jH6Dj9PvqONwtSBSmZBPc/H/8EvYsUzxPWukhOtotSH3VXDqZ4jl96MLe0+5g2Wi7MxRX44X1RiPS14ba1ES538bThhcQ4SMj3uhbdsCIkcm7eF4EY3pEXQpXEEGnZGfwYgQr+6cT07Zd/WDM0NX3KxH6qRk9gDjPnfcMuFbOTbfD/nuvx6FNX6OUrzrZSglkLvcPIBVOW7Ln41LAb7aXmbWLFEJnuLooPpYYr+6NhnFDNGpsBKGKr/kvbQyDKKst3CKj9otPS1363ni41qnoA7YWSqxwz4185dKKc+Y7yvJQsRlr6qG1sNLO+c77fSS5VZImzNozBcRkuLJFlX+WB0uzgQU5s45IZW+fK92nfu8MmKjzHR+idyr4OyjS0YSN3GMgc0UP7K6hVphLedApFpykBSFGUgiPZwrT+mGSVgmOXq5n1dQTCD14lEh2qt3/rff8zNc0CMANWybaMGBGQ4bhVVXeRKYx9u2PZjPv53p7Yb/DCdqnGEDw/HCBDiCs4oYe4daE36xUojxDSm3DaeNG68z9RL7gfUjAxQIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUf+lbNX0Wh4h+Q0SRthRK+KfLjqEwDQYJKoZIhvcNAQELBQADggIBAEhJja0ZSKwXcaOXCYRXTE06+JbpezI5LevBhmbRQK789Rq10JeAXa7mEToRGlGFLH2uDT11msFKyM3v67KlE1SYVcqKmClYfIVEYH3La0uI+9rHZnWgb4Bly1B8wblKJzhYQD9Z4H/gs+BAsoRX5VoFyIgkNBk1p3ftaVCbkQvS0OYtYs5iw4eKcI71/IsTIT3Zppj9R8IGsqwLKgzfnyNcFJdz+ohc6V22PjZMEBHCsHPO4av2LlWK5Y1flL+2bqTqbmO/bjfX0w4Z1DuojRcOZF7SH4O3Qu2Y7/69gH7Cp0niVCm5z+S5011V6PvMjrmiE+xVkxLHbYEgocbFhd5DciMCXpvsuDZojaI3FREmBqiIhKoki3rbwuElya78bMwkZ1krp76nWso47/0+51io/WriAdr0cjmzonho7RqIE3DC77CEMkagZvKSmL3sff+WNSrnPlznK19NA2z4ImW9MszqPrCTQGP//BBu7SamzofVM9f4PAIrFTpnW6sGdpCzP8E0WUu9B+viKrtfM/9sxnI9WhfJPdrEP0iZW3vhwvgQbKb5D2OSU4nrVov6BWr/BnhQK8IXo1tq3j8FCRIoleXNhks4gnkOaDsW2KtVqwtK3iO3BvPbL5w0gdLjwMLkek72y61Xqz5WxZwNhl5YcmBKuSvmVSHvA68BVSbB"}]},"validFor":{"start":"2024-01-01T00:00:00Z"}}],"tlogs":[{"baseUrl":"https://rekor.example.com","hashAlgorithm":"SHA2_256","publicKey":{"rawBytes":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7D2WvgqSzs9jpdJsOJ5Nl6xg8JXmNmo7M3bN7+dQddw9Ibc2R3SV8tzBZw0rST8FKcn4apJepcKM4qUpYUeNfw==","keyDetails":"PKIX_ECDSA_P256_SHA_256","validFor":{"start":"2024-01-01T00:00:00Z"}},"logId":{"keyId":"0bac0fddd0c15fbc46f8b1bf51c2b57676a9f262294fe13417d85602e73f392a"}}],"ctlogs":[{"baseUrl":"https://ctfe.example.com","hashAlgorithm":"SHA2_256","publicKey":{"rawBytes":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJvCJi707fv5tMJ1U2TVMZ+uO4dKGaEcvjlCkgBCKXbrkumZV0m0dSlK1V1gxEiyQ8y6hk1MxJNe2AZrZUt7a4w==","keyDetails":"PKIX_ECDSA_P256_SHA_256","validFor":{"start":"2024-01-01T00:00:00Z"}},"logId":{"keyId":"39d1c085f7d5f3fe7a0de9e52a3ead14186891e52a9269d90de7990a30b55083"}}],"timestampAuthorities":[{"subject":{"organization":"tsa-organization","commonName":"tsa-common-name"},"uri":"https://tsa.example.com","certChain":{"certificates":[{"rawBytes":"MIIBzDCCAXKgAwIBAgIUfyGKDoFa7y6s/W1p1CiTmBRs1eAwCgYIKoZIzj0EAwIwMDEOMAwGA1UEChMFbG9jYWwxHjAcBgNVBAMTFVRlc3QgVFNBIEludGVybWVkaWF0ZTAeFw0yMjExMDkyMDMxMzRaFw0zMTExMDkyMDM0MzRaMDAxDjAMBgNVBAoTBWxvY2FsMR4wHAYDVQQDExVUZXN0IFRTQSBUaW1lc3RhbXBpbmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR3KcDy9jwARX0rDvyr+MGGkG3n1OA0MU5+ZiDmgusFyk6U6bovKWVMfD8J8NTcJZE0RaYJr8/dE9kgcIIXlhMwo2owaDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFHNn5R3b3MtUdSNrFO49Q6XDVSnkMB8GA1UdIwQYMBaAFNLS6gno7Om++Qt5zIa+H9o0HiT2MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqGSM49BAMCA0gAMEUCIQCF0olohnvdUq6T7/wPk19Z5aQP/yxRTjCWYuhn/TCyHgIgazV3air4GRZbN9bdYtcQ7JUAKq89GOhtFfl6kcoVUvU="},{"rawBytes":"MIIB0jCCAXigAwIBAgIUXpBmYJFFaGW3cC8p6b/DHr1i8IowCgYIKoZIzj0EAwIwKDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIxMTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAwMQ4wDAYDVQQKEwVsb2NhbDEeMBwGA1UEAxMVVGVzdCBUU0EgSW50ZXJtZWRpYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKDPDRIwDS1ZCymub6yanCG5ma0qDjLpNonDvooSkRHEgU0TNibeJn6M+5W608hCw8nwuucMbXQ41kNeuBeevyqN4MHYwDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNLS6gno7Om++Qt5zIa+H9o0HiT2MB8GA1UdIwQYMBaAFB1nvXpNK7AuQlbJ+ya6nPSqWi+TMAoGCCqGSM49BAMCA0gAMEUCIGiwqCI29w7C4V8TltCsi728s5DtklCPySDASUSua5y5AiEA40Ifdlwf7Uj8q8NSD6Z4g/0js0tGNdLSUJ1do/WoN0s="},{"rawBytes":"MIIBlDCCATqgAwIBAgIUYZx9sS14En7SuHDOJJP4IPopMjUwCgYIKoZIzj0EAwIwKDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIxMTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQGA1UEAxMNVGVzdCBUU0EgUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAbBB0SU8G75hVIUphChA4nfOwNWP347TjScIdsEPrKVn+/Y1HmmLHJDjSfn+xhEFoEk7jqgrqon48i4xbo7xAujQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQdZ716TSuwLkJWyfsmupz0qlovkzAKBggqhkjOPQQDAgNIADBFAiBe5P56foqmFcZAVpEeAOFZrAlEiq05CCpMNYh5EjLvmAIhAKNF6xIV5uFdpSTJsAwzjW78CKQm7qol0uPmPPu6mNaw"}]},"validFor":{"start":"2024-01-01T00:00:00Z"}}]} + diff --git a/pkg/reconciler/trustroot/resources/configmap.go b/pkg/reconciler/trustroot/resources/configmap.go index 685777f4..051048ed 100644 --- a/pkg/reconciler/trustroot/resources/configmap.go +++ b/pkg/reconciler/trustroot/resources/configmap.go @@ -15,10 +15,10 @@ package resources import ( - "encoding/json" "fmt" "github.com/sigstore/policy-controller/pkg/apis/config" + "google.golang.org/protobuf/encoding/protojson" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis/duck" @@ -83,7 +83,7 @@ func CreateRemovePatch(ns, name string, cm *corev1.ConfigMap, tkName string) ([] } func Marshal(spec *config.SigstoreKeys) (string, error) { - bytes, err := json.Marshal(spec) + bytes, err := protojson.Marshal(spec) if err != nil { return "", err } diff --git a/pkg/reconciler/trustroot/testdata/ctfeLogID.txt b/pkg/reconciler/trustroot/testdata/ctfeLogID.txt index fe4d37d5..6e92256b 100644 --- a/pkg/reconciler/trustroot/testdata/ctfeLogID.txt +++ b/pkg/reconciler/trustroot/testdata/ctfeLogID.txt @@ -1 +1 @@ -83e749763552c099b251d441566b9c12f160b24fbff28ab08d2681757d8acbde \ No newline at end of file +1710e23da0651aaa8194bc9652cd00a97c1fda9c76fce12f14eb635e42036954 \ No newline at end of file diff --git a/pkg/reconciler/trustroot/testdata/ctfePublicKey.pem b/pkg/reconciler/trustroot/testdata/ctfePublicKey.pem index fb91a0d3..ea57536c 100644 --- a/pkg/reconciler/trustroot/testdata/ctfePublicKey.pem +++ b/pkg/reconciler/trustroot/testdata/ctfePublicKey.pem @@ -1,4 +1,4 @@ -----BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZ4cgFaCk7JtO/wxDw2E1S3U+97F0 -2dF2fixniThvXgbxAQ+bkQ4dQUNwN46QcCzwYuJc9742Vi6LvNx7X7427A== +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBQY7A479x/VleGrvxp1gQAykOZMj +ld4J6VWVLnN0WLiqOesr9QkSBVnBkYKw0pr6Bgr8Qjg6NA3x470DLPxrDQ== -----END PUBLIC KEY----- diff --git a/pkg/reconciler/trustroot/testdata/fulcioCertChain.pem b/pkg/reconciler/trustroot/testdata/fulcioCertChain.pem index 59e6d653..4b10e30d 100644 --- a/pkg/reconciler/trustroot/testdata/fulcioCertChain.pem +++ b/pkg/reconciler/trustroot/testdata/fulcioCertChain.pem @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIBPjCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0 -MDMyMTIxMzcwNVoXDTM0MDMyMTIxMzcwNVowDzENMAsGA1UEAxMEbGVhZjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABNnZTptnN0TWM6BRIPn/KLgo2u/W5Vt8lmOM -6xYfr1uXobdkmcUI+qMxAmXhOHDhcXgQKlgZuivcd8XwmOlpQ0SjMzAxMA4GA1Ud -DwEB/wQEAwIGwDAfBgNVHSMEGDAWgBRz6KN30XFdWO9mNjwtziSnqItmEjAKBggq -hkjOPQQDAgNJADBGAiEA9dnInoX3QVoKbqGohmvuHjcw3SLi3cYMkMCGyLI3sioC -IQDqFTNB7UGQG2HCCXoGO+hHd1uCDEz2i+56JDXYSiKnOQ== +MIIBPTCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0 +MDMyMjIwNDczOVoXDTM0MDMyMjIwNDczOVowDzENMAsGA1UEAxMEbGVhZjBZMBMG +ByqGSM49AgEGCCqGSM49AwEHA0IABNr99Dzn4PLhw3a9dP8YLwZaPnm3hpF3vt/5 +5rMc7N194IPRB+qCDQIKIsyFMQ937IA+ylxdYvwYPB30kw/nie+jMzAxMA4GA1Ud +DwEB/wQEAwIGwDAfBgNVHSMEGDAWgBSgpcC8Rht4JttKz/d6pqb87A+f+zAKBggq +hkjOPQQDAgNIADBFAiEAtuSOJ8LaCp6OrUIo8eKz7iYFEeOMI5d3aBEUSUp8y64C +IHnTyu87fhXigrwrrhx0mEluHBfqeBpJilenwWjcUzYT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIBSjCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0 -MDMyMTIxMzcwNVoXDTM0MDMyMTIxMzcwNVowDTELMAkGA1UEAxMCY2EwWTATBgcq -hkjOPQIBBggqhkjOPQMBBwNCAAREu5I6L0ARFHjrcT+YWXuKOyo57mqOB6mCz74o -4Puipf3w8Ciuh9tnN2I1FlZ+gL3j9RKn613E399EUHkjpOoro0IwQDAOBgNVHQ8B -Af8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc+ijd9FxXVjvZjY8 -Lc4kp6iLZhIwCgYIKoZIzj0EAwIDSAAwRQIgGpcv3B78/j4Ru+AqVA934rCGqM/X -83pUXjS4/PUsP3UCIQDlosQuYkks7zlgY7rCYMF6Nqo/1OvTOwy9V2yY3v0a4A== +MIIBSTCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0 +MDMyMjIwNDczOVoXDTM0MDMyMjIwNDczOVowDTELMAkGA1UEAxMCY2EwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAATpp0ZNVPLAIzjTPkYzluuwuJxo4kmCLQRmznmz +9GE89huCeLhyLbgj6xLgLrlZPwEnlGRKdiba+pLxUzKVKTPAo0IwQDAOBgNVHQ8B +Af8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoKXAvEYbeCbbSs/3 +eqam/OwPn/swCgYIKoZIzj0EAwIDRwAwRAIgPpFwR+kjxrG75XPEQCiKPwF1Zg55 +FZVT7PlNJKyIPYACIFMMqZ4//ncJoBxMtvTsr3++2d91SPpyis2cLiDcr3kW -----END CERTIFICATE----- diff --git a/pkg/reconciler/trustroot/testdata/marshalledEntry.json b/pkg/reconciler/trustroot/testdata/marshalledEntry.json index 0945662c..e9fc1f2e 100644 --- a/pkg/reconciler/trustroot/testdata/marshalledEntry.json +++ b/pkg/reconciler/trustroot/testdata/marshalledEntry.json @@ -1,38 +1,79 @@ { - "certificateAuthorities": [ + "mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1", + "tlogs": [ { - "subject": { - "organization": "fulcio-organization", - "commonName": "fulcio-common-name" + "baseUrl": "https://rekor.example.com", + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Vobk4rjNzYrf/uqDwEd/HDfCro89r63DaHCTRYQJaf/JHdJj/nxBl1e3ZCo0B7kB/uU+e7d56A9gPdelFc51g==", + "keyDetails": "PKIX_ECDSA_P256_SHA_256", + "validFor": { + "start": "1970-01-01T00:00:00Z" + } }, - "uri": "https://fulcio.example.com", - "certChain": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCNUtBREFnRUNBZ0VDTUFvR0NDcUdTTTQ5QkFNQ01BMHhDekFKQmdOVkJBTVRBbU5oTUI0WERUSTAKTURNeU1USXhNemN3TlZvWERUTTBNRE15TVRJeE16Y3dOVm93RHpFTk1Bc0dBMVVFQXhNRWJHVmhaakJaTUJNRwpCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk5uWlRwdG5OMFRXTTZCUklQbi9LTGdvMnUvVzVWdDhsbU9NCjZ4WWZyMXVYb2Jka21jVUkrcU14QW1YaE9IRGhjWGdRS2xnWnVpdmNkOFh3bU9scFEwU2pNekF4TUE0R0ExVWQKRHdFQi93UUVBd0lHd0RBZkJnTlZIU01FR0RBV2dCUno2S04zMFhGZFdPOW1Oand0emlTbnFJdG1FakFLQmdncQpoa2pPUFFRREFnTkpBREJHQWlFQTlkbklub1gzUVZvS2JxR29obXZ1SGpjdzNTTGkzY1lNa01DR3lMSTNzaW9DCklRRHFGVE5CN1VHUUcySENDWG9HTytoSGQxdUNERXoyaSs1NkpEWFlTaUtuT1E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlCU2pDQjhhQURBZ0VDQWdFQk1Bb0dDQ3FHU000OUJBTUNNQTB4Q3pBSkJnTlZCQU1UQW1OaE1CNFhEVEkwCk1ETXlNVEl4TXpjd05Wb1hEVE0wTURNeU1USXhNemN3TlZvd0RURUxNQWtHQTFVRUF4TUNZMkV3V1RBVEJnY3EKaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFSRXU1STZMMEFSRkhqcmNUK1lXWHVLT3lvNTdtcU9CNm1Dejc0bwo0UHVpcGYzdzhDaXVoOXRuTjJJMUZsWitnTDNqOVJLbjYxM0UzOTlFVUhranBPb3JvMEl3UURBT0JnTlZIUThCCkFmOEVCQU1DQWdRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVWMraWpkOUZ4WFZqdlpqWTgKTGM0a3A2aUxaaEl3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnR3BjdjNCNzgvajRSdStBcVZBOTM0ckNHcU0vWAo4M3BVWGpTNC9QVXNQM1VDSVFEbG9zUXVZa2tzN3psZ1k3ckNZTUY2TnFvLzFPdlRPd3k5VjJ5WTN2MGE0QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + "logId": { + "keyId": "YWRjNTE1MWY5OTExZWUxZjAwMWVkYzc0Y2Q3MWNkNThmOGExMWE0ODRhOGM5NzA5NDkwYjRkOTY2NDcxZjQxMQ==" + } } ], - "tLogs": [ + "certificateAuthorities": [ { - "baseURL": "https://rekor.example.com", - "hashAlgorithm": "sha-256", - "publicKey": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFMHh0SkYxNzZabE1qV0F5dFVTNXJpZXVrcEFWUgo5d1JpN1BDaG1Ed2NFTUZIemFwczN3NnVUcG9aSDQ1TzZkcnJvcGl1azNBZEJtbHc4Rkdpcnd4Z2ZnPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", - "logID": "fe807d6c26f5b8e4f2f11a1e210c42a1dd38499c448d25ba04a5c5997dec4f3a" + "subject": { + "organization": "fulcio-organization", + "commonName": "fulcio-common-name" + }, + "uri": "https://fulcio.example.com", + "certChain": { + "certificates": [ + { + "rawBytes": "MIIBPTCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0MDMyMjIwNDczOVoXDTM0MDMyMjIwNDczOVowDzENMAsGA1UEAxMEbGVhZjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNr99Dzn4PLhw3a9dP8YLwZaPnm3hpF3vt/55rMc7N194IPRB+qCDQIKIsyFMQ937IA+ylxdYvwYPB30kw/nie+jMzAxMA4GA1UdDwEB/wQEAwIGwDAfBgNVHSMEGDAWgBSgpcC8Rht4JttKz/d6pqb87A+f+zAKBggqhkjOPQQDAgNIADBFAiEAtuSOJ8LaCp6OrUIo8eKz7iYFEeOMI5d3aBEUSUp8y64CIHnTyu87fhXigrwrrhx0mEluHBfqeBpJilenwWjcUzYT" + }, + { + "rawBytes": "MIIBSTCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0MDMyMjIwNDczOVoXDTM0MDMyMjIwNDczOVowDTELMAkGA1UEAxMCY2EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATpp0ZNVPLAIzjTPkYzluuwuJxo4kmCLQRmznmz9GE89huCeLhyLbgj6xLgLrlZPwEnlGRKdiba+pLxUzKVKTPAo0IwQDAOBgNVHQ8BAf8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoKXAvEYbeCbbSs/3eqam/OwPn/swCgYIKoZIzj0EAwIDRwAwRAIgPpFwR+kjxrG75XPEQCiKPwF1Zg55FZVT7PlNJKyIPYACIFMMqZ4//ncJoBxMtvTsr3++2d91SPpyis2cLiDcr3kW" + } + ] + }, + "validFor": { + "start": "1970-01-01T00:00:00Z" + } } ], - "ctLogs": [ + "ctlogs": [ { - "baseURL": "https://ctfe.example.com", - "hashAlgorithm": "sha-256", - "publicKey": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWjRjZ0ZhQ2s3SnRPL3d4RHcyRTFTM1UrOTdGMAoyZEYyZml4bmlUaHZYZ2J4QVErYmtRNGRRVU53TjQ2UWNDendZdUpjOTc0MlZpNkx2Tng3WDc0MjdBPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", - "logID": "83e749763552c099b251d441566b9c12f160b24fbff28ab08d2681757d8acbde" + "baseUrl": "https://ctfe.example.com", + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBQY7A479x/VleGrvxp1gQAykOZMjld4J6VWVLnN0WLiqOesr9QkSBVnBkYKw0pr6Bgr8Qjg6NA3x470DLPxrDQ==", + "keyDetails": "PKIX_ECDSA_P256_SHA_256", + "validFor": { + "start": "1970-01-01T00:00:00Z" + } + }, + "logId": { + "keyId": "MTcxMGUyM2RhMDY1MWFhYTgxOTRiYzk2NTJjZDAwYTk3YzFmZGE5Yzc2ZmNlMTJmMTRlYjYzNWU0MjAzNjk1NA==" + } } ], - "timestampAuthorities": [ + "timestampAuthorities": [ { - "subject": { - "organization": "tsa-organization", - "commonName": "tsa-common-name" + "subject": { + "organization": "tsa-organization", + "commonName": "tsa-common-name" + }, + "uri": "https://tsa.example.com", + "certChain": { + "certificates": [ + { + "rawBytes": "MIIBPTCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0MDMyMjIwNDczOVoXDTM0MDMyMjIwNDczOVowDzENMAsGA1UEAxMEbGVhZjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDgjsTzgbEsFFuBFCp1LIRv4SwYLCLL1fxtq95tbtGj/wHQUmrKLxMLMxaxIzdJs54lIDP+LoKeK25+HBPftwtCjMzAxMA4GA1UdDwEB/wQEAwIEEDAfBgNVHSMEGDAWgBRRiPL3dEhG22Qh+0GTFJ/G1SW1yDAKBggqhkjOPQQDAgNIADBFAiABNvVUla7gqF/135UkA55FQ57M6r84IArwk43Zy2aPPgIhAO8/F8k9VB5+I1FSiQL1qsM8yO6SUpVF9E+hNJ9n/6zU" + }, + { + "rawBytes": "MIIBSzCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0MDMyMjIwNDczOVoXDTM0MDMyMjIwNDczOVowDTELMAkGA1UEAxMCY2EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARjUhxtm6QXaB2bkGKHenCToVRPhVf0PTkuS7/hTGjHhELoMrD8r3nbqyceFEl4FUTzEMDfrj/YhefX7ZbeesSho0IwQDAOBgNVHQ8BAf8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUUYjy93RIRttkIftBkxSfxtUltcgwCgYIKoZIzj0EAwIDSQAwRgIhAJgRO/ig4ZBrlYjuNYpC/kqUIVsfSKLpS9c4/lkcTGBPAiEAq+euZ8zkevab16uWx7ZaEcElKYY3xzhTr5yQYeJPOcQ=" + } + ] }, - "uri": "https://tsa.example.com", - "certChain": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQRENCNUtBREFnRUNBZ0VDTUFvR0NDcUdTTTQ5QkFNQ01BMHhDekFKQmdOVkJBTVRBbU5oTUI0WERUSTAKTURNeU1USXhNemN3TlZvWERUTTBNRE15TVRJeE16Y3dOVm93RHpFTk1Bc0dBMVVFQXhNRWJHVmhaakJaTUJNRwpCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk1RMXBPSHJpSGV1eHFDV3RrOVlVZkNDWWZsZ2ZzdUR2SWdHCitLeXExNTVlQVdqSjVjVzFkbXpLOHU3ZjQzU0F6dmVmRWRuUWo0OHlGZVBzeXRyOTNGQ2pNekF4TUE0R0ExVWQKRHdFQi93UUVBd0lFRURBZkJnTlZIU01FR0RBV2dCUXpHTVVTTmJTLzIrNU5jVTFoN3NaNXRML3VZVEFLQmdncQpoa2pPUFFRREFnTkhBREJFQWlBVXlUSHlhWDB1a2NWMHdaa3NMMUg1VkU3dmlKQVp4d1dNS2F1MlJiWURSd0lnCmJORW9MdDFvZGdqZ1B5OU9WdFNpYmIrOEZ3RlJwc0MxdWo3TFVXM1pWNzQ9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJTVENCOGFBREFnRUNBZ0VCTUFvR0NDcUdTTTQ5QkFNQ01BMHhDekFKQmdOVkJBTVRBbU5oTUI0WERUSTAKTURNeU1USXhNemN3TlZvWERUTTBNRE15TVRJeE16Y3dOVm93RFRFTE1Ba0dBMVVFQXhNQ1kyRXdXVEFUQmdjcQpoa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFDVDVVQ1RTYUtqUWZ1dDRUNWJXTy8rSWl0OWEzYW05SFhMZWdaClhMQUMrNU1Yd3lUM0ozWGVRcnRRZk8rMk4xb0NneWp0MVRLRE9sRGdkOXpOSkp5NG8wSXdRREFPQmdOVkhROEIKQWY4RUJBTUNBZ1F3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVTXhqRkVqVzB2OXZ1VFhGTgpZZTdHZWJTLzdtRXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdaS0Q2M0VUY2xHV0J0enJhSm1DdExobGduMWx6CmtBS1hwK0IyUUpkNnRKOENJQUdPZEJnZFFYemVDdFBEOTllVnpPSzVqSm5iMm1yWStXT0FCcTVzRDhpbQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + "validFor": { + "start": "1970-01-01T00:00:00Z" + } } ] } \ No newline at end of file diff --git a/pkg/reconciler/trustroot/testdata/marshalledEntryFromMirrorFS.json b/pkg/reconciler/trustroot/testdata/marshalledEntryFromMirrorFS.json index e93bd564..a3774db9 100644 --- a/pkg/reconciler/trustroot/testdata/marshalledEntryFromMirrorFS.json +++ b/pkg/reconciler/trustroot/testdata/marshalledEntryFromMirrorFS.json @@ -1,29 +1,49 @@ { - "certificateAuthorities": [ + "tlogs": [ { - "subject": { - "organization": "", - "commonName": "" + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Vobk4rjNzYrf/uqDwEd/HDfCro89r63DaHCTRYQJaf/JHdJj/nxBl1e3ZCo0B7kB/uU+e7d56A9gPdelFc51g==", + "keyDetails": "PKIX_ECDSA_P256_SHA_256", + "validFor": { + "start": "1970-01-01T00:00:00Z" + } }, - "uri": "", - "certChain": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCNUtBREFnRUNBZ0VDTUFvR0NDcUdTTTQ5QkFNQ01BMHhDekFKQmdOVkJBTVRBbU5oTUI0WERUSTAKTURNeU1USXhNemN3TlZvWERUTTBNRE15TVRJeE16Y3dOVm93RHpFTk1Bc0dBMVVFQXhNRWJHVmhaakJaTUJNRwpCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk5uWlRwdG5OMFRXTTZCUklQbi9LTGdvMnUvVzVWdDhsbU9NCjZ4WWZyMXVYb2Jka21jVUkrcU14QW1YaE9IRGhjWGdRS2xnWnVpdmNkOFh3bU9scFEwU2pNekF4TUE0R0ExVWQKRHdFQi93UUVBd0lHd0RBZkJnTlZIU01FR0RBV2dCUno2S04zMFhGZFdPOW1Oand0emlTbnFJdG1FakFLQmdncQpoa2pPUFFRREFnTkpBREJHQWlFQTlkbklub1gzUVZvS2JxR29obXZ1SGpjdzNTTGkzY1lNa01DR3lMSTNzaW9DCklRRHFGVE5CN1VHUUcySENDWG9HTytoSGQxdUNERXoyaSs1NkpEWFlTaUtuT1E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlCU2pDQjhhQURBZ0VDQWdFQk1Bb0dDQ3FHU000OUJBTUNNQTB4Q3pBSkJnTlZCQU1UQW1OaE1CNFhEVEkwCk1ETXlNVEl4TXpjd05Wb1hEVE0wTURNeU1USXhNemN3TlZvd0RURUxNQWtHQTFVRUF4TUNZMkV3V1RBVEJnY3EKaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFSRXU1STZMMEFSRkhqcmNUK1lXWHVLT3lvNTdtcU9CNm1Dejc0bwo0UHVpcGYzdzhDaXVoOXRuTjJJMUZsWitnTDNqOVJLbjYxM0UzOTlFVUhranBPb3JvMEl3UURBT0JnTlZIUThCCkFmOEVCQU1DQWdRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVWMraWpkOUZ4WFZqdlpqWTgKTGM0a3A2aUxaaEl3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnR3BjdjNCNzgvajRSdStBcVZBOTM0ckNHcU0vWAo4M3BVWGpTNC9QVXNQM1VDSVFEbG9zUXVZa2tzN3psZ1k3ckNZTUY2TnFvLzFPdlRPd3k5VjJ5WTN2MGE0QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + "logId": { + "keyId": "YWRjNTE1MWY5OTExZWUxZjAwMWVkYzc0Y2Q3MWNkNThmOGExMWE0ODRhOGM5NzA5NDkwYjRkOTY2NDcxZjQxMQ==" + } } ], - "tLogs": [ + "certificateAuthorities": [ { - "baseURL": "", - "hashAlgorithm": "", - "publicKey": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFMHh0SkYxNzZabE1qV0F5dFVTNXJpZXVrcEFWUgo5d1JpN1BDaG1Ed2NFTUZIemFwczN3NnVUcG9aSDQ1TzZkcnJvcGl1azNBZEJtbHc4Rkdpcnd4Z2ZnPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", - "logID": "fe807d6c26f5b8e4f2f11a1e210c42a1dd38499c448d25ba04a5c5997dec4f3a" + "certChain": { + "certificates": [ + { + "rawBytes": "MIIBPTCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0MDMyMjIwNDczOVoXDTM0MDMyMjIwNDczOVowDzENMAsGA1UEAxMEbGVhZjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNr99Dzn4PLhw3a9dP8YLwZaPnm3hpF3vt/55rMc7N194IPRB+qCDQIKIsyFMQ937IA+ylxdYvwYPB30kw/nie+jMzAxMA4GA1UdDwEB/wQEAwIGwDAfBgNVHSMEGDAWgBSgpcC8Rht4JttKz/d6pqb87A+f+zAKBggqhkjOPQQDAgNIADBFAiEAtuSOJ8LaCp6OrUIo8eKz7iYFEeOMI5d3aBEUSUp8y64CIHnTyu87fhXigrwrrhx0mEluHBfqeBpJilenwWjcUzYT" + }, + { + "rawBytes": "MIIBSTCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0MDMyMjIwNDczOVoXDTM0MDMyMjIwNDczOVowDTELMAkGA1UEAxMCY2EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATpp0ZNVPLAIzjTPkYzluuwuJxo4kmCLQRmznmz9GE89huCeLhyLbgj6xLgLrlZPwEnlGRKdiba+pLxUzKVKTPAo0IwQDAOBgNVHQ8BAf8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoKXAvEYbeCbbSs/3eqam/OwPn/swCgYIKoZIzj0EAwIDRwAwRAIgPpFwR+kjxrG75XPEQCiKPwF1Zg55FZVT7PlNJKyIPYACIFMMqZ4//ncJoBxMtvTsr3++2d91SPpyis2cLiDcr3kW" + } + ] + }, + "validFor": { + "start": "1970-01-01T00:00:00Z" + } } ], - "ctLogs": [ + "ctlogs": [ { - "baseURL": "", - "hashAlgorithm": "", - "publicKey": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWjRjZ0ZhQ2s3SnRPL3d4RHcyRTFTM1UrOTdGMAoyZEYyZml4bmlUaHZYZ2J4QVErYmtRNGRRVU53TjQ2UWNDendZdUpjOTc0MlZpNkx2Tng3WDc0MjdBPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", - "logID": "83e749763552c099b251d441566b9c12f160b24fbff28ab08d2681757d8acbde" + "hashAlgorithm": "SHA2_256", + "publicKey": { + "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBQY7A479x/VleGrvxp1gQAykOZMjld4J6VWVLnN0WLiqOesr9QkSBVnBkYKw0pr6Bgr8Qjg6NA3x470DLPxrDQ==", + "keyDetails": "PKIX_ECDSA_P256_SHA_256", + "validFor": { + "start": "1970-01-01T00:00:00Z" + } + }, + "logId": { + "keyId": "MTcxMGUyM2RhMDY1MWFhYTgxOTRiYzk2NTJjZDAwYTk3YzFmZGE5Yzc2ZmNlMTJmMTRlYjYzNWU0MjAzNjk1NA==" + } } - ], - "timestampAuthorities": null + ] } \ No newline at end of file diff --git a/pkg/reconciler/trustroot/testdata/rekorLogID.txt b/pkg/reconciler/trustroot/testdata/rekorLogID.txt index b69acbab..e96bd223 100644 --- a/pkg/reconciler/trustroot/testdata/rekorLogID.txt +++ b/pkg/reconciler/trustroot/testdata/rekorLogID.txt @@ -1 +1 @@ -fe807d6c26f5b8e4f2f11a1e210c42a1dd38499c448d25ba04a5c5997dec4f3a \ No newline at end of file +adc5151f9911ee1f001edc74cd71cd58f8a11a484a8c9709490b4d966471f411 \ No newline at end of file diff --git a/pkg/reconciler/trustroot/testdata/rekorPublicKey.pem b/pkg/reconciler/trustroot/testdata/rekorPublicKey.pem index 50ac0c58..58573372 100644 --- a/pkg/reconciler/trustroot/testdata/rekorPublicKey.pem +++ b/pkg/reconciler/trustroot/testdata/rekorPublicKey.pem @@ -1,4 +1,4 @@ -----BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0xtJF176ZlMjWAytUS5rieukpAVR -9wRi7PChmDwcEMFHzaps3w6uTpoZH45O6drropiuk3AdBmlw8FGirwxgfg== +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Vobk4rjNzYrf/uqDwEd/HDfCro8 +9r63DaHCTRYQJaf/JHdJj/nxBl1e3ZCo0B7kB/uU+e7d56A9gPdelFc51g== -----END PUBLIC KEY----- diff --git a/pkg/reconciler/trustroot/testdata/root.json b/pkg/reconciler/trustroot/testdata/root.json index c1a671d7..f7bae914 100644 --- a/pkg/reconciler/trustroot/testdata/root.json +++ b/pkg/reconciler/trustroot/testdata/root.json @@ -3,9 +3,9 @@ "_type": "root", "spec_version": "1.0", "version": 1, - "expires": "2024-09-21T17:37:05-04:00", + "expires": "2024-09-22T16:47:39-04:00", "keys": { - "0eb0ad52cfe100a2a23a3ccd9d04be89ec8e2dd227b6c07f93c97ba520266e03": { + "0c5ee15a0b35012b32989697c15e22f199d8534863a80197bea385adb908d0c9": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ @@ -13,10 +13,10 @@ "sha512" ], "keyval": { - "public": "a206426b3e527818be479e2ed56af0bf40ac94e5b7c1c16fe971e916cbac0131" + "public": "06ba72d6fe28cc6d1d85ca8f933f7e855875af2cabb97dd075074f5d1c188249" } }, - "6518b160ca979f75f590dd0eb2b63e5ade89020de7f249f49f41e7dd70102072": { + "b2cf295def74b86b6a50211bfcf3ab3839a2bdbed936d95cfacce1f4c31deedd": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ @@ -24,10 +24,10 @@ "sha512" ], "keyval": { - "public": "682a3ffa5b6831005501a880bdcf402cfc5957ed90e7f02603d454f7a6220f5b" + "public": "97c5f9488951eb67f16ea9328c9537c2ade4485a0b924ec0486a236f50e80f96" } }, - "95e5d5d9bec66701589cf7c6469037ae792ace408b3db1165a7c8cfd388f2c87": { + "d4177b1e89bf7eb02c44285e9f7907eb089ff7951199179d6fd68280dbb4d69d": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ @@ -35,10 +35,10 @@ "sha512" ], "keyval": { - "public": "5265fdc744fba2b29eac631b065b0f863a4dfbb6b6ee21a7088b0df65bcc6444" + "public": "4b92888524b5cd2de6cad461f83fb86b3f5590792c037b416132811ba71e1e8b" } }, - "ecff6ba56f1930f6ee81e3b4c7763bf79d3e8344400c3864e22456365c38cbde": { + "fcf4d6c6bfa6fccb41df570cc60e6ef63cfe45baed10c0ead716de97f4a25264": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ @@ -46,32 +46,32 @@ "sha512" ], "keyval": { - "public": "feb8ba11326535d888cbd97eea3f031014e0fd40549c1eb907afff592be4c249" + "public": "6f98dc24fc1df15ed2888658f711dbe59433aa7b0a62334080100fa52a483716" } } }, "roles": { "root": { "keyids": [ - "0eb0ad52cfe100a2a23a3ccd9d04be89ec8e2dd227b6c07f93c97ba520266e03" + "d4177b1e89bf7eb02c44285e9f7907eb089ff7951199179d6fd68280dbb4d69d" ], "threshold": 1 }, "snapshot": { "keyids": [ - "6518b160ca979f75f590dd0eb2b63e5ade89020de7f249f49f41e7dd70102072" + "b2cf295def74b86b6a50211bfcf3ab3839a2bdbed936d95cfacce1f4c31deedd" ], "threshold": 1 }, "targets": { "keyids": [ - "ecff6ba56f1930f6ee81e3b4c7763bf79d3e8344400c3864e22456365c38cbde" + "fcf4d6c6bfa6fccb41df570cc60e6ef63cfe45baed10c0ead716de97f4a25264" ], "threshold": 1 }, "timestamp": { "keyids": [ - "95e5d5d9bec66701589cf7c6469037ae792ace408b3db1165a7c8cfd388f2c87" + "0c5ee15a0b35012b32989697c15e22f199d8534863a80197bea385adb908d0c9" ], "threshold": 1 } @@ -80,8 +80,8 @@ }, "signatures": [ { - "keyid": "0eb0ad52cfe100a2a23a3ccd9d04be89ec8e2dd227b6c07f93c97ba520266e03", - "sig": "a7afdd2cbe3518a0fa66a091f1647d7ce7a7e0b14304ce9c86f16f24d6da9aebef07b9ee97295bff1f2af6a5fbfdc35a5be21c6a393ce34fe34d34a2c713aa04" + "keyid": "d4177b1e89bf7eb02c44285e9f7907eb089ff7951199179d6fd68280dbb4d69d", + "sig": "0eca8e52cd9d8e18dc02593925bde4c44f2eac3e173199ff30a8a875391636f419914563fafe171d5b4b22917b8a6604ad77af5ea9f88166b3f8ca6c15332201" } ] } \ No newline at end of file diff --git a/pkg/reconciler/trustroot/testdata/rootWithTrustedRootJSON.json b/pkg/reconciler/trustroot/testdata/rootWithTrustedRootJSON.json new file mode 100644 index 00000000..cc9bb5cf --- /dev/null +++ b/pkg/reconciler/trustroot/testdata/rootWithTrustedRootJSON.json @@ -0,0 +1,87 @@ +{ + "signed": { + "_type": "root", + "spec_version": "1.0", + "version": 1, + "expires": "2024-09-22T16:47:40-04:00", + "keys": { + "1742f6a1f846f4042382403b907864f125c2fca7bd70d6c157a40ac8e6f7d505": { + "keytype": "ed25519", + "scheme": "ed25519", + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keyval": { + "public": "3bfd19c0931a80cd3279322fc22b04b90831b1804f5dbc72c31676ca2ac82f97" + } + }, + "5dd6940e523073d10a6252f38a4dc2ebf33e23641c103682e43cb351a5672f43": { + "keytype": "ed25519", + "scheme": "ed25519", + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keyval": { + "public": "d64a13987f3b0ccfcbfab8c5631acff1b69dda70e40c1aae0cb1f0f9575716cb" + } + }, + "8b635809713e0b6ae3370afeb6fa83d7aae2039b355e56d1211049246c3d1a4d": { + "keytype": "ed25519", + "scheme": "ed25519", + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keyval": { + "public": "ecf8b527a4a4ce34718286dc9a67a5969060053bf1750e2dc74e065c9ab30ec1" + } + }, + "d263be84f7043dd0b4636fb797cfd1c9b455b9168f282cad8f48ff0ca47465fc": { + "keytype": "ed25519", + "scheme": "ed25519", + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keyval": { + "public": "e7f35e9f47b6e2f38e62b184d9f9a54f085843c57bb102cab0fe684dabe1e0bd" + } + } + }, + "roles": { + "root": { + "keyids": [ + "1742f6a1f846f4042382403b907864f125c2fca7bd70d6c157a40ac8e6f7d505" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "8b635809713e0b6ae3370afeb6fa83d7aae2039b355e56d1211049246c3d1a4d" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "5dd6940e523073d10a6252f38a4dc2ebf33e23641c103682e43cb351a5672f43" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "d263be84f7043dd0b4636fb797cfd1c9b455b9168f282cad8f48ff0ca47465fc" + ], + "threshold": 1 + } + }, + "consistent_snapshot": false + }, + "signatures": [ + { + "keyid": "1742f6a1f846f4042382403b907864f125c2fca7bd70d6c157a40ac8e6f7d505", + "sig": "1050176114e44eec30b0661a9016b0a1ce607b4168d8e84ab1d4c15d73c3bdb051f0c0b21b67f03c77d4a98ea7dabc5fd1404bbef2eaac605ddfa2a6145d0709" + } + ] +} \ No newline at end of file diff --git a/pkg/reconciler/trustroot/testdata/testdata.go b/pkg/reconciler/trustroot/testdata/testdata.go index 49c4e703..ef49b81f 100644 --- a/pkg/reconciler/trustroot/testdata/testdata.go +++ b/pkg/reconciler/trustroot/testdata/testdata.go @@ -1,10 +1,10 @@ -// Copyright 2024 The Sigstore Authors +// Copyright 2022 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 +// 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, diff --git a/pkg/reconciler/trustroot/testdata/tsaCertChain.pem b/pkg/reconciler/trustroot/testdata/tsaCertChain.pem index 5b568e52..0c657654 100644 --- a/pkg/reconciler/trustroot/testdata/tsaCertChain.pem +++ b/pkg/reconciler/trustroot/testdata/tsaCertChain.pem @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIBPDCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0 -MDMyMTIxMzcwNVoXDTM0MDMyMTIxMzcwNVowDzENMAsGA1UEAxMEbGVhZjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABMQ1pOHriHeuxqCWtk9YUfCCYflgfsuDvIgG -+Kyq155eAWjJ5cW1dmzK8u7f43SAzvefEdnQj48yFePsytr93FCjMzAxMA4GA1Ud -DwEB/wQEAwIEEDAfBgNVHSMEGDAWgBQzGMUSNbS/2+5NcU1h7sZ5tL/uYTAKBggq -hkjOPQQDAgNHADBEAiAUyTHyaX0ukcV0wZksL1H5VE7viJAZxwWMKau2RbYDRwIg -bNEoLt1odgjgPy9OVtSibb+8FwFRpsC1uj7LUW3ZV74= +MIIBPTCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0 +MDMyMjIwNDczOVoXDTM0MDMyMjIwNDczOVowDzENMAsGA1UEAxMEbGVhZjBZMBMG +ByqGSM49AgEGCCqGSM49AwEHA0IABDgjsTzgbEsFFuBFCp1LIRv4SwYLCLL1fxtq +95tbtGj/wHQUmrKLxMLMxaxIzdJs54lIDP+LoKeK25+HBPftwtCjMzAxMA4GA1Ud +DwEB/wQEAwIEEDAfBgNVHSMEGDAWgBRRiPL3dEhG22Qh+0GTFJ/G1SW1yDAKBggq +hkjOPQQDAgNIADBFAiABNvVUla7gqF/135UkA55FQ57M6r84IArwk43Zy2aPPgIh +AO8/F8k9VB5+I1FSiQL1qsM8yO6SUpVF9E+hNJ9n/6zU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIBSTCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0 -MDMyMTIxMzcwNVoXDTM0MDMyMTIxMzcwNVowDTELMAkGA1UEAxMCY2EwWTATBgcq -hkjOPQIBBggqhkjOPQMBBwNCAAQCT5UCTSaKjQfut4T5bWO/+Iit9a3am9HXLegZ -XLAC+5MXwyT3J3XeQrtQfO+2N1oCgyjt1TKDOlDgd9zNJJy4o0IwQDAOBgNVHQ8B -Af8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUMxjFEjW0v9vuTXFN -Ye7GebS/7mEwCgYIKoZIzj0EAwIDRwAwRAIgZKD63ETclGWBtzraJmCtLhlgn1lz -kAKXp+B2QJd6tJ8CIAGOdBgdQXzeCtPD99eVzOK5jJnb2mrY+WOABq5sD8im +MIIBSzCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI0 +MDMyMjIwNDczOVoXDTM0MDMyMjIwNDczOVowDTELMAkGA1UEAxMCY2EwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAARjUhxtm6QXaB2bkGKHenCToVRPhVf0PTkuS7/h +TGjHhELoMrD8r3nbqyceFEl4FUTzEMDfrj/YhefX7ZbeesSho0IwQDAOBgNVHQ8B +Af8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUUYjy93RIRttkIftB +kxSfxtUltcgwCgYIKoZIzj0EAwIDSQAwRgIhAJgRO/ig4ZBrlYjuNYpC/kqUIVsf +SKLpS9c4/lkcTGBPAiEAq+euZ8zkevab16uWx7ZaEcElKYY3xzhTr5yQYeJPOcQ= -----END CERTIFICATE----- diff --git a/pkg/reconciler/trustroot/testdata/tufRepo.tar b/pkg/reconciler/trustroot/testdata/tufRepo.tar index aeb86988..53f2a8d1 100644 Binary files a/pkg/reconciler/trustroot/testdata/tufRepo.tar and b/pkg/reconciler/trustroot/testdata/tufRepo.tar differ diff --git a/pkg/reconciler/trustroot/testdata/tufRepoWithTrustedRootJSON.tar b/pkg/reconciler/trustroot/testdata/tufRepoWithTrustedRootJSON.tar new file mode 100644 index 00000000..da8106fd Binary files /dev/null and b/pkg/reconciler/trustroot/testdata/tufRepoWithTrustedRootJSON.tar differ diff --git a/pkg/reconciler/trustroot/trustroot.go b/pkg/reconciler/trustroot/trustroot.go index f010b7c6..ded2c861 100644 --- a/pkg/reconciler/trustroot/trustroot.go +++ b/pkg/reconciler/trustroot/trustroot.go @@ -29,9 +29,11 @@ import ( trustrootreconciler "github.com/sigstore/policy-controller/pkg/client/injection/reconciler/policy/v1alpha1/trustroot" "github.com/sigstore/policy-controller/pkg/reconciler/trustroot/resources" "github.com/sigstore/policy-controller/pkg/tuf" + pbcommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" "github.com/sigstore/sigstore/pkg/cryptoutils" sigstoretuf "github.com/sigstore/sigstore/pkg/tuf" "github.com/theupdateframework/go-tuf/client" + "google.golang.org/protobuf/encoding/protojson" corev1 "k8s.io/api/core/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -66,8 +68,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, trustroot *v1alpha1.Trus case trustroot.Spec.Remote != nil: sigstoreKeys, err = r.getSigstoreKeysFromRemote(ctx, trustroot.Spec.Remote) case trustroot.Spec.SigstoreKeys != nil: - sigstoreKeys = &config.SigstoreKeys{} - sigstoreKeys.ConvertFrom(ctx, trustroot.Spec.SigstoreKeys) + sigstoreKeys, err = config.ConvertSigstoreKeys(ctx, trustroot.Spec.SigstoreKeys) default: // This should not happen since the CRD has been validated. err = fmt.Errorf("invalid TrustRoot entry: %s missing repository,remote, and sigstoreKeys", trustroot.Name) @@ -84,8 +85,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, trustroot *v1alpha1.Trus // them before serializing. // Note this is identical to what we do with CTLog PublicKeys, but they // are not restricted to being only ecdsa.PublicKey. - for i, tlog := range sigstoreKeys.TLogs { - pk, logID, err := pemToKeyAndID(tlog.PublicKey) + for i, tlog := range sigstoreKeys.Tlogs { + pk, logID, err := pemToKeyAndID(config.SerializePublicKey(tlog.PublicKey)) if err != nil { return fmt.Errorf("invalid rekor public key %d: %w", i, err) } @@ -95,14 +96,14 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, trustroot *v1alpha1.Trus if !ok { return fmt.Errorf("public key %d is not ecdsa.PublicKey", i) } - sigstoreKeys.TLogs[i].LogID = logID + sigstoreKeys.Tlogs[i].LogId = &config.LogID{KeyId: []byte(logID)} } - for i, ctlog := range sigstoreKeys.CTLogs { - _, logID, err := pemToKeyAndID(ctlog.PublicKey) + for i, ctlog := range sigstoreKeys.Ctlogs { + _, logID, err := pemToKeyAndID(config.SerializePublicKey(ctlog.PublicKey)) if err != nil { return fmt.Errorf("invalid ctlog public key %d: %w", i, err) } - sigstoreKeys.CTLogs[i].LogID = logID + sigstoreKeys.Ctlogs[i].LogId = &config.LogID{KeyId: []byte(logID)} } // See if the CM holding configs exists @@ -203,7 +204,7 @@ func (r *Reconciler) removeTrustRootEntry(ctx context.Context, cm *corev1.Config } // pemToKeyAndID takes a public key in PEM format, and turns it into -// crypto.PublicKey and the CTLog LogID. +// crypto.PublicKey and the CTLog LogId. func pemToKeyAndID(pem []byte) (crypto.PublicKey, string, error) { pk, err := cryptoutils.UnmarshalPEMToPublicKey(pem) if err != nil { @@ -221,6 +222,7 @@ func pemToKeyAndID(pem []byte) (crypto.PublicKey, string, error) { type customMetadata struct { Usage sigstoretuf.UsageKind `json:"usage"` Status sigstoretuf.StatusKind `json:"status"` + URI string `json:"uri"` } type sigstoreCustomMetadata struct { @@ -236,6 +238,22 @@ func getSigstoreKeysFromTuf(ctx context.Context, tufClient *client.Client) (*con return nil, fmt.Errorf("error getting targets: %w", err) } ret := &config.SigstoreKeys{} + + // if there is a "trusted_root.json" target, we can use that instead of the custom metadata + if _, ok := targets["trusted_root.json"]; ok { + dl := newDownloader() + if err = tufClient.Download("trusted_root.json", &dl); err != nil { + return nil, fmt.Errorf("downloading trusted_root.json: %w", err) + } + + err := protojson.Unmarshal(dl.Bytes(), ret) + if err != nil { + return nil, fmt.Errorf("parsing trusted_root.json: %w", err) + } + return ret, nil + } + + // fall back to using custom metadata (e.g. for private TUF repositories) for name, targetMeta := range targets { // Skip any targets that do not include custom metadata. if targetMeta.Custom == nil { @@ -251,13 +269,34 @@ func getSigstoreKeysFromTuf(ctx context.Context, tufClient *client.Client) (*con if err = tufClient.Download(name, &dl); err != nil { return nil, fmt.Errorf("downloading target %s: %w", name, err) } + switch scm.Sigstore.Usage { case sigstoretuf.Fulcio: - ret.CertificateAuthorities = append(ret.CertificateAuthorities, config.CertificateAuthority{CertChain: dl.Bytes()}) + certChain, err := config.DeserializeCertChain(dl.Bytes()) + if err != nil { + return nil, fmt.Errorf("deserializing certificate chain: %w", err) + } + ret.CertificateAuthorities = append(ret.CertificateAuthorities, + &config.CertificateAuthority{ + Uri: scm.Sigstore.URI, + CertChain: certChain, + ValidFor: &config.TimeRange{ + Start: &config.Timestamp{}, + }, + }, + ) case sigstoretuf.CTFE: - ret.CTLogs = append(ret.CTLogs, config.TransparencyLogInstance{PublicKey: dl.Bytes()}) + tlog, err := genTransparencyLogInstance(scm.Sigstore.URI, dl.Bytes()) + if err != nil { + return nil, fmt.Errorf("creating transparency log instance: %w", err) + } + ret.Ctlogs = append(ret.Ctlogs, tlog) case sigstoretuf.Rekor: - ret.TLogs = append(ret.TLogs, config.TransparencyLogInstance{PublicKey: dl.Bytes()}) + tlog, err := genTransparencyLogInstance(scm.Sigstore.URI, dl.Bytes()) + if err != nil { + return nil, fmt.Errorf("creating transparency log instance: %w", err) + } + ret.Tlogs = append(ret.Tlogs, tlog) } } // Make sure there's at least a single CertificateAuthority (Fulcio there). @@ -268,6 +307,23 @@ func getSigstoreKeysFromTuf(ctx context.Context, tufClient *client.Client) (*con return ret, nil } +func genTransparencyLogInstance(baseURL string, pkBytes []byte) (*config.TransparencyLogInstance, error) { + pbpk, pk, err := config.DeserializePublicKey(pkBytes) + if err != nil { + return nil, fmt.Errorf("unmarshaling PEM public key: %w", err) + } + logID, err := cosign.GetTransparencyLogID(pk) + if err != nil { + return nil, fmt.Errorf("failed to construct LogID: %w", err) + } + return &config.TransparencyLogInstance{ + BaseUrl: baseURL, + HashAlgorithm: pbcommon.HashAlgorithm_SHA2_256, + PublicKey: pbpk, + LogId: &pbcommon.LogId{KeyId: []byte(logID)}, + }, nil +} + func newDownloader() downloader { return downloader{&bytes.Buffer{}} } diff --git a/pkg/reconciler/trustroot/trustroot_test.go b/pkg/reconciler/trustroot/trustroot_test.go index 88226322..af26e08d 100644 --- a/pkg/reconciler/trustroot/trustroot_test.go +++ b/pkg/reconciler/trustroot/trustroot_test.go @@ -17,12 +17,20 @@ package trustroot import ( "bytes" "context" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" _ "embed" - "encoding/json" + "encoding/pem" "fmt" + "math/big" "strings" "testing" + "time" + "google.golang.org/protobuf/encoding/protojson" "knative.dev/pkg/apis" logtesting "knative.dev/pkg/logging/testing" @@ -30,6 +38,7 @@ import ( "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" fakecosignclient "github.com/sigstore/policy-controller/pkg/client/injection/client/fake" "github.com/sigstore/policy-controller/pkg/client/injection/reconciler/policy/v1alpha1/trustroot" + pbcommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -110,17 +119,6 @@ const ( removePatchFmtString = `[{"op":"remove","path":"/data/%s"}]` ) -// compactJSON compacts the given JSON, as the test data is formatted with -// indentation for readability, but the expected patches are compacted. -func compactJSON(in []byte) []byte { - out := bytes.NewBuffer([]byte{}) - err := json.Compact(out, in) - if err != nil { - panic("error compacting json test data: " + err.Error()) - } - return out.Bytes() -} - // testmap with prepopulated entries for creating TrustRoot resource. // ctfe => CTLog Public Key // fulcio => CertificateAuthority certificate @@ -133,12 +131,31 @@ var sigstoreKeys = map[string]string{ "tsa": string(testdata.Get("tsaCertChain.pem")), } +// canonicalizeSigstoreKeys round-trips the SigstoreKeys through protojson so +// the output is deterministic for the current test run. This is necessary +// because protojson has "randomly deterministic" output, meaning it will add +// whitespace randomly depending on the digest of the executable. +// See https://go-review.googlesource.com/c/protobuf/+/151340 and +// https://github.com/golang/protobuf/issues/1121 +func canonicalizeSigstoreKeys(in []byte) []byte { + keys := &config.SigstoreKeys{} + err := protojson.Unmarshal(in, keys) + if err != nil { + panic(err) + } + out, err := protojson.Marshal(keys) + if err != nil { + panic(err) + } + return out +} + // This is the marshalled entry from above keys/certs with fixed values // (for ease of testing) for other parts. -var marshalledEntry = string(compactJSON(testdata.Get("marshalledEntry.json"))) +var marshalledEntry = string(canonicalizeSigstoreKeys(testdata.Get("marshalledEntry.json"))) // this is the marshalled entry for when we construct from the repository. -var marshalledEntryFromMirrorFS = string(compactJSON(testdata.Get("marshalledEntryFromMirrorFS.json"))) +var marshalledEntryFromMirrorFS = string(canonicalizeSigstoreKeys(testdata.Get("marshalledEntryFromMirrorFS.json"))) var rekorLogID = string(testdata.Get("rekorLogID.txt")) var ctfeLogID = string(testdata.Get("ctfeLogID.txt")) @@ -151,6 +168,14 @@ var validRepository = testdata.Get("tufRepo.tar") // rootJSON is a valid root.json for above TUF repository. var rootJSON = testdata.Get("root.json") +// validRepositoryWithTrustedRootJSON is a valid tarred repository representing +// an air-gap TUF repository containing trusted_root.json. +var validRepositoryWithTrustedRootJSON = testdata.Get("tufRepoWithTrustedRootJSON.tar") + +// IMPORTANT: The next expiration is on 2024-09-21 +// rootJSON is a valid root.json for above TUF repository. +var rootWithTrustedRootJSON = testdata.Get("rootWithTrustedRootJSON.json") + func TestReconcile(t *testing.T) { table := TableTest{{ Name: "bad workqueue key", @@ -325,7 +350,7 @@ func TestReconcile(t *testing.T) { ), }, WantCreates: []runtime.Object{ - makeConfigMapWithMirrorFS(), + makeConfigMapWithMirrorFS(marshalledEntryFromMirrorFS), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewTrustRoot(trName, @@ -335,6 +360,30 @@ func TestReconcile(t *testing.T) { WithTrustRootFinalizer, MarkReadyTrustRoot, )}}, + }, { + Name: "With repository containing trusted_root.json", + Key: testKey, + + SkipNamespaceValidation: true, // Cluster scoped + Objects: []runtime.Object{ + NewTrustRoot(trName, + WithTrustRootUID(uid), + WithTrustRootResourceVersion(resourceVersion), + WithRepository("targets", rootWithTrustedRootJSON, validRepositoryWithTrustedRootJSON), + WithTrustRootFinalizer, + ), + }, + WantCreates: []runtime.Object{ + makeConfigMapWithMirrorFS(marshalledEntry), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewTrustRoot(trName, + WithTrustRootUID(uid), + WithTrustRootResourceVersion(resourceVersion), + WithRepository("targets", rootWithTrustedRootJSON, validRepositoryWithTrustedRootJSON), + WithTrustRootFinalizer, + MarkReadyTrustRoot, + )}}, }} logger := logtesting.TestLogger(t) @@ -363,13 +412,15 @@ func makeConfigMapWithSigstoreKeys() *corev1.ConfigMap { Data: make(map[string]string), } source := NewTrustRoot(trName, WithSigstoreKeys(sigstoreKeys)) - c := &config.SigstoreKeys{} - c.ConvertFrom(context.Background(), source.Spec.SigstoreKeys) - for i := range c.TLogs { - c.TLogs[i].LogID = rekorLogID + c, err := config.ConvertSigstoreKeys(context.Background(), source.Spec.SigstoreKeys) + if err != nil { + panic("failed to convert test SigstoreKeys") } - for i := range c.CTLogs { - c.CTLogs[i].LogID = ctfeLogID + for i := range c.Tlogs { + c.Tlogs[i].LogId = &config.LogID{KeyId: []byte(rekorLogID)} + } + for i := range c.Ctlogs { + c.Ctlogs[i].LogId = &config.LogID{KeyId: []byte(ctfeLogID)} } marshalled, err := resources.Marshal(c) if err != nil { @@ -379,13 +430,13 @@ func makeConfigMapWithSigstoreKeys() *corev1.ConfigMap { return ret } -func makeConfigMapWithMirrorFS() *corev1.ConfigMap { +func makeConfigMapWithMirrorFS(entry string) *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: config.SigstoreKeysConfigName, }, - Data: map[string]string{"test-trustroot": marshalledEntryFromMirrorFS}, + Data: map[string]string{"test-trustroot": entry}, } } @@ -463,67 +514,164 @@ func patchRemoveFinalizers(namespace, name string) clientgotesting.PatchActionIm return action } -// TestConvertFrom tests marshalling / unmarshalling to the configmap and back. +// TestConvertSigstoreKeys tests marshalling / unmarshalling to the configmap and back. // This is here instead of in the pkg/apis/config because of import cycles and // having both types v1alpha1.SigstoreTypes and config.SigstoreTypes being // available makes testing way easier, and due to import cycles we can't put // that in config and yet import v1alpha1. -func TestConvertFrom(t *testing.T) { - source := v1alpha1.SigstoreKeys{} - +func TestConvertSigstoreKeys(t *testing.T) { itemsPerEntry := 2 - // Create TransparencyLogInstances. - // Values are not valid for proper usage, but we want to make sure - // we properly handle the serialize/unserialize so we use fixed values - // for testing that. + type key struct { + pem []byte + der []byte + } + type testTlog struct { + url string + hashAlgorithm string + publicKey key + } + type testCA struct { + url string + org string + commonName string + certChain []key + } + type testData struct { + tlogs []testTlog + ctlogs []testTlog + cas []testCA + tsas []testCA + } + + hashAlgorithms := []string{"sha-256", "sha-512"} + hashAlgorithmMap := map[string]pbcommon.HashAlgorithm{"sha-256": pbcommon.HashAlgorithm_SHA2_256, "sha-512": pbcommon.HashAlgorithm_SHA2_512} + + test := testData{} + + // construct test data for i := 0; i < itemsPerEntry; i++ { - for _, prefix := range []string{"tlog", "ctlog"} { - entry := v1alpha1.TransparencyLogInstance{ - BaseURL: *apis.HTTP(fmt.Sprintf("%s-%d.example.com", prefix, i)), - HashAlgorithm: fmt.Sprintf("%s-hash-%d", prefix, i), - PublicKey: []byte(fmt.Sprintf("%s-publickey-%d", prefix, i)), + for _, service := range []string{"tlog", "ctlog"} { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("failed to generate ecdsa key: %v", err) } - switch prefix { + der, err := x509.MarshalPKIXPublicKey(priv.Public().(*ecdsa.PublicKey)) + if err != nil { + t.Fatalf("failed to marshal ecdsa key: %v", err) + } + pem := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: der}) + tlog := testTlog{ + url: fmt.Sprintf("https://%s-%d.example.com", service, i), + hashAlgorithm: hashAlgorithms[i%2], + publicKey: key{pem, der}, + } + + switch service { case "tlog": - source.TLogs = append(source.TLogs, entry) + test.tlogs = append(test.tlogs, tlog) case "ctlog": - source.CTLogs = append(source.CTLogs, entry) - default: - panic("invalid type") + test.ctlogs = append(test.ctlogs, tlog) } } - } - // Create CertificateAuthorities. - // Values are not valid for proper usage, but we want to make sure - // we properly handle the serialize/unserialize so we use fixed values - // for testing that. - for i := 0; i < itemsPerEntry; i++ { - for _, prefix := range []string{"fulcio", "tsa"} { - entry := v1alpha1.CertificateAuthority{ - Subject: v1alpha1.DistinguishedName{ - Organization: fmt.Sprintf("%s-organization-%d", prefix, i), - CommonName: fmt.Sprintf("%s-commonname-%d", prefix, i), + for _, service := range []string{"fulcio", "tsa"} { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("failed to generate ecdsa key: %v", err) + } + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: "Test Certificate", }, - URI: *apis.HTTP(fmt.Sprintf("%s-%d.example.com", prefix, i)), - CertChain: []byte(fmt.Sprintf("%s-certchain-%d", prefix, i)), + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(1, 0, 0), + KeyUsage: x509.KeyUsageDigitalSignature, + BasicConstraintsValid: true, } - switch prefix { + der, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv) + if err != nil { + t.Fatalf("failed to create x509 certificate: %v", err) + } + pem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}) + ca := testCA{ + url: fmt.Sprintf("https://%s-%d.example.com", service, i), + org: fmt.Sprintf("Test Org %d for %s", i, service), + commonName: fmt.Sprintf("Test CA %d for %s", i, service), + certChain: []key{{pem, der}}, + } + + switch service { case "fulcio": - source.CertificateAuthorities = append(source.CertificateAuthorities, entry) + test.cas = append(test.cas, ca) case "tsa": - source.TimeStampAuthorities = append(source.TimeStampAuthorities, entry) - default: - panic("invalid type") + test.tsas = append(test.tsas, ca) } } } - converted := &config.SigstoreKeys{} + + // create and populate source + source := v1alpha1.SigstoreKeys{} + + for _, tlog := range test.tlogs { + url, err := apis.ParseURL(tlog.url) + if err != nil { + t.Fatalf("failed to parse url: %v", err) + } + source.TLogs = append(source.TLogs, v1alpha1.TransparencyLogInstance{ + BaseURL: *url, + HashAlgorithm: tlog.hashAlgorithm, + PublicKey: tlog.publicKey.pem, + }) + } + for _, ctlog := range test.ctlogs { + url, err := apis.ParseURL(ctlog.url) + if err != nil { + t.Fatalf("failed to parse url: %v", err) + } + source.CTLogs = append(source.CTLogs, v1alpha1.TransparencyLogInstance{ + BaseURL: *url, + HashAlgorithm: ctlog.hashAlgorithm, + PublicKey: ctlog.publicKey.pem, + }) + } + for _, ca := range test.cas { + url, err := apis.ParseURL(ca.url) + if err != nil { + t.Fatalf("failed to parse url: %v", err) + } + source.CertificateAuthorities = append(source.CertificateAuthorities, v1alpha1.CertificateAuthority{ + Subject: v1alpha1.DistinguishedName{ + Organization: ca.org, + CommonName: ca.commonName, + }, + URI: *url, + CertChain: ca.certChain[0].pem, + }) + } + for _, tsa := range test.tsas { + url, err := apis.ParseURL(tsa.url) + if err != nil { + t.Fatalf("failed to parse url: %v", err) + } + source.TimeStampAuthorities = append(source.TimeStampAuthorities, v1alpha1.CertificateAuthority{ + Subject: v1alpha1.DistinguishedName{ + Organization: tsa.org, + CommonName: tsa.commonName, + }, + URI: *url, + CertChain: tsa.certChain[0].pem, + }) + } + // convert from v1alpha1 to config and let's marshal to configmap and back // to make sure we exercise the path from: // v1alpha1 => config => configMap => back (this is what reconciler will // use to call cosign verification functions with). - converted.ConvertFrom(context.Background(), &source) + converted, err := config.ConvertSigstoreKeys(context.Background(), &source) + if err != nil { + t.Fatalf("Failed to convert entry: %v", err) + } marshalled, err := resources.Marshal(converted) if err != nil { t.Fatalf("Failed to marshal entry: %v", err) @@ -534,72 +682,70 @@ func TestConvertFrom(t *testing.T) { t.Fatalf("Failed to construct from map entry: %v", err) } sk := skMap.SigstoreKeys["test-entry"] - if len(sk.TLogs) != 2 { - t.Errorf("Not enough TLog entries, want 2 got %d", len(sk.TLogs)) + if len(sk.Tlogs) != 2 { + t.Errorf("Not enough TLog entries, want 2 got %d", len(sk.Tlogs)) } - if len(sk.CTLogs) != 2 { - t.Errorf("Not enough CTLog entries, want 2 got %d", len(sk.CTLogs)) + if len(sk.Ctlogs) != 2 { + t.Errorf("Not enough CTLog entries, want 2 got %d", len(sk.Ctlogs)) } if len(sk.CertificateAuthorities) != 2 { t.Errorf("Not enough CertificateAuthority entries, want 2 got %d", len(sk.CertificateAuthorities)) } - if len(sk.TimeStampAuthorities) != 2 { - t.Errorf("Not enough TimestampAuthorities entries, want 2 got %d", len(sk.TimeStampAuthorities)) + if len(sk.TimestampAuthorities) != 2 { + t.Errorf("Not enough TimestampAuthorities entries, want 2 got %d", len(sk.TimestampAuthorities)) } // Verify TLog, CTLog for i := 0; i < itemsPerEntry; i++ { - for _, prefix := range []string{"tlog", "ctlog"} { - var entry config.TransparencyLogInstance - switch prefix { + for _, service := range []string{"tlog", "ctlog"} { + var entry *config.TransparencyLogInstance + var tlog testTlog + switch service { case "tlog": - entry = sk.TLogs[i] + entry = sk.Tlogs[i] + tlog = test.tlogs[i] case "ctlog": - entry = sk.CTLogs[i] + entry = sk.Ctlogs[i] + tlog = test.ctlogs[i] default: panic("invalid type") } - wantURL := fmt.Sprintf("http://%s-%d.example.com", prefix, i) - wantHash := fmt.Sprintf("%s-hash-%d", prefix, i) - wantPublicKey := fmt.Sprintf("%s-publickey-%d", prefix, i) - if entry.BaseURL.String() != wantURL { - t.Errorf("Unexpected BaseURL for %s %d wanted %s got %s", prefix, i, wantURL, entry.BaseURL.String()) + if entry.BaseUrl != tlog.url { + t.Errorf("Unexpected BaseUrl for %s %d wanted %s got %s", service, i, tlog.url, entry.BaseUrl) } - if entry.HashAlgorithm != wantHash { - t.Errorf("Unexpected HashAlgorithm for %s %d wanted %s got %s", prefix, i, wantHash, entry.HashAlgorithm) + if entry.HashAlgorithm != hashAlgorithmMap[tlog.hashAlgorithm] { + t.Errorf("Unexpected HashAlgorithm for %s %d wanted %s got %s", service, i, tlog.hashAlgorithm, entry.HashAlgorithm) } - if string(entry.PublicKey) != wantPublicKey { - t.Errorf("Unexpected PublicKey for %s %d wanted %s got %s", prefix, i, wantPublicKey, string(entry.PublicKey)) + if !bytes.Equal(entry.PublicKey.RawBytes, tlog.publicKey.der) { + t.Errorf("Unexpected PublicKey for %s %d wanted %s got %s", service, i, tlog.publicKey.der, entry.PublicKey.RawBytes) } } } - // Verify CertificateAuthority, TimeStampAuthorities + // Verify CertificateAuthority, TimestampAuthorities for i := 0; i < itemsPerEntry; i++ { for _, prefix := range []string{"fulcio", "tsa"} { - var entry config.CertificateAuthority + var entry *config.CertificateAuthority + var ca testCA switch prefix { case "fulcio": entry = sk.CertificateAuthorities[i] + ca = test.cas[i] case "tsa": - entry = sk.TimeStampAuthorities[i] + entry = sk.TimestampAuthorities[i] + ca = test.tsas[i] default: panic("invalid type") } - wantOrganization := fmt.Sprintf("%s-organization-%d", prefix, i) - wantCommonName := fmt.Sprintf("%s-commonname-%d", prefix, i) - wantURI := fmt.Sprintf("http://%s-%d.example.com", prefix, i) - wantCertChain := fmt.Sprintf("%s-certchain-%d", prefix, i) - - if entry.Subject.Organization != wantOrganization { - t.Errorf("Unexpected Organization for %s %d wanted %s got %s", prefix, i, wantOrganization, entry.Subject.Organization) + if entry.Uri != ca.url { + t.Errorf("Unexpected Uri for %s %d wanted %s got %s", prefix, i, ca.url, entry.Uri) } - if entry.Subject.CommonName != wantCommonName { - t.Errorf("Unexpected CommonName for %s %d wanted %s got %s", prefix, i, wantCommonName, entry.Subject.CommonName) + if entry.Subject.Organization != ca.org { + t.Errorf("Unexpected Organization for %s %d wanted %s got %s", prefix, i, ca.org, entry.Subject.Organization) } - if string(entry.CertChain) != wantCertChain { - t.Errorf("Unexpected CertChain for %s %d wanted %s got %s", prefix, i, wantCertChain, string(entry.CertChain)) + if entry.Subject.CommonName != ca.commonName { + t.Errorf("Unexpected CommonName for %s %d wanted %s got %s", prefix, i, ca.commonName, entry.Subject.CommonName) } - if entry.URI.String() != wantURI { - t.Errorf("Unexpected URI for %s %d wanted %s got %s", prefix, i, wantURI, entry.URI.String()) + if !bytes.Equal(entry.CertChain.Certificates[0].RawBytes, ca.certChain[0].der) { + t.Errorf("Unexpected CertChain for %s %d wanted %s got %s", prefix, i, ca.certChain[0].der, entry.CertChain.Certificates[0].RawBytes) } } } diff --git a/pkg/webhook/validator.go b/pkg/webhook/validator.go index dfe45942..5a144106 100644 --- a/pkg/webhook/validator.go +++ b/pkg/webhook/validator.go @@ -1394,8 +1394,8 @@ func checkOptsFromAuthority(ctx context.Context, authority webhookcip.Authority, if !ok { return nil, fmt.Errorf("trustRootRef %s not found", authority.RFC3161Timestamp.TrustRootRef) } - for _, timestampAuthority := range sk.TimeStampAuthorities { - leaves, intermediates, roots, err := splitPEMCertificateChain(timestampAuthority.CertChain) + for _, timestampAuthority := range sk.TimestampAuthorities { + leaves, intermediates, roots, err := splitPEMCertificateChain(config.SerializeCertChain(timestampAuthority.CertChain)) // TODO: this is less efficient than it could be if err != nil { return nil, fmt.Errorf("error splitting certificates: %w", err) } @@ -1463,7 +1463,7 @@ func fulcioCertsFromAuthority(ctx context.Context, keylessRef *webhookcip.Keyles return nil, nil, nil, fmt.Errorf("trustRootRef %s not found", trustRootRef) } for _, ca := range sk.CertificateAuthorities { - certs, err := cryptoutils.UnmarshalCertificatesFromPEM(ca.CertChain) + certs, err := cryptoutils.UnmarshalCertificatesFromPEM(config.SerializeCertChain(ca.CertChain)) // TODO: this is less efficient than it could be if err != nil { return nil, nil, nil, fmt.Errorf("error unmarshalling certificates: %w", err) } @@ -1478,14 +1478,14 @@ func fulcioCertsFromAuthority(ctx context.Context, keylessRef *webhookcip.Keyles } ctlogKeys := &cosign.TrustedTransparencyLogPubKeys{ - Keys: make(map[string]cosign.TransparencyLogPubKey, len(sk.CTLogs)), + Keys: make(map[string]cosign.TransparencyLogPubKey, len(sk.Ctlogs)), } - for i, ctlog := range sk.CTLogs { - pk, err := cryptoutils.UnmarshalPEMToPublicKey(ctlog.PublicKey) + for i, ctlog := range sk.Ctlogs { + pk, err := cryptoutils.UnmarshalPEMToPublicKey(config.SerializePublicKey(ctlog.PublicKey)) // TODO: this is less efficient than it could be if err != nil { return nil, nil, nil, fmt.Errorf("unmarshaling public key %d failed: %w", i, err) } - ctlogKeys.Keys[ctlog.LogID] = cosign.TransparencyLogPubKey{ + ctlogKeys.Keys[string(ctlog.LogId.KeyId)] = cosign.TransparencyLogPubKey{ PubKey: pk, Status: tuf.Active, } @@ -1563,11 +1563,11 @@ func rekorKeysFromTrustRef(ctx context.Context, trustRootRef string) (*cosign.Tr if sk, ok := sigstoreKeys.SigstoreKeys[trustRootRef]; ok { retKeys := &cosign.TrustedTransparencyLogPubKeys{ - Keys: make(map[string]cosign.TransparencyLogPubKey, len(sk.TLogs)), + Keys: make(map[string]cosign.TransparencyLogPubKey, len(sk.Tlogs)), } rekorURL := "" - for i, tlog := range sk.TLogs { - pk, err := cryptoutils.UnmarshalPEMToPublicKey(tlog.PublicKey) + for i, tlog := range sk.Tlogs { + pk, err := cryptoutils.UnmarshalPEMToPublicKey(config.SerializePublicKey(tlog.PublicKey)) if err != nil { return nil, "", fmt.Errorf("unmarshaling public key %d failed: %w", i, err) } @@ -1577,11 +1577,11 @@ func rekorKeysFromTrustRef(ctx context.Context, trustRootRef string) (*cosign.Tr if !ok { return nil, "", fmt.Errorf("public key %d is not ecdsa.PublicKey", i) } - retKeys.Keys[tlog.LogID] = cosign.TransparencyLogPubKey{ + retKeys.Keys[string(tlog.LogId.KeyId)] = cosign.TransparencyLogPubKey{ PubKey: pkecdsa, Status: tuf.Active, } - rekorURL = tlog.BaseURL.String() + rekorURL = tlog.BaseUrl } return retKeys, rekorURL, nil } diff --git a/pkg/webhook/validator_test.go b/pkg/webhook/validator_test.go index 0753903f..dcd80b09 100644 --- a/pkg/webhook/validator_test.go +++ b/pkg/webhook/validator_test.go @@ -2950,27 +2950,34 @@ func TestFulcioCertsFromAuthority(t *testing.T) { if err != nil { t.Fatalf("Failed to get embedded CTLog Public keys for testing") } + pbpk, marshalledPK, err := config.DeserializePublicKey([]byte(ctfePublicKey)) + if err != nil { + t.Fatalf("Failed to deserialize CTLog public key: %v", err) + } + certChain, err := config.DeserializeCertChain([]byte(certChain)) + if err != nil { + t.Fatalf("Failed to deserialize cert chain: %v", err) + } sk := config.SigstoreKeys{ - CertificateAuthorities: []config.CertificateAuthority{{ - Subject: config.DistinguishedName{ + CertificateAuthorities: []*config.CertificateAuthority{{ + Subject: &config.DistinguishedName{ Organization: "testorg", CommonName: "testcommonname", }, - CertChain: []byte(certChain), + CertChain: certChain, + }}, + Ctlogs: []*config.TransparencyLogInstance{{ + LogId: &config.LogID{KeyId: []byte(ctfeLogID)}, + PublicKey: pbpk, }}, - CTLogs: []config.TransparencyLogInstance{{LogID: ctfeLogID, PublicKey: []byte(ctfePublicKey)}}, } c := &config.Config{ SigstoreKeysConfig: &config.SigstoreKeysMap{ - SigstoreKeys: map[string]config.SigstoreKeys{ - "test-trust-root": sk, + SigstoreKeys: map[string]*config.SigstoreKeys{ + "test-trust-root": &sk, }, }, } - marshalledPK, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(ctfePublicKey)) - if err != nil { - t.Fatalf("Failed to unmarshal CTLog public key: %v", err) - } testCtx := config.ToContext(context.Background(), c) @@ -3042,7 +3049,7 @@ func TestFulcioCertsFromAuthority(t *testing.T) { } func TestRekorClientAndKeysFromAuthority(t *testing.T) { - pk, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(rekorPublicKey)) + pbpk, pk, err := config.DeserializePublicKey([]byte(rekorPublicKey)) if err != nil { t.Fatalf("Failed to unmarshal public key for testing: %v", err) } @@ -3066,16 +3073,16 @@ func TestRekorClientAndKeysFromAuthority(t *testing.T) { } sk := config.SigstoreKeys{ - TLogs: []config.TransparencyLogInstance{{ - PublicKey: []byte(rekorPublicKey), - LogID: rekorLogID, - BaseURL: *apis.HTTPS("rekor.example.com"), + Tlogs: []*config.TransparencyLogInstance{{ + PublicKey: pbpk, + LogId: &config.LogID{KeyId: []byte(rekorLogID)}, + BaseUrl: "rekor.example.com", }}, } c := &config.Config{ SigstoreKeysConfig: &config.SigstoreKeysMap{ - SigstoreKeys: map[string]config.SigstoreKeys{ - "test-trust-root": sk, + SigstoreKeys: map[string]*config.SigstoreKeys{ + "test-trust-root": &sk, }, }, } @@ -3155,11 +3162,15 @@ func TestRekorClientAndKeysFromAuthority(t *testing.T) { } func TestCheckOptsFromAuthority(t *testing.T) { - pk, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(rekorPublicKey)) + pbpkRekor, pkRekor, err := config.DeserializePublicKey([]byte(rekorPublicKey)) if err != nil { t.Fatalf("Failed to unmarshal public key for testing: %v", err) } - ecpk, ok := pk.(*ecdsa.PublicKey) + pbpkCTFE, pkCTFE, err := config.DeserializePublicKey([]byte(ctfePublicKey)) + if err != nil { + t.Fatalf("Failed to unmarshal public key for testing: %v", err) + } + ecpk, ok := pkRekor.(*ecdsa.PublicKey) if !ok { t.Fatalf("pk is not a ecsda public key") } @@ -3204,49 +3215,54 @@ func TestCheckOptsFromAuthority(t *testing.T) { t.Fatalf("Failed to get embedded CTLog Public keys for testing") } - marshalledPK, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(ctfePublicKey)) - if err != nil { - t.Fatalf("Failed to unmarshal CTLog public key: %v", err) - } - skRekor := config.SigstoreKeys{ - TLogs: []config.TransparencyLogInstance{{ - PublicKey: []byte(rekorPublicKey), - LogID: "rekor-logid", - BaseURL: *apis.HTTPS("rekor.example.com"), + Tlogs: []*config.TransparencyLogInstance{{ + PublicKey: pbpkRekor, + LogId: &config.LogID{KeyId: []byte("rekor-logid")}, + BaseUrl: "rekor.example.com", }}, } + certChainPB, err := config.DeserializeCertChain([]byte(certChain)) + if err != nil { + t.Fatalf("Failed to unmarshal cert chain for testing: %v", err) + } skFulcio := config.SigstoreKeys{ - CertificateAuthorities: []config.CertificateAuthority{{ - Subject: config.DistinguishedName{ + CertificateAuthorities: []*config.CertificateAuthority{{ + Subject: &config.DistinguishedName{ Organization: "testorg", CommonName: "testcommonname", }, - CertChain: []byte(certChain), + CertChain: certChainPB, + }}, + Ctlogs: []*config.TransparencyLogInstance{{ + LogId: &config.LogID{KeyId: []byte(ctfeLogID)}, + PublicKey: pbpkCTFE, }}, - CTLogs: []config.TransparencyLogInstance{{LogID: ctfeLogID, PublicKey: []byte(ctfePublicKey)}}, } skCombined := config.SigstoreKeys{ - TLogs: []config.TransparencyLogInstance{{ - PublicKey: []byte(rekorPublicKey), - LogID: "rekor-logid", - BaseURL: *apis.HTTPS("rekor.example.com"), + Tlogs: []*config.TransparencyLogInstance{{ + PublicKey: pbpkRekor, + LogId: &config.LogID{KeyId: []byte("rekor-logid")}, + BaseUrl: "rekor.example.com", }}, - CertificateAuthorities: []config.CertificateAuthority{{ - Subject: config.DistinguishedName{ + CertificateAuthorities: []*config.CertificateAuthority{{ + Subject: &config.DistinguishedName{ Organization: "testorg", CommonName: "testcommonname", }, - CertChain: []byte(certChain), + CertChain: certChainPB, + }}, + Ctlogs: []*config.TransparencyLogInstance{{ + LogId: &config.LogID{KeyId: []byte(ctfeLogID)}, + PublicKey: pbpkCTFE, }}, - CTLogs: []config.TransparencyLogInstance{{LogID: ctfeLogID, PublicKey: []byte(ctfePublicKey)}}, } c := &config.Config{ SigstoreKeysConfig: &config.SigstoreKeysMap{ - SigstoreKeys: map[string]config.SigstoreKeys{ - "test-trust-rekor": skRekor, - "test-trust-fulcio": skFulcio, - "test-trust-combined": skCombined, + SigstoreKeys: map[string]*config.SigstoreKeys{ + "test-trust-rekor": &skRekor, + "test-trust-fulcio": &skFulcio, + "test-trust-combined": &skCombined, }, }, } @@ -3312,7 +3328,7 @@ func TestCheckOptsFromAuthority(t *testing.T) { RootCerts: roots, IntermediateCerts: intermediates, IgnoreTlog: true, - CTLogPubKeys: &cosign.TrustedTransparencyLogPubKeys{Keys: map[string]cosign.TransparencyLogPubKey{ctfeLogID: {PubKey: marshalledPK, Status: tuf.Active}}}, + CTLogPubKeys: &cosign.TrustedTransparencyLogPubKeys{Keys: map[string]cosign.TransparencyLogPubKey{ctfeLogID: {PubKey: pkCTFE, Status: tuf.Active}}}, }, }, { name: "trustroot found, combined, with Identities", @@ -3337,7 +3353,7 @@ func TestCheckOptsFromAuthority(t *testing.T) { Issuer: "issuer", Subject: "subject", }}, - CTLogPubKeys: &cosign.TrustedTransparencyLogPubKeys{Keys: map[string]cosign.TransparencyLogPubKey{ctfeLogID: {PubKey: marshalledPK, Status: tuf.Active}}}, + CTLogPubKeys: &cosign.TrustedTransparencyLogPubKeys{Keys: map[string]cosign.TransparencyLogPubKey{ctfeLogID: {PubKey: pkCTFE, Status: tuf.Active}}}, }, }} diff --git a/test/e2e_test_trustroot_crd.sh b/test/e2e_test_trustroot_crd.sh index 88757b71..fbfc9e5f 100755 --- a/test/e2e_test_trustroot_crd.sh +++ b/test/e2e_test_trustroot_crd.sh @@ -36,19 +36,25 @@ echo '::endgroup::' echo '::group:: Validating the configmap entries' echo "Validating Fulcio entry" -kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.certificateAuthorities[0].certChain' | base64 -d > ./got.fulcio.pem +echo -n > ./got.fulcio.pem +for cert in $(kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.certificateAuthorities[0].certChain.certificates[] | .rawBytes' ); do + echo $cert | base64 -d | openssl x509 -inform der >> ./got.fulcio.pem +done diff ./got.fulcio.pem ./test/testdata/trustroot/golden/fulcio.crt.pem echo "Validating TSA entry" -kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.timestampAuthorities[0].certChain' | base64 -d > ./got.tsa.pem +echo -n > ./got.tsa.pem +for cert in $(kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.timestampAuthorities[0].certChain.certificates[] | .rawBytes' ); do + echo $cert | base64 -d | openssl x509 -inform der >> ./got.tsa.pem +done diff ./got.tsa.pem ./test/testdata/trustroot/golden/tsa.crt.pem echo "Validating Rekor entry" -kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.tLogs[0].publicKey' | base64 -d > ./got.rekor.pem +kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.tlogs[0].publicKey.rawBytes' | base64 -d | openssl pkey -pubin -inform der > ./got.rekor.pem diff ./got.rekor.pem ./test/testdata/trustroot/golden/rekor.pem echo "Validating CTLog entry" -kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.ctLogs[0].publicKey' | base64 -d > ./got.ctfe.pem +kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.ctlogs[0].publicKey.rawBytes' | base64 -d | openssl pkey -pubin -inform der > ./got.ctfe.pem diff ./got.ctfe.pem ./test/testdata/trustroot/golden/ctfe.pem kubectl delete -f ./test/testdata/trustroot/valid/valid-sigstore-keys.yaml