remove --public-key-hash-algo, make verified-levels an array

Signed-off-by: Ramon Petgrave <ramon.petgrave64@gmail.com>
This commit is contained in:
Ramon Petgrave
2024-07-01 23:57:16 +00:00
parent 891ffffcb1
commit b145f3605f
7 changed files with 120 additions and 114 deletions
+9 -10
View File
@@ -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
+34 -57
View File
@@ -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())
+8 -9
View File
@@ -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)
+11 -15
View File
@@ -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")
+39 -22
View File
@@ -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
}
-1
View File
@@ -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")
+19
View File
@@ -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{