diff --git a/cmd/notation/blob/verify.go b/cmd/notation/blob/verify.go index f0c2c1875..229112f50 100644 --- a/cmd/notation/blob/verify.go +++ b/cmd/notation/blob/verify.go @@ -20,12 +20,11 @@ import ( "path/filepath" "strings" - "github.com/notaryproject/notation-core-go/signature/cose" - "github.com/notaryproject/notation-core-go/signature/jws" "github.com/notaryproject/notation-go" "github.com/notaryproject/notation/cmd/notation/internal/display" "github.com/notaryproject/notation/cmd/notation/internal/option" "github.com/notaryproject/notation/internal/cmd" + "github.com/notaryproject/notation/internal/envelope" "github.com/notaryproject/notation/internal/ioutil" "github.com/spf13/cobra" ) @@ -155,19 +154,16 @@ func runVerify(command *cobra.Command, cmdOpts *blobVerifyOpts) error { // `application/jose+json` and `application/cose` are supported. func parseSignatureMediaType(signaturePath string) (string, error) { signatureFileName := filepath.Base(signaturePath) + if filepath.Ext(signatureFileName) != ".sig" { + return "", fmt.Errorf("invalid signature filename %s. The file extension must be .sig", signatureFileName) + } sigFilenameArr := strings.Split(signatureFileName, ".") // a valid signature file name has at least 3 parts. // for example, `myFile.jws.sig` if len(sigFilenameArr) < 3 { - return "", fmt.Errorf("invalid signature filename %s", signatureFileName) - } - format := sigFilenameArr[len(sigFilenameArr)-2] - switch format { - case "cose": - return cose.MediaTypeEnvelope, nil - case "jws": - return jws.MediaTypeEnvelope, nil + return "", fmt.Errorf("invalid signature filename %s. A valid signature file name must contain signature format and .sig file extension", signatureFileName) } - return "", fmt.Errorf("unsupported signature format %s", format) + sigFormat := sigFilenameArr[len(sigFilenameArr)-2] + return envelope.GetEnvelopeMediaType(sigFormat) } diff --git a/cmd/notation/internal/display/handler.go b/cmd/notation/internal/display/handler.go index f23ce96cb..02cec17f1 100644 --- a/cmd/notation/internal/display/handler.go +++ b/cmd/notation/internal/display/handler.go @@ -49,7 +49,7 @@ func NewVerifyHandler(printer *output.Printer) metadata.VerifyHandler { } // NewBlobVerifyHandler creates a new metadata BlobVerifyHandler for printing -// blob veriifcation result and warnings. +// blob verification result and warnings. func NewBlobVerifyHandler(printer *output.Printer) metadata.BlobVerifyHandler { return text.NewBlobVerifyHandler(printer) } diff --git a/cmd/notation/internal/display/metadata/text/base.go b/cmd/notation/internal/display/metadata/text/base.go index e6844ff9c..299b4db90 100644 --- a/cmd/notation/internal/display/metadata/text/base.go +++ b/cmd/notation/internal/display/metadata/text/base.go @@ -25,8 +25,8 @@ import ( "github.com/notaryproject/notation/cmd/notation/internal/display/output" ) -// PrintVerificationSuccess prints out messages when verification succeeds -func PrintVerificationSuccess(printer *output.Printer, outcome *notation.VerificationOutcome, printout string, hasWarning bool) error { +// printVerificationSuccess prints out messages when verification succeeds +func printVerificationSuccess(printer *output.Printer, outcome *notation.VerificationOutcome, printout string, hasWarning bool) error { // write out on success // print out warning for any failed result with logged verification action for _, result := range outcome.VerificationResults { @@ -45,13 +45,13 @@ func PrintVerificationSuccess(printer *output.Printer, outcome *notation.Verific printer.Println("Trust policy is configured to skip signature verification for", printout) } else { printer.Println("Successfully verified signature for", printout) - PrintUserMetadataIfPresent(printer, outcome) + printUserMetadataIfPresent(printer, outcome) } return nil } -// PrintUserMetadataIfPresent prints out user metadata if present -func PrintUserMetadataIfPresent(printer *output.Printer, outcome *notation.VerificationOutcome) { +// printUserMetadataIfPresent prints out user metadata if present +func printUserMetadataIfPresent(printer *output.Printer, outcome *notation.VerificationOutcome) { // the signature envelope is parsed as part of verification. // since user metadata is only printed on successful verification, // this error can be ignored. diff --git a/cmd/notation/internal/display/metadata/text/base_test.go b/cmd/notation/internal/display/metadata/text/base_test.go index 0466f849f..ce5abf7fe 100644 --- a/cmd/notation/internal/display/metadata/text/base_test.go +++ b/cmd/notation/internal/display/metadata/text/base_test.go @@ -47,7 +47,7 @@ func TestPrintMetadataIfPresent(t *testing.T) { buf := bytes.Buffer{} printer := output.NewPrinter(&buf, &buf) h := NewVerifyHandler(printer) - PrintUserMetadataIfPresent(h.printer, outcome) + printUserMetadataIfPresent(h.printer, outcome) got := buf.String() expected := "\nThe artifact was signed with the following user metadata.\n\nKEY VALUE \nfoo bar \n" if got != expected { diff --git a/cmd/notation/internal/display/metadata/text/blobverify.go b/cmd/notation/internal/display/metadata/text/blobverify.go index 03b13143b..6160b3865 100644 --- a/cmd/notation/internal/display/metadata/text/blobverify.go +++ b/cmd/notation/internal/display/metadata/text/blobverify.go @@ -44,5 +44,5 @@ func (h *BlobVerifyHandler) OnVerifySucceeded(outcomes []*notation.VerificationO // Render prints out the verification results in human-readable format. func (h *BlobVerifyHandler) Render() error { - return PrintVerificationSuccess(h.printer, h.outcome, h.blobPath, false) + return printVerificationSuccess(h.printer, h.outcome, h.blobPath, false) } diff --git a/cmd/notation/internal/display/metadata/text/verify.go b/cmd/notation/internal/display/metadata/text/verify.go index 4d64de15b..743e17d4a 100644 --- a/cmd/notation/internal/display/metadata/text/verify.go +++ b/cmd/notation/internal/display/metadata/text/verify.go @@ -50,5 +50,5 @@ func (h *VerifyHandler) OnVerifySucceeded(outcomes []*notation.VerificationOutco // Render prints out the verification results in human-readable format. func (h *VerifyHandler) Render() error { - return PrintVerificationSuccess(h.printer, h.outcome, h.digestReference, h.hasWarning) + return printVerificationSuccess(h.printer, h.outcome, h.digestReference, h.hasWarning) } diff --git a/test/e2e/suite/command/blob/verify.go b/test/e2e/suite/command/blob/verify.go index c18093716..22c8eb45e 100644 --- a/test/e2e/suite/command/blob/verify.go +++ b/test/e2e/suite/command/blob/verify.go @@ -17,6 +17,7 @@ import ( "fmt" "os" "path/filepath" + "strings" . "github.com/notaryproject/notation/test/e2e/internal/notation" "github.com/notaryproject/notation/test/e2e/internal/utils" @@ -201,6 +202,40 @@ var _ = Describe("notation blob verify", func() { }) }) + It("with invalid signature file extension", func() { + HostWithBlob(BaseBlobOptions(), func(notation *utils.ExecOpts, blobPath string, vhost *utils.VirtualHost) { + workDir := vhost.AbsolutePath() + notation.WithWorkDir(workDir).Exec("blob", "sign", blobPath). + MatchKeyWords(SignSuccessfully). + MatchKeyWords("Signature file written to") + + signaturePath := signatureFilepath(workDir, blobPath, "jws") + invalidSignaturePath := strings.TrimSuffix(signaturePath, ".sig") + "." + "invalid" + if err := os.Rename(signaturePath, invalidSignaturePath); err != nil { + Fail(err.Error()) + } + notation.ExpectFailure().Exec("blob", "verify", "--signature", invalidSignaturePath, blobPath). + MatchErrKeyWords(`invalid signature filename blobFile.txt.jws.invalid. The file extension must be .sig`) + }) + }) + + It("with invalid signature file name", func() { + HostWithBlob(BaseBlobOptions(), func(notation *utils.ExecOpts, blobPath string, vhost *utils.VirtualHost) { + workDir := vhost.AbsolutePath() + notation.WithWorkDir(workDir).Exec("blob", "sign", blobPath). + MatchKeyWords(SignSuccessfully). + MatchKeyWords("Signature file written to") + + signaturePath := signatureFilepath(workDir, blobPath, "jws") + invalidSignaturePath := strings.TrimSuffix(signaturePath, ".jws.sig") + if err := os.Rename(signaturePath, invalidSignaturePath); err != nil { + Fail(err.Error()) + } + notation.ExpectFailure().Exec("blob", "verify", "--signature", invalidSignaturePath, blobPath). + MatchErrKeyWords(`invalid signature filename blobFile.txt. A valid signature file name must contain signature format and .sig file extension`) + }) + }) + It("with invalid signature format", func() { HostWithBlob(BaseBlobOptions(), func(notation *utils.ExecOpts, blobPath string, vhost *utils.VirtualHost) { workDir := vhost.AbsolutePath() @@ -214,7 +249,7 @@ var _ = Describe("notation blob verify", func() { Fail(err.Error()) } notation.ExpectFailure().Exec("blob", "verify", "--signature", invalidSignaturePath, blobPath). - MatchErrKeyWords("unsupported signature format invalid") + MatchErrKeyWords(`signature format "invalid" not supported\nSupported signature envelope formats are "jws" and "cose"`) }) })