mirror of
https://github.com/slsa-framework/slsa-verifier.git
synced 2026-08-26 09:37:19 +00:00
remove --public-key-hash-algo, make verified-levels an array
Signed-off-by: Ramon Petgrave <ramon.petgrave64@gmail.com>
This commit is contained in:
@@ -502,16 +502,15 @@ Usage:
|
||||
slsa-verifier verify-vsa [flags] subject-digest [subject-digest...]
|
||||
|
||||
Flags:
|
||||
--attestations-path string path to a file containing the attestations
|
||||
-h, --help help for verify-vsa
|
||||
--print-attestation [optional] print the contents of attestation to stdout
|
||||
--public-key-signing-hash-algo string [optional] the hash algorithm used to compute the digest to be signed, one of SHA256 [default], SHA384, or SHA512
|
||||
--public-key-id string [optional] the ID of the public key, defaults to the SHA256 digest of the base64-encoded public key
|
||||
--public-key-path string path to a public key file
|
||||
--resource-uri string the resource URI to be verified
|
||||
--subject-digest stringArray the digests to be verified. Pass multiple digests by repeating the flag. e.g. <digest type>:<digest value>
|
||||
--verified-levels strings [optional] the levels of verification to be performed, comma-separated. e.g., 'SLSA_BUILD_LEVEL_2,FEDRAMP_LOW'
|
||||
--verifier-id string the unique verifier ID who created the attestations
|
||||
--attestation-path string path to a file containing the attestation
|
||||
-h, --help help for verify-vsa
|
||||
--print-attestation [optional] print the contents of attestation to stdout
|
||||
--public-key-id string [optional] the ID of the public key, defaults to the SHA256 digest of the base64-encoded public key
|
||||
--public-key-path string path to a public key file
|
||||
--resource-uri string the resource URI to be verified
|
||||
--subject-digest stringArray the digests to be verified. Pass multiple digests by repeating the flag. e.g. --subject-digest <digest type>:<digest value> --subject-digest <digest type>:<digest value>
|
||||
--verified-level stringArray [optional] the levels of verification to be performed. Pass multiple digests by repeating the flag, e.g., --verified-level SLSA_BUILD_LEVEL_2 --verified-level FEDRAMP_LOW'
|
||||
--verifier-id string the unique verifier ID who created the attestation
|
||||
```
|
||||
|
||||
To verify VSAs, invoke like this
|
||||
|
||||
@@ -1801,61 +1801,39 @@ func Test_runVerifyVSA(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
attestationPath *string
|
||||
subjectDigests *[]string
|
||||
verifierID *string
|
||||
resourceURI *string
|
||||
verifiedLevels *[]string
|
||||
publicKeyPath *string
|
||||
publicKeyID *string
|
||||
publicKeyHashAlgo *string
|
||||
err error
|
||||
name string
|
||||
attestationPath *string
|
||||
subjectDigests *[]string
|
||||
verifierID *string
|
||||
resourceURI *string
|
||||
verifiedLevels *[]string
|
||||
publicKeyPath *string
|
||||
publicKeyID *string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "success: gke",
|
||||
attestationPath: pointerTo("gce/v1/gke-gce-pre.bcid-vsa.jsonl"),
|
||||
subjectDigests: pointerTo([]string{"gce_image_id:8970095005306000053"}),
|
||||
verifierID: pointerTo("https://bcid.corp.google.com/verifier/bcid_package_enforcer/v0.1"),
|
||||
resourceURI: pointerTo("gce_image://gke-node-images:gke-12615-gke1418000-cos-101-17162-463-29-c-cgpv1-pre"),
|
||||
verifiedLevels: pointerTo([]string{"BCID_L1", "SLSA_BUILD_LEVEL_2"}),
|
||||
publicKeyPath: pointerTo("gce/v1/vsa_signing_public_key.pem"),
|
||||
publicKeyID: pointerTo("keystore://76574:prod:vsa_signing_public_key"),
|
||||
publicKeyHashAlgo: pointerTo("SHA256"),
|
||||
name: "success: gke",
|
||||
attestationPath: pointerTo("gce/v1/gke-gce-pre.bcid-vsa.jsonl"),
|
||||
subjectDigests: pointerTo([]string{"gce_image_id:8970095005306000053"}),
|
||||
verifierID: pointerTo("https://bcid.corp.google.com/verifier/bcid_package_enforcer/v0.1"),
|
||||
resourceURI: pointerTo("gce_image://gke-node-images:gke-12615-gke1418000-cos-101-17162-463-29-c-cgpv1-pre"),
|
||||
verifiedLevels: pointerTo([]string{"BCID_L1", "SLSA_BUILD_LEVEL_2"}),
|
||||
publicKeyPath: pointerTo("gce/v1/vsa_signing_public_key.pem"),
|
||||
publicKeyID: pointerTo("keystore://76574:prod:vsa_signing_public_key"),
|
||||
},
|
||||
{
|
||||
name: "success: gke, default public key hash algo",
|
||||
attestationPath: pointerTo("gce/v1/gke-gce-pre.bcid-vsa.jsonl"),
|
||||
subjectDigests: pointerTo([]string{"gce_image_id:8970095005306000053"}),
|
||||
verifierID: pointerTo("https://bcid.corp.google.com/verifier/bcid_package_enforcer/v0.1"),
|
||||
resourceURI: pointerTo("gce_image://gke-node-images:gke-12615-gke1418000-cos-101-17162-463-29-c-cgpv1-pre"),
|
||||
verifiedLevels: pointerTo([]string{"BCID_L1", "SLSA_BUILD_LEVEL_2"}),
|
||||
publicKeyPath: pointerTo("gce/v1/vsa_signing_public_key.pem"),
|
||||
publicKeyID: pointerTo("keystore://76574:prod:vsa_signing_public_key"),
|
||||
publicKeyHashAlgo: pointerTo(""),
|
||||
name: "fail: gke, empty public key id",
|
||||
attestationPath: pointerTo("gce/v1/gke-gce-pre.bcid-vsa.jsonl"),
|
||||
publicKeyPath: pointerTo("gce/v1/vsa_signing_public_key.pem"),
|
||||
publicKeyID: pointerTo(""),
|
||||
err: serrors.ErrorNoValidSignature,
|
||||
},
|
||||
{
|
||||
name: "fail: gke, unsupported public key hash algo",
|
||||
attestationPath: pointerTo("gce/v1/gke-gce-pre.bcid-vsa.jsonl"),
|
||||
publicKeyPath: pointerTo("gce/v1/vsa_signing_public_key.pem"),
|
||||
publicKeyHashAlgo: pointerTo("SHA123"),
|
||||
err: serrors.ErrorInvalidHashAlgo,
|
||||
},
|
||||
{
|
||||
name: "fail: gke, wrong public key hash algo",
|
||||
attestationPath: pointerTo("gce/v1/gke-gce-pre.bcid-vsa.jsonl"),
|
||||
publicKeyPath: pointerTo("gce/v1/vsa_signing_public_key.pem"),
|
||||
publicKeyID: pointerTo(""),
|
||||
publicKeyHashAlgo: pointerTo("SHA512"),
|
||||
err: serrors.ErrorNoValidSignature,
|
||||
},
|
||||
{
|
||||
name: "fail: gke, wrong key id",
|
||||
attestationPath: pointerTo("gce/v1/gke-gce-pre.bcid-vsa.jsonl"),
|
||||
publicKeyPath: pointerTo("gce/v1/vsa_signing_public_key.pem"),
|
||||
publicKeyID: pointerTo("my_key_id"),
|
||||
publicKeyHashAlgo: pointerTo("SHA256"),
|
||||
err: serrors.ErrorNoValidSignature,
|
||||
name: "fail: gke, wrong key id",
|
||||
attestationPath: pointerTo("gce/v1/gke-gce-pre.bcid-vsa.jsonl"),
|
||||
publicKeyPath: pointerTo("gce/v1/vsa_signing_public_key.pem"),
|
||||
publicKeyID: pointerTo("my_key_id"),
|
||||
err: serrors.ErrorNoValidSignature,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1868,14 +1846,13 @@ func Test_runVerifyVSA(t *testing.T) {
|
||||
publicKeyPath := filepath.Clean(filepath.Join(TEST_DIR, "vsa", *tt.publicKeyPath))
|
||||
|
||||
cmd := verify.VerifyVSACommand{
|
||||
AttestationPath: &attestationPath,
|
||||
SubjectDigests: tt.subjectDigests,
|
||||
VerifierID: tt.verifierID,
|
||||
ResourceURI: tt.resourceURI,
|
||||
VerifiedLevels: tt.verifiedLevels,
|
||||
PublicKeyPath: &publicKeyPath,
|
||||
PublicKeyID: tt.publicKeyID,
|
||||
PublicKeyHashAlgo: tt.publicKeyHashAlgo,
|
||||
AttestationPath: &attestationPath,
|
||||
SubjectDigests: tt.subjectDigests,
|
||||
VerifierID: tt.verifierID,
|
||||
ResourceURI: tt.resourceURI,
|
||||
VerifiedLevels: tt.verifiedLevels,
|
||||
PublicKeyPath: &publicKeyPath,
|
||||
PublicKeyID: tt.publicKeyID,
|
||||
}
|
||||
|
||||
err := cmd.Exec(context.Background())
|
||||
|
||||
@@ -194,15 +194,14 @@ func verifyVSACmd() *cobra.Command {
|
||||
Short: "Verifies SLSA VSAs for the given subject-digests",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
v := verify.VerifyVSACommand{
|
||||
SubjectDigests: &o.SubjectDigests,
|
||||
AttestationPath: &o.AttestationPath,
|
||||
VerifierID: &o.VerifierID,
|
||||
ResourceURI: &o.ResourceURI,
|
||||
VerifiedLevels: &o.VerifiedLevels,
|
||||
PrintAttestation: o.PrintAttestation,
|
||||
PublicKeyPath: &o.PublicKeyPath,
|
||||
PublicKeyID: &o.PublicKeyID,
|
||||
PublicKeyHashAlgo: &o.PublicKeyHashAlgo,
|
||||
SubjectDigests: &o.SubjectDigests,
|
||||
AttestationPath: &o.AttestationPath,
|
||||
VerifierID: &o.VerifierID,
|
||||
ResourceURI: &o.ResourceURI,
|
||||
VerifiedLevels: &o.VerifiedLevels,
|
||||
PrintAttestation: o.PrintAttestation,
|
||||
PublicKeyPath: &o.PublicKeyPath,
|
||||
PublicKeyID: &o.PublicKeyID,
|
||||
}
|
||||
if err := v.Exec(cmd.Context()); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: %v\n", FAILURE, err)
|
||||
|
||||
@@ -129,15 +129,14 @@ func (o *VerifyNpmOptions) AddFlags(cmd *cobra.Command) {
|
||||
|
||||
// VerifyVSAOptions is the top-level options for the `verifyVSA` command.
|
||||
type VerifyVSAOptions struct {
|
||||
SubjectDigests []string
|
||||
AttestationPath string
|
||||
VerifierID string
|
||||
ResourceURI string
|
||||
VerifiedLevels []string
|
||||
PublicKeyPath string
|
||||
PublicKeyID string
|
||||
PublicKeyHashAlgo string
|
||||
PrintAttestation bool
|
||||
SubjectDigests []string
|
||||
AttestationPath string
|
||||
VerifierID string
|
||||
ResourceURI string
|
||||
VerifiedLevels []string
|
||||
PublicKeyPath string
|
||||
PublicKeyID string
|
||||
PrintAttestation bool
|
||||
}
|
||||
|
||||
var _ Interface = (*VerifyVSAOptions)(nil)
|
||||
@@ -145,7 +144,7 @@ var _ Interface = (*VerifyVSAOptions)(nil)
|
||||
// AddFlags implements Interface.
|
||||
func (o *VerifyVSAOptions) AddFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringArrayVar(&o.SubjectDigests, "subject-digest", []string{},
|
||||
"the digests to be verified. Pass multiple digests by repeating the flag. e.g. <digest type>:<digest value>")
|
||||
"the digests to be verified. Pass multiple digests by repeating the flag. e.g. --subject-digest <digest type>:<digest value> --subject-digest <digest type>:<digest value>")
|
||||
|
||||
cmd.Flags().StringVar(&o.AttestationPath, "attestation-path", "",
|
||||
"path to a file containing the attestation")
|
||||
@@ -156,8 +155,8 @@ func (o *VerifyVSAOptions) AddFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringVar(&o.ResourceURI, "resource-uri", "",
|
||||
"the resource URI to be verified")
|
||||
|
||||
cmd.Flags().StringSliceVar(&o.VerifiedLevels, "verified-levels", []string{},
|
||||
"[optional] the levels of verification to be performed, comma-separated. e.g., 'SLSA_BUILD_LEVEL_2,FEDRAMP_LOW'")
|
||||
cmd.Flags().StringArrayVar(&o.VerifiedLevels, "verified-level", []string{},
|
||||
"[optional] the levels of verification to be performed. Pass multiple digests by repeating the flag, e.g., --verified-level SLSA_BUILD_LEVEL_2 --verified-level FEDRAMP_LOW'")
|
||||
|
||||
cmd.Flags().BoolVar(&o.PrintAttestation, "print-attestation", false,
|
||||
"[optional] print the contents of attestation to stdout")
|
||||
@@ -168,9 +167,6 @@ func (o *VerifyVSAOptions) AddFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringVar(&o.PublicKeyID, "public-key-id", "",
|
||||
"[optional] the ID of the public key, defaults to the SHA256 digest of the base64-encoded public key")
|
||||
|
||||
cmd.Flags().StringVar(&o.PublicKeyHashAlgo, "public-key-signing-hash-algo", "SHA256",
|
||||
"[optional] the hash algorithm used to compute the digest to be signed, one of SHA256 [default], SHA384, or SHA512")
|
||||
|
||||
cmd.MarkFlagRequired("subject-digests")
|
||||
cmd.MarkFlagRequired("attestation-path")
|
||||
cmd.MarkFlagRequired("verifier-id")
|
||||
|
||||
@@ -17,6 +17,10 @@ package verify
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@@ -28,22 +32,14 @@ import (
|
||||
|
||||
// VerifyVSACommand contains the parameters for the verify-vsa command.
|
||||
type VerifyVSACommand struct {
|
||||
SubjectDigests *[]string
|
||||
AttestationPath *string
|
||||
VerifierID *string
|
||||
ResourceURI *string
|
||||
VerifiedLevels *[]string
|
||||
PrintAttestation bool
|
||||
PublicKeyPath *string
|
||||
PublicKeyID *string
|
||||
PublicKeyHashAlgo *string
|
||||
}
|
||||
|
||||
var hashAlgos = map[string]crypto.Hash{
|
||||
"": crypto.SHA256, // default to SHA256
|
||||
"SHA256": crypto.SHA256,
|
||||
"SHA384": crypto.SHA384,
|
||||
"SHA512": crypto.SHA512,
|
||||
SubjectDigests *[]string
|
||||
AttestationPath *string
|
||||
VerifierID *string
|
||||
ResourceURI *string
|
||||
VerifiedLevels *[]string
|
||||
PrintAttestation bool
|
||||
PublicKeyPath *string
|
||||
PublicKeyID *string
|
||||
}
|
||||
|
||||
// Exec executes the verifiers.VerifyVSA.
|
||||
@@ -65,12 +61,7 @@ func (c *VerifyVSACommand) Exec(ctx context.Context) error {
|
||||
printFailed(err)
|
||||
return err
|
||||
}
|
||||
hashAlgo, ok := hashAlgos[*c.PublicKeyHashAlgo]
|
||||
if !ok {
|
||||
err := fmt.Errorf("%w: %s", serrors.ErrorInvalidHashAlgo, *c.PublicKeyHashAlgo)
|
||||
printFailed(err)
|
||||
return err
|
||||
}
|
||||
hashAlgo := determineSignatureHashAlgo(pubKey)
|
||||
VerificationOpts := &options.VerificationOpts{
|
||||
PublicKey: pubKey,
|
||||
PublicKeyID: c.PublicKeyID,
|
||||
@@ -98,3 +89,29 @@ func (c *VerifyVSACommand) Exec(ctx context.Context) error {
|
||||
func printFailed(err error) {
|
||||
fmt.Fprintf(os.Stderr, "Verifying VSA: FAILED: %v\n\n", err)
|
||||
}
|
||||
|
||||
// determineSignatureHashAlgo determines the hash algorithm used to compute the digest to be signed, based on the public key.
|
||||
// some well-known defaults can be determined, otherwise the it returns crypto.SHA256.
|
||||
func determineSignatureHashAlgo(pubKey crypto.PublicKey) crypto.Hash {
|
||||
var h crypto.Hash
|
||||
switch pk := pubKey.(type) {
|
||||
case *rsa.PublicKey:
|
||||
h = crypto.SHA256
|
||||
case *ecdsa.PublicKey:
|
||||
switch pk.Curve {
|
||||
case elliptic.P256():
|
||||
h = crypto.SHA256
|
||||
case elliptic.P384():
|
||||
h = crypto.SHA384
|
||||
case elliptic.P521():
|
||||
h = crypto.SHA512
|
||||
default:
|
||||
h = crypto.SHA256
|
||||
}
|
||||
case ed25519.PublicKey:
|
||||
h = crypto.SHA512
|
||||
default:
|
||||
h = crypto.SHA256
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ var (
|
||||
ErrorInvalidHash = errors.New("invalid hash")
|
||||
ErrorNotPresent = errors.New("not present")
|
||||
ErrorInvalidPublicKey = errors.New("invalid public key")
|
||||
ErrorInvalidHashAlgo = errors.New("unsupported hash algorithm")
|
||||
ErrorInvalidVerificationResult = errors.New("verificationResult is not PASSED")
|
||||
ErrorMismatchVerifiedLevels = errors.New("verified levels do not match")
|
||||
ErrorMissingSubjectDigest = errors.New("missing subject digest")
|
||||
|
||||
@@ -114,6 +114,25 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeGa6ZCZn0q6WpaUwJrSk+PPYEsca
|
||||
opts: goodVSAOpts,
|
||||
expectedVSA: goodVSA,
|
||||
},
|
||||
{
|
||||
name: "success: sha256 key id in envelope",
|
||||
envelope: &dsse.Envelope{
|
||||
PayloadType: goodEnvelope.PayloadType,
|
||||
Payload: goodEnvelope.Payload,
|
||||
Signatures: []dsse.Signature{
|
||||
{
|
||||
KeyID: "SHA256:Zphi7kubaI7RnOrkqPgkRdVhF5a2JOFB4gor/Zajiiw",
|
||||
Sig: goodEnvelope.Signatures[0].Sig,
|
||||
},
|
||||
},
|
||||
},
|
||||
opts: &options.VerificationOpts{
|
||||
PublicKey: goodVSAOpts.PublicKey,
|
||||
PublicKeyID: pointerTo(""),
|
||||
PublicKeyHashAlgo: crypto.SHA256,
|
||||
},
|
||||
expectedVSA: goodVSA,
|
||||
},
|
||||
{
|
||||
name: "failure: empty signatures",
|
||||
envelope: &dsse.Envelope{
|
||||
|
||||
Reference in New Issue
Block a user