Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support for GCB verification #202

Merged
merged 22 commits into from
Aug 24, 2022
11 changes: 3 additions & 8 deletions cli/slsa-verifier/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strings"

serrors "github.com/slsa-framework/slsa-verifier/errors"

"github.com/slsa-framework/slsa-verifier/options"
"github.com/slsa-framework/slsa-verifier/verifiers"
"github.com/slsa-framework/slsa-verifier/verifiers/container"
Expand Down Expand Up @@ -74,14 +75,8 @@ func main() {
"[optional] a workflow input provided by a user at trigger time in the format 'key=value'. (Only for 'workflow_dispatch' events).")
flag.Parse()

if (provenancePath == "" || artifactPath == "") && artifactImage == "" {
fmt.Fprintf(os.Stderr, "either 'provenance' and 'artifact-path' or 'artifact-image' must be specified\n")
flag.Usage()
os.Exit(1)
}

if artifactImage != "" && (provenancePath != "" || artifactPath != "") {
fmt.Fprintf(os.Stderr, "'provenance' and 'artifact-path' should not be specified when 'artifact-image' is provided\n")
if artifactImage != "" && artifactPath != "" {
fmt.Fprintf(os.Stderr, "'artifact-image' and 'artifact-path' cannot be specified together\n")
flag.Usage()
os.Exit(1)
}
Expand Down
20 changes: 12 additions & 8 deletions cli/slsa-verifier/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ func pString(s string) *string {

const TEST_DIR = "./testdata"

var ARTIFACT_PATH_BUILDERS = []string{"go", "generic"}
var ARTIFACT_IMAGE_BUILDERS = []string{"generic_container"}
var (
ARTIFACT_PATH_BUILDERS = []string{"go", "generic"}
ARTIFACT_IMAGE_BUILDERS = []string{"generic_container"}
)

func getBuildersAndVersions(t *testing.T,
optionalMinVersion string, specifiedBuilders []string,
defaultBuilders []string) []string {
defaultBuilders []string,
) []string {
res := []string{}
builders := specifiedBuilders
if len(builders) == 0 {
Expand Down Expand Up @@ -473,6 +476,7 @@ func Test_runVerifyArtifactPath(t *testing.T) {
for _, tt := range tests {
tt := tt // Re-initializing variable so it is not changed while executing the closure below
t.Run(tt.name, func(t *testing.T) {
// Avoid rate limiting by not running the tests in parallel.
// t.Parallel()

checkVersions := getBuildersAndVersions(t, tt.minversion, tt.builders, ARTIFACT_PATH_BUILDERS)
Expand All @@ -484,8 +488,7 @@ func Test_runVerifyArtifactPath(t *testing.T) {

artifactPath := filepath.Clean(filepath.Join(TEST_DIR, v, tt.artifact))
provenancePath := fmt.Sprintf("%s.intoto.jsonl", artifactPath)

_, outBuilderId, err := runVerify("", artifactPath,
_, outBuilderID, err := runVerify("", artifactPath,
provenancePath,
tt.source, tt.pbranch, tt.pbuilderID,
tt.ptag, tt.pversiontag, tt.inputs)
Expand All @@ -498,8 +501,8 @@ func Test_runVerifyArtifactPath(t *testing.T) {
return
}

if tt.outBuilderID != "" && outBuilderId != tt.outBuilderID {
t.Errorf(cmp.Diff(outBuilderId, tt.outBuilderID))
if tt.outBuilderID != "" && outBuilderID != tt.outBuilderID {
t.Errorf(cmp.Diff(outBuilderID, tt.outBuilderID))
}
}
})
Expand All @@ -511,7 +514,8 @@ func Test_runVerifyArtifactImage(t *testing.T) {

// Override cosign image verification function for local image testing.
container.RunCosignImageVerification = func(ctx context.Context,
image string, co *cosign.CheckOpts) ([]oci.Signature, bool, error) {
image string, co *cosign.CheckOpts,
) ([]oci.Signature, bool, error) {
return cosign.VerifyLocalImageAttestations(ctx, image, co)
}

Expand Down
6 changes: 5 additions & 1 deletion errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ var (
ErrorMismatchVersionedTag = errors.New("tag used to generate the binary does not match provenance")
ErrorInvalidSemver = errors.New("invalid semantic version")
ErrorRekorSearch = errors.New("error searching rekor entries")
ErrorMismatchHash = errors.New("binary artifact hash does not match provenance subject")
ErrorMismatchHash = errors.New("artifact hash does not match provenance subject")
ErrorInvalidRef = errors.New("invalid ref")
ErrorUntrustedReusableWorkflow = errors.New("untrusted reusable workflow")
ErrorNoValidRekorEntries = errors.New("could not find a matching valid signature entry")
ErrorVerifierNotSupported = errors.New("no verifier support the builder")
ErrorNotSupported = errors.New("not supported")
ErrorInvalidFormat = errors.New("invalid format")
ErrorInvalidPEM = errors.New("invalid PEM")
ErrorInvalidSignature = errors.New("invalid signature")
ErrorNoValidSignature = errors.New("no valid signature")
ErrorInternal = errors.New("internal error")
)
2 changes: 1 addition & 1 deletion register/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type SLSAVerifier interface {

// VerifyImage verifies a provenance for a supplied OCI image.
VerifyImage(ctx context.Context,
artifactImage string,
provenance []byte, artifactImage string,
provenanceOpts *options.ProvenanceOpts,
builderOpts *options.BuilderOpts,
) ([]byte, string, error)
Expand Down
12 changes: 12 additions & 0 deletions verifiers/internal/gcb/keys/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Download the GCB keys

This is a temporary solution. We should try to automate key verification on pre-submits.
We should pin the CA certificate when downloading them, maybe using curl and the googlecloudapi REST endpoint.
See discussion in [#181](https://github.com/slsa-framework/slsa-verifier/issues/181).

For now, you can verify the keys we downloaded by downloading them yourself.

```shell
cd verifiers/internal/gcb/keys
gcloud compute regions list | grep -v NAME | xargs -0 | cut -d ' ' -f1 | xargs -i gcloud kms keys versions get-public-key 1 --location {} --keyring attestor --key builtByGCB --project verified-builder --output-file {}.key
```
63 changes: 63 additions & 0 deletions verifiers/internal/gcb/keys/keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package keys

import (
"crypto/ecdsa"
"crypto/x509"
"embed"
"encoding/pem"
"fmt"
"io/fs"
"path"

serrors "github.com/slsa-framework/slsa-verifier/errors"
)

//go:embed materials/*
var publicKeys embed.FS

type PublicKey struct {
value []byte
pubKey *ecdsa.PublicKey
region string
// TODO: key type and size
}

func PublicKeyNew(region string) (*PublicKey, error) {
content, err := fs.ReadFile(publicKeys, path.Join("materials", region+".key"))
if err != nil {
return nil, fmt.Errorf("%w: cannot read key materials", err)
}

block, _ := pem.Decode(content)
if block == nil {
return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidPEM, content)
}

key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("x509.ParsePKIXPublicKey: %w", err)
}

pubKey, ok := key.(*ecdsa.PublicKey)
if !ok {
return nil, fmt.Errorf("%w: public key not of type ECDSA", err)
}

return &PublicKey{
value: content,
pubKey: pubKey,
region: region,
}, nil
}

func (self *PublicKey) VerifySignature(digest [32]byte, sig []byte) error {
if self.pubKey == nil {
return fmt.Errorf("%w: key is empty", serrors.ErrorInternal)
}
if !ecdsa.VerifyASN1(self.pubKey, digest[:], sig) {
return fmt.Errorf("%w: cannot verify with public key '%v'",
serrors.ErrorInvalidSignature, string(self.region))
}

return nil
}
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/asia-east1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAED19/xPzO6sLFZxDzsItbVQSLMPBS
w7iVGtkXyNicWdplf4pXm6wFyZ/HyqL0Acd4Q3gfJvtVIY3HiAzjohx0cw==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/asia-northeast1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4RlI/MHfE9ZjKba6rMSGu3A/M0FH
UPBu4anB9yXC+8ubmMBAWIoqgXr7CYGBenw27YasBOQhyGgZQSe9sF+DhQ==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/asia-southeast1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQGLAkRjCFqZbdd4BjhNFNS8l9xMJ
K1MVNpTA/K+sGl9+HG0r43MMAIXt6QUst9kCiqiXRp+Oqc0HIGRFZMBFcg==
-----END PUBLIC KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcYAxYYze8pKKoggou7Pz5oAfFv/Y
gWN1HAjtT0v0L6sOOKOXvFNTpjQ8nDz1ooNfuxv8pva6l8ZLICTH10CJog==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/europe-north1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoKSuwi41RBzyWlwYBu61xgVrO6zw
G8yjVsbyha4FfDSPMQ0V8BIJbqOphh40ACwzEKCszMY36d22FJHSLDiNvg==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/europe-west1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDmJxa2BxOnfra0/J4FHf/2yIOElN
p6+ah2tcpK0W8FGFFU3TaC4XEXFKVV/bWmormNDvZGtN710Qi4VforgRzg==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/europe-west2.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfDuhy/obSeBa+RwcAZ3EYFvRJmIT
1+lcAk/yINf0PBysMV9Lg482EEKmq8ce2rTZXuNFxLLMiHENunJ3oGlJIg==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/europe-west3.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWNPQh5Z5gTBJGwINV7nja+uJ0qCD
Pek4yIfgjrhmqM3Cu06kdpfod8TCL7z32uIQTb5VysO4XVhbAY2bN0BAkg==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/europe-west4.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOHbdm8kpkMdEeD0i2WcWFCss620T
ts1x82wakzDELaS4rxDfJ7eSTQOyfQupjDl9M9k99uY8DoX2vAABI8DdoA==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/global.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECGIoAk3mHV8xq/P1x6doSzAJlTaW
YhrmI3rfN5zfk3/Dq6nPpm8D0CMVNyc4HZ5ChTDqTV8EyaR56nLqjvMYUA==
-----END PUBLIC KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExvyU8IkmPjrV8V8dkuBMcOtvJykf
WZhaTuYcOS5KXMVpEllJ3jh9WFyuoG54mVLgFJUQwrYLhUWORRVGH1kskw==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/us-central1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAUqas+Xhfss+NCsiL8ayl1Sxz9TF
bDxLuokg59lGmpm4ca2Idmh1aYt04ZkM8sgXq/FMTXxqISA4dQapp0utZg==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/us-central2.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOBZl8kLzGV63W0ERoHAG0xpkOu+T
zDUzk6kISDonvno/emAacWmrTMxbhDQwRcnTtT9TpUG98+WukL2PDPQ61g==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/us-east1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyWUk6LGBm/wTWioZ7pTA7Ds0sXQd
3Y4HYyF3/Hl/UYNveSBhMdkM4yReQPU2fNh5CkK77+JzGU8NypnvFWYSVQ==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/us-east4.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE88g3xqG/UtPE5LFG3Z6MWpZ/ofJR
E9VHeavlxhNSzV6USMUBJEU3I9/xfanRJUTT4oNdMi7cv5BeCaS2Q3mZ3w==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/us-west1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIZhFqz97qH9dFn23yWYVkwZVYXOA
Hllzqzr14tRkXesHcZoVnekBMBkkIkP+jgechjkjZG3NPssdmIZFZ6+oyA==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/us-west2.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEw/gdczl7qDD4ww9B6WmJ6++/hQ5S
mdw/1RBcwNNQE9qN0O+DilRE9/AjH7OvJUhNznOzEzH7mFq5mNdmUjYlXg==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/us-west3.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEolPSVMeD5XcXCa5gNIdSj51Z4VE7
u3uie+EeCOAAi//g2zj+hsEchXjYA5edo9eH6iv2w1g2DMrNWutW45nRkg==
-----END PUBLIC KEY-----
4 changes: 4 additions & 0 deletions verifiers/internal/gcb/keys/materials/us-west4.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERM4hS/6KZNbEootGWRBc8lmTzIGp
FvCKxVQL2xRU87d4OCyp1iP0IsSe2a1GQPQuK8SD0vwEb9hJDBZaEOF15g==
-----END PUBLIC KEY-----
Loading