//go:build sync && scrub && metrics && search // +build sync,scrub,metrics,search package signature_test import ( "encoding/json" "fmt" "os" "path" "testing" notconfig "github.com/notaryproject/notation-go/config" . "github.com/smartystreets/goconvey/convey" "zotregistry.dev/zot/pkg/api" "zotregistry.dev/zot/pkg/api/config" tcommon "zotregistry.dev/zot/pkg/test/common" . "zotregistry.dev/zot/pkg/test/image-utils" signature "zotregistry.dev/zot/pkg/test/signature" ) func TestLoadNotationSigningkeys(t *testing.T) { Convey("notation directory doesn't exist", t, func() { _, err := signature.LoadNotationSigningkeys(t.TempDir()) So(err, ShouldNotBeNil) }) Convey("wrong content of signingkeys.json", t, func() { tempDir := t.TempDir() dir := path.Join(tempDir, "notation") err := os.Mkdir(dir, 0o777) So(err, ShouldBeNil) filePath := path.Join(dir, "signingkeys.json") err = os.WriteFile(filePath, []byte("some dummy file content"), 0o666) //nolint: gosec So(err, ShouldBeNil) _, err = signature.LoadNotationSigningkeys(tempDir) So(err, ShouldNotBeNil) }) Convey("not enough permissions to access signingkeys.json", t, func() { tempDir := t.TempDir() dir := path.Join(tempDir, "notation") err := os.Mkdir(dir, 0o777) So(err, ShouldBeNil) filePath := path.Join(dir, "signingkeys.json") err = os.WriteFile(filePath, []byte("some dummy file content"), 0o300) //nolint: gosec So(err, ShouldBeNil) _, err = signature.LoadNotationSigningkeys(tempDir) So(err, ShouldNotBeNil) }) Convey("signingkeys.json not exists so it is created successfully", t, func() { tempDir := t.TempDir() dir := path.Join(tempDir, "notation") err := os.Mkdir(dir, 0o777) So(err, ShouldBeNil) _, err = signature.LoadNotationSigningkeys(tempDir) So(err, ShouldBeNil) }) Convey("signingkeys.json not exists - error trying to create it", t, func() { tempDir := t.TempDir() dir := path.Join(tempDir, "notation") // create notation directory without write permissions err := os.Mkdir(dir, 0o555) So(err, ShouldBeNil) _, err = signature.LoadNotationSigningkeys(tempDir) So(err, ShouldNotBeNil) }) } func TestLoadNotationConfig(t *testing.T) { Convey("directory doesn't exist", t, func() { _, err := signature.LoadNotationConfig(t.TempDir()) So(err, ShouldNotBeNil) }) Convey("wrong content of signingkeys.json", t, func() { tempDir := t.TempDir() dir := path.Join(tempDir, "notation") err := os.Mkdir(dir, 0o777) So(err, ShouldBeNil) filePath := path.Join(dir, "signingkeys.json") err = os.WriteFile(filePath, []byte("some dummy file content"), 0o666) //nolint: gosec So(err, ShouldBeNil) _, err = signature.LoadNotationConfig(tempDir) So(err, ShouldNotBeNil) }) Convey("check default value of signature format", t, func() { tempDir := t.TempDir() dir := path.Join(tempDir, "notation") err := os.Mkdir(dir, 0o777) So(err, ShouldBeNil) filePath := path.Join(dir, "signingkeys.json") err = os.WriteFile(filePath, []byte("{\"SignatureFormat\": \"\"}"), 0o666) //nolint: gosec So(err, ShouldBeNil) configInfo, err := signature.LoadNotationConfig(tempDir) So(err, ShouldBeNil) So(configInfo.SignatureFormat, ShouldEqual, "jws") }) } func TestSignWithNotation(t *testing.T) { Convey("notation directory doesn't exist", t, func() { err := signature.SignWithNotation("key", "reference", t.TempDir(), true) So(err, ShouldNotBeNil) }) Convey("key not found", t, func() { tempDir := t.TempDir() dir := path.Join(tempDir, "notation") err := os.Mkdir(dir, 0o777) So(err, ShouldBeNil) filePath := path.Join(dir, "signingkeys.json") err = os.WriteFile(filePath, []byte("{}"), 0o666) //nolint: gosec So(err, ShouldBeNil) err = signature.SignWithNotation("key", "reference", tempDir, true) So(err, ShouldEqual, signature.ErrKeyNotFound) }) Convey("not enough permissions to access notation/localkeys dir", t, func() { cwd, err := os.Getwd() So(err, ShouldBeNil) defer func() { _ = os.Chdir(cwd) }() tdir := t.TempDir() _ = os.Chdir(tdir) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tdir) err = signature.GenerateNotationCerts(tdir, "key") So(err, ShouldBeNil) err = os.Chmod(path.Join(tdir, "notation", "localkeys"), 0o000) So(err, ShouldBeNil) err = signature.SignWithNotation("key", "reference", tdir, true) So(err, ShouldNotBeNil) err = os.Chmod(path.Join(tdir, "notation", "localkeys"), 0o755) So(err, ShouldBeNil) }) Convey("error parsing reference", t, func() { cwd, err := os.Getwd() So(err, ShouldBeNil) defer func() { _ = os.Chdir(cwd) }() tdir := t.TempDir() _ = os.Chdir(tdir) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tdir) err = signature.GenerateNotationCerts(tdir, "key") So(err, ShouldBeNil) err = signature.SignWithNotation("key", "invalidReference", tdir, true) So(err, ShouldNotBeNil) }) Convey("error signing", t, func() { cwd, err := os.Getwd() So(err, ShouldBeNil) defer func() { _ = os.Chdir(cwd) }() tdir := t.TempDir() _ = os.Chdir(tdir) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tdir) err = signature.GenerateNotationCerts(tdir, "key") So(err, ShouldBeNil) err = signature.SignWithNotation("key", "localhost:8080/invalidreference:1.0", tdir, true) So(err, ShouldNotBeNil) }) } func TestVerifyWithNotation(t *testing.T) { Convey("notation directory doesn't exist", t, func() { err := signature.VerifyWithNotation("reference", t.TempDir()) So(err, ShouldNotBeNil) }) Convey("error parsing reference", t, func() { cwd, err := os.Getwd() So(err, ShouldBeNil) defer func() { _ = os.Chdir(cwd) }() tdir := t.TempDir() _ = os.Chdir(tdir) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tdir) err = signature.GenerateNotationCerts(tdir, "key") So(err, ShouldBeNil) err = signature.VerifyWithNotation("invalidReference", tdir) So(err, ShouldNotBeNil) }) Convey("error trying to get manifest", t, func() { cwd, err := os.Getwd() So(err, ShouldBeNil) defer func() { _ = os.Chdir(cwd) }() tdir := t.TempDir() _ = os.Chdir(tdir) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tdir) err = signature.GenerateNotationCerts(tdir, "key") So(err, ShouldBeNil) err = signature.VerifyWithNotation("localhost:8080/invalidreference:1.0", tdir) So(err, ShouldNotBeNil) }) Convey("invalid content of trustpolicy.json", t, func() { // start a new server port := tcommon.GetFreePort() baseURL := tcommon.GetBaseURL(port) dir := t.TempDir() conf := config.New() conf.HTTP.Port = port conf.Storage.RootDirectory = dir ctlr := api.NewController(conf) cm := tcommon.NewControllerManager(ctlr) // this blocks cm.StartAndWait(port) defer cm.StopServer() repoName := "signed-repo" tag := "1.0" image := CreateRandomImage() err := UploadImage(image, baseURL, repoName, tag) So(err, ShouldBeNil) tempDir := t.TempDir() notationDir := path.Join(tempDir, "notation") err = os.Mkdir(notationDir, 0o777) So(err, ShouldBeNil) filePath := path.Join(notationDir, "trustpolicy.json") err = os.WriteFile(filePath, []byte("some dummy file content"), 0o666) //nolint: gosec So(err, ShouldBeNil) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tempDir) err = signature.VerifyWithNotation(fmt.Sprintf("localhost:%s/%s:%s", port, repoName, tag), tempDir) So(err, ShouldNotBeNil) }) } func TestListNotarySignatures(t *testing.T) { Convey("error parsing reference", t, func() { cwd, err := os.Getwd() So(err, ShouldBeNil) defer func() { _ = os.Chdir(cwd) }() tdir := t.TempDir() _ = os.Chdir(tdir) _, err = signature.ListNotarySignatures("invalidReference", tdir) So(err, ShouldNotBeNil) }) Convey("error trying to get manifest", t, func() { cwd, err := os.Getwd() So(err, ShouldBeNil) defer func() { _ = os.Chdir(cwd) }() tdir := t.TempDir() _ = os.Chdir(tdir) _, err = signature.ListNotarySignatures("localhost:8080/invalidreference:1.0", tdir) So(err, ShouldNotBeNil) }) } func TestGenerateNotationCerts(t *testing.T) { Convey("write key file with permission", t, func() { tempDir := t.TempDir() notationDir := path.Join(tempDir, "notation") err := os.Mkdir(notationDir, 0o777) So(err, ShouldBeNil) filePath := path.Join(notationDir, "localkeys") err = os.WriteFile(filePath, []byte("{}"), 0o666) //nolint: gosec So(err, ShouldBeNil) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tempDir) err = signature.GenerateNotationCerts(t.TempDir(), "cert") So(err, ShouldNotBeNil) }) Convey("write cert file with permission", t, func() { tempDir := t.TempDir() notationDir := path.Join(tempDir, "notation", "localkeys") err := os.MkdirAll(notationDir, 0o777) So(err, ShouldBeNil) filePath := path.Join(notationDir, "cert.crt") err = os.WriteFile(filePath, []byte("{}"), 0o666) //nolint: gosec So(err, ShouldBeNil) err = os.Chmod(filePath, 0o000) So(err, ShouldBeNil) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tempDir) err = signature.GenerateNotationCerts(t.TempDir(), "cert") So(err, ShouldNotBeNil) err = os.Chmod(filePath, 0o755) So(err, ShouldBeNil) }) Convey("signingkeys.json file - not enough permission", t, func() { tempDir := t.TempDir() notationDir := path.Join(tempDir, "notation") err := os.Mkdir(notationDir, 0o777) So(err, ShouldBeNil) filePath := path.Join(notationDir, "signingkeys.json") _, err = os.Create(filePath) //nolint: gosec So(err, ShouldBeNil) err = os.Chmod(filePath, 0o000) So(err, ShouldBeNil) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tempDir) err = signature.GenerateNotationCerts(t.TempDir(), "cert") So(err, ShouldNotBeNil) err = os.Remove(filePath) So(err, ShouldBeNil) err = os.RemoveAll(path.Join(notationDir, "localkeys")) So(err, ShouldBeNil) signingKeysBuf, err := json.Marshal(notconfig.SigningKeys{}) So(err, ShouldBeNil) err = os.WriteFile(filePath, signingKeysBuf, 0o555) //nolint:gosec // test code So(err, ShouldBeNil) err = signature.GenerateNotationCerts(t.TempDir(), "cert") So(err, ShouldNotBeNil) }) Convey("keysuite already exists in signingkeys.json", t, func() { tempDir := t.TempDir() notationDir := path.Join(tempDir, "notation") err := os.Mkdir(notationDir, 0o777) So(err, ShouldBeNil) certName := "cert-test" filePath := path.Join(notationDir, "signingkeys.json") keyPath := path.Join(notationDir, "localkeys", certName+".key") certPath := path.Join(notationDir, "localkeys", certName+".crt") signingKeys := notconfig.SigningKeys{} keySuite := notconfig.KeySuite{ Name: certName, X509KeyPair: ¬config.X509KeyPair{ KeyPath: keyPath, CertificatePath: certPath, }, } signingKeys.Keys = []notconfig.KeySuite{keySuite} signingKeysBuf, err := json.Marshal(signingKeys) So(err, ShouldBeNil) err = os.WriteFile(filePath, signingKeysBuf, 0o600) So(err, ShouldBeNil) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tempDir) err = signature.GenerateNotationCerts(t.TempDir(), certName) So(err, ShouldNotBeNil) }) Convey("truststore files", t, func() { tempDir := t.TempDir() notationDir := path.Join(tempDir, "notation") err := os.Mkdir(notationDir, 0o777) So(err, ShouldBeNil) certName := "cert-test" trustStorePath := path.Join(notationDir, fmt.Sprintf("truststore/x509/ca/%s", certName)) err = os.MkdirAll(trustStorePath, 0o755) So(err, ShouldBeNil) err = os.Chmod(path.Join(notationDir, "truststore/x509"), 0o000) So(err, ShouldBeNil) signature.NotationPathLock.Lock() defer signature.NotationPathLock.Unlock() signature.LoadNotationPath(tempDir) err = signature.GenerateNotationCerts(tempDir, certName) So(err, ShouldNotBeNil) err = os.RemoveAll(path.Join(notationDir, "localkeys")) So(err, ShouldBeNil) err = os.Chmod(path.Join(notationDir, "truststore/x509"), 0o755) So(err, ShouldBeNil) _, err = os.Create(path.Join(trustStorePath, "cert-test.crt")) So(err, ShouldBeNil) err = signature.GenerateNotationCerts(tempDir, certName) So(err, ShouldNotBeNil) err = os.RemoveAll(path.Join(notationDir, "localkeys")) So(err, ShouldBeNil) err = os.Remove(path.Join(trustStorePath, "cert-test.crt")) So(err, ShouldBeNil) err = os.Chmod(path.Join(notationDir, "truststore/x509/ca", certName), 0o555) So(err, ShouldBeNil) err = signature.GenerateNotationCerts(tempDir, certName) So(err, ShouldNotBeNil) }) }