From 6b61f309893aa1db09160db2c623fc68314baa32 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Tue, 9 Jan 2024 15:49:10 +0000 Subject: [PATCH 1/8] fixed incorrect error message Signed-off-by: chaosinthecrd --- cmd/verify.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/verify.go b/cmd/verify.go index e44af9d3..92be3eeb 100644 --- a/cmd/verify.go +++ b/cmd/verify.go @@ -77,7 +77,7 @@ func runVerify(ctx context.Context, vo options.VerifyOptions) error { inFile, err := os.Open(vo.PolicyFilePath) if err != nil { - return fmt.Errorf("failed to open file to sign: %w", err) + return fmt.Errorf("failed to open policy file: %w", err) } defer inFile.Close() From 273c2498941138787a3427d8c24a92fbf9bd9cb8 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Tue, 9 Jan 2024 16:43:20 +0000 Subject: [PATCH 2/8] adding functions to mark required flags Signed-off-by: chaosinthecrd --- cmd/run.go | 2 +- cmd/verify.go | 2 +- options/run.go | 9 +++++++++ options/sign.go | 6 ++++++ options/verify.go | 11 ++++++++++- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index ad19a30c..c144c85b 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -87,7 +87,7 @@ func runRun(ctx context.Context, ro options.RunOptions, args []string, signers . addtlAttestors, err := attestation.Attestors(ro.Attestations) if err != nil { - return fmt.Errorf("failed to create attestors := %w", err) + return fmt.Errorf("failed to create attestors: %w", err) } attestors = append(attestors, addtlAttestors...) diff --git a/cmd/verify.go b/cmd/verify.go index 92be3eeb..4e39f25c 100644 --- a/cmd/verify.go +++ b/cmd/verify.go @@ -57,7 +57,7 @@ const ( // we need to abstract where keys are coming from, etc func runVerify(ctx context.Context, vo options.VerifyOptions) error { if vo.KeyPath == "" && len(vo.CAPaths) == 0 { - return fmt.Errorf("must suply public key or ca paths") + return fmt.Errorf("must supply public key or ca paths") } var verifier cryptoutil.Verifier diff --git a/options/run.go b/options/run.go index 3cccb3f7..59e9ed98 100644 --- a/options/run.go +++ b/options/run.go @@ -33,6 +33,11 @@ type RunOptions struct { AttestorOptSetters map[string][]func(attestation.Attestor) (attestation.Attestor, error) } +var RequiredRunFlags = []string{ + "outfile", + "step", +} + func (ro *RunOptions) AddFlags(cmd *cobra.Command) { ro.SignerOptions.AddFlags(cmd) ro.ArchivistaOptions.AddFlags(cmd) @@ -44,6 +49,10 @@ func (ro *RunOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&ro.Tracing, "trace", false, "Enable tracing for the command") cmd.Flags().StringSliceVar(&ro.TimestampServers, "timestamp-servers", []string{}, "Timestamp Authority Servers to use when signing envelope") + for _, flag := range RequiredRunFlags { + cmd.MarkFlagRequired(flag) + } + attestationRegistrations := attestation.RegistrationEntries() ro.AttestorOptSetters = addFlagsFromRegistry("attestor", attestationRegistrations, cmd) } diff --git a/options/sign.go b/options/sign.go index 8a909e90..f88060c5 100644 --- a/options/sign.go +++ b/options/sign.go @@ -24,6 +24,12 @@ type SignOptions struct { TimestampServers []string } +var RequiredSignFlags = []string{ + "infile", + "outfile", + "datatype", +} + func (so *SignOptions) AddFlags(cmd *cobra.Command) { so.SignerOptions.AddFlags(cmd) cmd.Flags().StringVarP(&so.DataType, "datatype", "t", "https://witness.testifysec.com/policy/v0.1", "The URI reference to the type of data being signed. Defaults to the Witness policy type") diff --git a/options/verify.go b/options/verify.go index 3a43cd3a..f2a568b9 100644 --- a/options/verify.go +++ b/options/verify.go @@ -14,7 +14,9 @@ package options -import "github.com/spf13/cobra" +import ( + "github.com/spf13/cobra" +) type VerifyOptions struct { ArchivistaOptions ArchivistaOptions @@ -26,6 +28,10 @@ type VerifyOptions struct { CAPaths []string } +var RequiredVerifyFlags = []string{ + "policy", +} + func (vo *VerifyOptions) AddFlags(cmd *cobra.Command) { vo.ArchivistaOptions.AddFlags(cmd) cmd.Flags().StringVarP(&vo.KeyPath, "publickey", "k", "", "Path to the policy signer's public key") @@ -35,4 +41,7 @@ func (vo *VerifyOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringSliceVarP(&vo.AdditionalSubjects, "subjects", "s", []string{}, "Additional subjects to lookup attestations") cmd.Flags().StringSliceVarP(&vo.CAPaths, "policy-ca", "", []string{}, "Paths to CA certificates to use for verifying the policy") + for _, flag := range RequiredVerifyFlags { + cmd.MarkFlagRequired(flag) + } } From 608c958cb33cabb1235fccbf5f893c7fe3d551eb Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Tue, 9 Jan 2024 16:45:12 +0000 Subject: [PATCH 3/8] adding for loop for marking required flags on sign Signed-off-by: chaosinthecrd --- options/sign.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/options/sign.go b/options/sign.go index f88060c5..1bc37aeb 100644 --- a/options/sign.go +++ b/options/sign.go @@ -36,4 +36,8 @@ func (so *SignOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVarP(&so.OutFilePath, "outfile", "o", "", "File to write signed data. Defaults to stdout") cmd.Flags().StringVarP(&so.InFilePath, "infile", "f", "", "Witness policy file to sign") cmd.Flags().StringSliceVar(&so.TimestampServers, "timestamp-servers", []string{}, "Timestamp Authority Servers to use when signing envelope") + + for _, flag := range RequiredSignFlags { + cmd.MarkFlagRequired(flag) + } } From 70ca139edef0c316e4fb686f9b87627ec56b8bd0 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 27 Mar 2024 12:36:18 +0000 Subject: [PATCH 4/8] still need to finish off flags Signed-off-by: chaosinthecrd --- cmd/verify.go | 4 ---- options/sign.go | 1 - options/verify.go | 14 ++++++++++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/cmd/verify.go b/cmd/verify.go index 3b07ed79..9873cfe0 100644 --- a/cmd/verify.go +++ b/cmd/verify.go @@ -64,10 +64,6 @@ const ( // todo: this logic should be broken out and moved to pkg/ // we need to abstract where keys are coming from, etc func runVerify(ctx context.Context, vo options.VerifyOptions, verifiers ...cryptoutil.Verifier) error { - if vo.KeyPath == "" && len(vo.CAPaths) == 0 && len(verifiers) == 0 { - return fmt.Errorf("must supply either a public key, CA certificates or a verifier") - } - if vo.KeyPath != "" { keyFile, err := os.Open(vo.KeyPath) if err != nil { diff --git a/options/sign.go b/options/sign.go index 655f2053..fdc70789 100644 --- a/options/sign.go +++ b/options/sign.go @@ -28,7 +28,6 @@ type SignOptions struct { var RequiredSignFlags = []string{ "infile", "outfile", - "datatype", } func (so *SignOptions) AddFlags(cmd *cobra.Command) { diff --git a/options/verify.go b/options/verify.go index 7fb4c062..9cbb873e 100644 --- a/options/verify.go +++ b/options/verify.go @@ -34,6 +34,17 @@ var RequiredVerifyFlags = []string{ "policy", } +var OneRequiredPKFlags = []string{ + "publickey", + "policy-ca", + "verifier-kms-ref", +} + +var OneRequiredSubjectFlags = []string{ + "artifactfile", + "subjects", +} + func (vo *VerifyOptions) AddFlags(cmd *cobra.Command) { vo.VerifierOptions.AddFlags(cmd) vo.ArchivistaOptions.AddFlags(cmd) @@ -44,4 +55,7 @@ func (vo *VerifyOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVarP(&vo.ArtifactFilePath, "artifactfile", "f", "", "Path to the artifact to verify") cmd.Flags().StringSliceVarP(&vo.AdditionalSubjects, "subjects", "s", []string{}, "Additional subjects to lookup attestations") cmd.Flags().StringSliceVarP(&vo.CAPaths, "policy-ca", "", []string{}, "Paths to CA certificates to use for verifying the policy") + + cmd.MarkFlagsRequiredTogether(RequiredVerifyFlags...) + cmd.MarkFlagsOneRequired(OneRequiredPKFlags...) } From eea7fb2c4b7042cf287aa55cd8d09bd11efcbd34 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 27 Mar 2024 15:10:00 +0000 Subject: [PATCH 5/8] getting ready for final PR review Signed-off-by: chaosinthecrd --- cmd/run.go | 1 + options/run.go | 11 +++++++++-- options/sign.go | 4 +--- options/verify.go | 5 +++-- test/test.sh | 20 ++++++++++++++------ 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index 60a33a9e..5da86471 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -142,6 +142,7 @@ func runRun(ctx context.Context, ro options.RunOptions, args []string, signers . return fmt.Errorf("failed to marshal envelope: %w", err) } + log.Infof("Writing signed envelope to %s\n", ro.OutFilePath) if _, err := out.Write(signedBytes); err != nil { return fmt.Errorf("failed to write envelope to out file: %w", err) } diff --git a/options/run.go b/options/run.go index 72157264..77f40ddb 100644 --- a/options/run.go +++ b/options/run.go @@ -35,8 +35,15 @@ type RunOptions struct { } var RequiredRunFlags = []string{ - "outfile", "step", + // we're going to require an out file path specified as stdout is an unreliable default + "outfile", +} + +var OneRequiredPKSignFlags = []string{ + "signer-file-key-path", + "policy-ca", + "signer-kms-ref", } func (ro *RunOptions) AddFlags(cmd *cobra.Command) { @@ -45,7 +52,7 @@ func (ro *RunOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVarP(&ro.WorkingDir, "workingdir", "d", "", "Directory from which commands will run") cmd.Flags().StringSliceVarP(&ro.Attestations, "attestations", "a", []string{"environment", "git"}, "Attestations to record ('product' and 'material' are always recorded)") cmd.Flags().StringSliceVar(&ro.Hashes, "hashes", []string{"sha256"}, "Hashes selected for digest calculation. Defaults to SHA256") - cmd.Flags().StringVarP(&ro.OutFilePath, "outfile", "o", "", "File to which to write signed data. Defaults to stdout") + cmd.Flags().StringVarP(&ro.OutFilePath, "outfile", "o", "", "File to write signed data to") cmd.Flags().StringVarP(&ro.StepName, "step", "s", "", "Name of the step being run") cmd.Flags().BoolVar(&ro.Tracing, "trace", false, "Enable tracing for the command") cmd.Flags().StringSliceVar(&ro.TimestampServers, "timestamp-servers", []string{}, "Timestamp Authority Servers to use when signing envelope") diff --git a/options/sign.go b/options/sign.go index fdc70789..112993c3 100644 --- a/options/sign.go +++ b/options/sign.go @@ -38,7 +38,5 @@ func (so *SignOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVarP(&so.InFilePath, "infile", "f", "", "Witness policy file to sign") cmd.Flags().StringSliceVar(&so.TimestampServers, "timestamp-servers", []string{}, "Timestamp Authority Servers to use when signing envelope") - for _, flag := range RequiredSignFlags { - cmd.MarkFlagRequired(flag) - } + cmd.MarkFlagsRequiredTogether(RequiredSignFlags...) } diff --git a/options/verify.go b/options/verify.go index 9cbb873e..8b9813d0 100644 --- a/options/verify.go +++ b/options/verify.go @@ -34,7 +34,7 @@ var RequiredVerifyFlags = []string{ "policy", } -var OneRequiredPKFlags = []string{ +var OneRequiredPKVerifyFlags = []string{ "publickey", "policy-ca", "verifier-kms-ref", @@ -57,5 +57,6 @@ func (vo *VerifyOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringSliceVarP(&vo.CAPaths, "policy-ca", "", []string{}, "Paths to CA certificates to use for verifying the policy") cmd.MarkFlagsRequiredTogether(RequiredVerifyFlags...) - cmd.MarkFlagsOneRequired(OneRequiredPKFlags...) + cmd.MarkFlagsOneRequired(OneRequiredPKVerifyFlags...) + cmd.MarkFlagsOneRequired(OneRequiredSubjectFlags...) } diff --git a/test/test.sh b/test/test.sh index 7f1730a3..7c801b9e 100755 --- a/test/test.sh +++ b/test/test.sh @@ -16,27 +16,35 @@ set -e -DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +DIR="$( + cd -- "$(dirname "$0")" >/dev/null 2>&1 + pwd -P +)" . "$DIR/common.sh" -if ! checkprograms make tar ; then - exit 1 +if ! checkprograms make tar; then + exit 1 fi make -C ../ build rm -f ./policy-signed.json ./build.attestation.json ./package.attestation.json ./fail.attestation.json ./testapp ./testapp.tar.tgz +echo "testing signing policy" ../bin/witness -c test.yaml -l debug sign -f policy.json # successful test +echo "testing witness run on build step" ../bin/witness -c test.yaml run -o build.attestation.json -- go build -o=testapp . +echo "testing witness run on packaging step" ../bin/witness -c test.yaml run -s package -k ./testkey2.pem -o package.attestation.json -- tar czf ./testapp.tar.tgz ./testapp +echo "testing witness verify" ../bin/witness -c test.yaml verify # make sure we fail if we run with a key not in the policy -../bin/witness -c test.yaml run -k failkey.pem -o ./fail.attestation.json -- go build -o=testapp . +echo "testing that witness verify fails with a key not in the policy" +../bin/witness -c test.yaml run -k failkey.pem -o ./fail.attestation.json -- go build -o=testapp . ../bin/witness -c test.yaml run -s package -k ./testkey2.pem -o package.attestation.json -- tar czf ./testapp.tar.tgz ./testapp set +e if ../bin/witness -c test.yaml verify -a ./fail.attestation.json -a ./package.attestation.json; then - echo "expected verify to fail" - exit 1 + echo "expected verify to fail" + exit 1 fi From be2397cce94db5c9d0fbd104c16cbe61c7905d74 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 27 Mar 2024 15:17:47 +0000 Subject: [PATCH 6/8] fixed flag check Signed-off-by: chaosinthecrd --- options/run.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/options/run.go b/options/run.go index 77f40ddb..b4585969 100644 --- a/options/run.go +++ b/options/run.go @@ -57,9 +57,7 @@ func (ro *RunOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&ro.Tracing, "trace", false, "Enable tracing for the command") cmd.Flags().StringSliceVar(&ro.TimestampServers, "timestamp-servers", []string{}, "Timestamp Authority Servers to use when signing envelope") - for _, flag := range RequiredRunFlags { - cmd.MarkFlagRequired(flag) - } + cmd.MarkFlagsRequiredTogether(RequiredRunFlags...) attestationRegistrations := attestation.RegistrationEntries() ro.AttestorOptSetters = addFlagsFromRegistry("attestor", attestationRegistrations, cmd) From 61a03a7c6e2e96d38374b8d6d8f348c1307c047f Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 27 Mar 2024 15:28:12 +0000 Subject: [PATCH 7/8] updated doc Signed-off-by: chaosinthecrd --- docs/commands.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/commands.md b/docs/commands.md index 3be39524..97f50617 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -21,7 +21,7 @@ witness run [cmd] [flags] --enable-archivista Use Archivista to store or retrieve attestations --hashes strings Hashes selected for digest calculation. Defaults to SHA256 (default [sha256]) -h, --help help for run - -o, --outfile string File to which to write signed data. Defaults to stdout + -o, --outfile string File to write signed data to --signer-file-cert-path string Path to the file containing the certificate for the private key --signer-file-intermediate-paths strings Paths to files containing intermediates required to establish trust of the signer's certificate to a root -k, --signer-file-key-path string Path to the file containing the private key From 336ad64f1579b3befa62cae3d907415e9b3dc65e Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Fri, 3 May 2024 17:09:30 +0100 Subject: [PATCH 8/8] removing outfile as you can just push to archivista Signed-off-by: chaosinthecrd --- options/run.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/options/run.go b/options/run.go index f500a1af..472d1336 100644 --- a/options/run.go +++ b/options/run.go @@ -38,8 +38,6 @@ type RunOptions struct { var RequiredRunFlags = []string{ "step", - // we're going to require an out file path specified as stdout is an unreliable default - "outfile", } var OneRequiredPKSignFlags = []string{