zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/test/signature/notation_test.go (about) 1 //go:build sync && scrub && metrics && search 2 // +build sync,scrub,metrics,search 3 4 package signature_test 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "os" 10 "path" 11 "testing" 12 13 notconfig "github.com/notaryproject/notation-go/config" 14 . "github.com/smartystreets/goconvey/convey" 15 16 "zotregistry.io/zot/pkg/api" 17 "zotregistry.io/zot/pkg/api/config" 18 tcommon "zotregistry.io/zot/pkg/test/common" 19 . "zotregistry.io/zot/pkg/test/image-utils" 20 signature "zotregistry.io/zot/pkg/test/signature" 21 ) 22 23 func TestLoadNotationSigningkeys(t *testing.T) { 24 Convey("notation directory doesn't exist", t, func() { 25 _, err := signature.LoadNotationSigningkeys(t.TempDir()) 26 So(err, ShouldNotBeNil) 27 }) 28 29 Convey("wrong content of signingkeys.json", t, func() { 30 tempDir := t.TempDir() 31 dir := path.Join(tempDir, "notation") 32 err := os.Mkdir(dir, 0o777) 33 So(err, ShouldBeNil) 34 35 filePath := path.Join(dir, "signingkeys.json") 36 err = os.WriteFile(filePath, []byte("some dummy file content"), 0o666) //nolint: gosec 37 So(err, ShouldBeNil) 38 39 _, err = signature.LoadNotationSigningkeys(tempDir) 40 So(err, ShouldNotBeNil) 41 }) 42 43 Convey("not enough permissions to access signingkeys.json", t, func() { 44 tempDir := t.TempDir() 45 dir := path.Join(tempDir, "notation") 46 err := os.Mkdir(dir, 0o777) 47 So(err, ShouldBeNil) 48 49 filePath := path.Join(dir, "signingkeys.json") 50 err = os.WriteFile(filePath, []byte("some dummy file content"), 0o300) //nolint: gosec 51 So(err, ShouldBeNil) 52 53 _, err = signature.LoadNotationSigningkeys(tempDir) 54 So(err, ShouldNotBeNil) 55 }) 56 57 Convey("signingkeys.json not exists so it is created successfully", t, func() { 58 tempDir := t.TempDir() 59 dir := path.Join(tempDir, "notation") 60 err := os.Mkdir(dir, 0o777) 61 So(err, ShouldBeNil) 62 63 _, err = signature.LoadNotationSigningkeys(tempDir) 64 So(err, ShouldBeNil) 65 }) 66 67 Convey("signingkeys.json not exists - error trying to create it", t, func() { 68 tempDir := t.TempDir() 69 dir := path.Join(tempDir, "notation") 70 // create notation directory without write permissions 71 err := os.Mkdir(dir, 0o555) 72 So(err, ShouldBeNil) 73 74 _, err = signature.LoadNotationSigningkeys(tempDir) 75 So(err, ShouldNotBeNil) 76 }) 77 } 78 79 func TestLoadNotationConfig(t *testing.T) { 80 Convey("directory doesn't exist", t, func() { 81 _, err := signature.LoadNotationConfig(t.TempDir()) 82 So(err, ShouldNotBeNil) 83 }) 84 85 Convey("wrong content of signingkeys.json", t, func() { 86 tempDir := t.TempDir() 87 dir := path.Join(tempDir, "notation") 88 err := os.Mkdir(dir, 0o777) 89 So(err, ShouldBeNil) 90 91 filePath := path.Join(dir, "signingkeys.json") 92 err = os.WriteFile(filePath, []byte("some dummy file content"), 0o666) //nolint: gosec 93 So(err, ShouldBeNil) 94 95 _, err = signature.LoadNotationConfig(tempDir) 96 So(err, ShouldNotBeNil) 97 }) 98 99 Convey("check default value of signature format", t, func() { 100 tempDir := t.TempDir() 101 dir := path.Join(tempDir, "notation") 102 err := os.Mkdir(dir, 0o777) 103 So(err, ShouldBeNil) 104 105 filePath := path.Join(dir, "signingkeys.json") 106 err = os.WriteFile(filePath, []byte("{\"SignatureFormat\": \"\"}"), 0o666) //nolint: gosec 107 So(err, ShouldBeNil) 108 109 configInfo, err := signature.LoadNotationConfig(tempDir) 110 So(err, ShouldBeNil) 111 So(configInfo.SignatureFormat, ShouldEqual, "jws") 112 }) 113 } 114 115 func TestSignWithNotation(t *testing.T) { 116 Convey("notation directory doesn't exist", t, func() { 117 err := signature.SignWithNotation("key", "reference", t.TempDir(), true) 118 So(err, ShouldNotBeNil) 119 }) 120 121 Convey("key not found", t, func() { 122 tempDir := t.TempDir() 123 dir := path.Join(tempDir, "notation") 124 err := os.Mkdir(dir, 0o777) 125 So(err, ShouldBeNil) 126 127 filePath := path.Join(dir, "signingkeys.json") 128 err = os.WriteFile(filePath, []byte("{}"), 0o666) //nolint: gosec 129 So(err, ShouldBeNil) 130 131 err = signature.SignWithNotation("key", "reference", tempDir, true) 132 So(err, ShouldEqual, signature.ErrKeyNotFound) 133 }) 134 135 Convey("not enough permissions to access notation/localkeys dir", t, func() { 136 cwd, err := os.Getwd() 137 So(err, ShouldBeNil) 138 defer func() { _ = os.Chdir(cwd) }() 139 tdir := t.TempDir() 140 _ = os.Chdir(tdir) 141 142 signature.NotationPathLock.Lock() 143 defer signature.NotationPathLock.Unlock() 144 145 signature.LoadNotationPath(tdir) 146 147 err = signature.GenerateNotationCerts(tdir, "key") 148 So(err, ShouldBeNil) 149 150 err = os.Chmod(path.Join(tdir, "notation", "localkeys"), 0o000) 151 So(err, ShouldBeNil) 152 153 err = signature.SignWithNotation("key", "reference", tdir, true) 154 So(err, ShouldNotBeNil) 155 156 err = os.Chmod(path.Join(tdir, "notation", "localkeys"), 0o755) 157 So(err, ShouldBeNil) 158 }) 159 160 Convey("error parsing reference", t, func() { 161 cwd, err := os.Getwd() 162 So(err, ShouldBeNil) 163 defer func() { _ = os.Chdir(cwd) }() 164 tdir := t.TempDir() 165 _ = os.Chdir(tdir) 166 167 signature.NotationPathLock.Lock() 168 defer signature.NotationPathLock.Unlock() 169 170 signature.LoadNotationPath(tdir) 171 172 err = signature.GenerateNotationCerts(tdir, "key") 173 So(err, ShouldBeNil) 174 175 err = signature.SignWithNotation("key", "invalidReference", tdir, true) 176 So(err, ShouldNotBeNil) 177 }) 178 179 Convey("error signing", t, func() { 180 cwd, err := os.Getwd() 181 So(err, ShouldBeNil) 182 defer func() { _ = os.Chdir(cwd) }() 183 tdir := t.TempDir() 184 _ = os.Chdir(tdir) 185 186 signature.NotationPathLock.Lock() 187 defer signature.NotationPathLock.Unlock() 188 189 signature.LoadNotationPath(tdir) 190 191 err = signature.GenerateNotationCerts(tdir, "key") 192 So(err, ShouldBeNil) 193 194 err = signature.SignWithNotation("key", "localhost:8080/invalidreference:1.0", tdir, true) 195 So(err, ShouldNotBeNil) 196 }) 197 } 198 199 func TestVerifyWithNotation(t *testing.T) { 200 Convey("notation directory doesn't exist", t, func() { 201 err := signature.VerifyWithNotation("reference", t.TempDir()) 202 So(err, ShouldNotBeNil) 203 }) 204 205 Convey("error parsing reference", t, func() { 206 cwd, err := os.Getwd() 207 So(err, ShouldBeNil) 208 defer func() { _ = os.Chdir(cwd) }() 209 tdir := t.TempDir() 210 _ = os.Chdir(tdir) 211 212 signature.NotationPathLock.Lock() 213 defer signature.NotationPathLock.Unlock() 214 215 signature.LoadNotationPath(tdir) 216 217 err = signature.GenerateNotationCerts(tdir, "key") 218 So(err, ShouldBeNil) 219 220 err = signature.VerifyWithNotation("invalidReference", tdir) 221 So(err, ShouldNotBeNil) 222 }) 223 224 Convey("error trying to get manifest", t, func() { 225 cwd, err := os.Getwd() 226 So(err, ShouldBeNil) 227 defer func() { _ = os.Chdir(cwd) }() 228 tdir := t.TempDir() 229 _ = os.Chdir(tdir) 230 231 signature.NotationPathLock.Lock() 232 defer signature.NotationPathLock.Unlock() 233 234 signature.LoadNotationPath(tdir) 235 236 err = signature.GenerateNotationCerts(tdir, "key") 237 So(err, ShouldBeNil) 238 239 err = signature.VerifyWithNotation("localhost:8080/invalidreference:1.0", tdir) 240 So(err, ShouldNotBeNil) 241 }) 242 243 Convey("invalid content of trustpolicy.json", t, func() { 244 // start a new server 245 port := tcommon.GetFreePort() 246 baseURL := tcommon.GetBaseURL(port) 247 dir := t.TempDir() 248 249 conf := config.New() 250 conf.HTTP.Port = port 251 conf.Storage.RootDirectory = dir 252 253 ctlr := api.NewController(conf) 254 cm := tcommon.NewControllerManager(ctlr) 255 // this blocks 256 cm.StartAndWait(port) 257 defer cm.StopServer() 258 259 repoName := "signed-repo" 260 tag := "1.0" 261 262 image := CreateRandomImage() 263 264 err := UploadImage(image, baseURL, repoName, tag) 265 So(err, ShouldBeNil) 266 267 tempDir := t.TempDir() 268 notationDir := path.Join(tempDir, "notation") 269 err = os.Mkdir(notationDir, 0o777) 270 So(err, ShouldBeNil) 271 272 filePath := path.Join(notationDir, "trustpolicy.json") 273 err = os.WriteFile(filePath, []byte("some dummy file content"), 0o666) //nolint: gosec 274 So(err, ShouldBeNil) 275 276 signature.NotationPathLock.Lock() 277 defer signature.NotationPathLock.Unlock() 278 279 signature.LoadNotationPath(tempDir) 280 281 err = signature.VerifyWithNotation(fmt.Sprintf("localhost:%s/%s:%s", port, repoName, tag), tempDir) 282 So(err, ShouldNotBeNil) 283 }) 284 } 285 286 func TestListNotarySignatures(t *testing.T) { 287 Convey("error parsing reference", t, func() { 288 cwd, err := os.Getwd() 289 So(err, ShouldBeNil) 290 defer func() { _ = os.Chdir(cwd) }() 291 tdir := t.TempDir() 292 _ = os.Chdir(tdir) 293 294 _, err = signature.ListNotarySignatures("invalidReference", tdir) 295 So(err, ShouldNotBeNil) 296 }) 297 298 Convey("error trying to get manifest", t, func() { 299 cwd, err := os.Getwd() 300 So(err, ShouldBeNil) 301 defer func() { _ = os.Chdir(cwd) }() 302 tdir := t.TempDir() 303 _ = os.Chdir(tdir) 304 305 _, err = signature.ListNotarySignatures("localhost:8080/invalidreference:1.0", tdir) 306 So(err, ShouldNotBeNil) 307 }) 308 } 309 310 func TestGenerateNotationCerts(t *testing.T) { 311 Convey("write key file with permission", t, func() { 312 tempDir := t.TempDir() 313 314 notationDir := path.Join(tempDir, "notation") 315 err := os.Mkdir(notationDir, 0o777) 316 So(err, ShouldBeNil) 317 318 filePath := path.Join(notationDir, "localkeys") 319 err = os.WriteFile(filePath, []byte("{}"), 0o666) //nolint: gosec 320 So(err, ShouldBeNil) 321 322 signature.NotationPathLock.Lock() 323 defer signature.NotationPathLock.Unlock() 324 325 signature.LoadNotationPath(tempDir) 326 327 err = signature.GenerateNotationCerts(t.TempDir(), "cert") 328 So(err, ShouldNotBeNil) 329 }) 330 331 Convey("write cert file with permission", t, func() { 332 tempDir := t.TempDir() 333 334 notationDir := path.Join(tempDir, "notation", "localkeys") 335 err := os.MkdirAll(notationDir, 0o777) 336 So(err, ShouldBeNil) 337 338 filePath := path.Join(notationDir, "cert.crt") 339 err = os.WriteFile(filePath, []byte("{}"), 0o666) //nolint: gosec 340 So(err, ShouldBeNil) 341 342 err = os.Chmod(filePath, 0o000) 343 So(err, ShouldBeNil) 344 345 signature.NotationPathLock.Lock() 346 defer signature.NotationPathLock.Unlock() 347 348 signature.LoadNotationPath(tempDir) 349 350 err = signature.GenerateNotationCerts(t.TempDir(), "cert") 351 So(err, ShouldNotBeNil) 352 353 err = os.Chmod(filePath, 0o755) 354 So(err, ShouldBeNil) 355 }) 356 357 Convey("signingkeys.json file - not enough permission", t, func() { 358 tempDir := t.TempDir() 359 360 notationDir := path.Join(tempDir, "notation") 361 err := os.Mkdir(notationDir, 0o777) 362 So(err, ShouldBeNil) 363 364 filePath := path.Join(notationDir, "signingkeys.json") 365 _, err = os.Create(filePath) //nolint: gosec 366 So(err, ShouldBeNil) 367 err = os.Chmod(filePath, 0o000) 368 So(err, ShouldBeNil) 369 370 signature.NotationPathLock.Lock() 371 defer signature.NotationPathLock.Unlock() 372 373 signature.LoadNotationPath(tempDir) 374 375 err = signature.GenerateNotationCerts(t.TempDir(), "cert") 376 So(err, ShouldNotBeNil) 377 378 err = os.Remove(filePath) 379 So(err, ShouldBeNil) 380 err = os.RemoveAll(path.Join(notationDir, "localkeys")) 381 So(err, ShouldBeNil) 382 signingKeysBuf, err := json.Marshal(notconfig.SigningKeys{}) 383 So(err, ShouldBeNil) 384 err = os.WriteFile(filePath, signingKeysBuf, 0o555) //nolint:gosec // test code 385 So(err, ShouldBeNil) 386 err = signature.GenerateNotationCerts(t.TempDir(), "cert") 387 So(err, ShouldNotBeNil) 388 }) 389 Convey("keysuite already exists in signingkeys.json", t, func() { 390 tempDir := t.TempDir() 391 392 notationDir := path.Join(tempDir, "notation") 393 err := os.Mkdir(notationDir, 0o777) 394 So(err, ShouldBeNil) 395 396 certName := "cert-test" 397 filePath := path.Join(notationDir, "signingkeys.json") 398 keyPath := path.Join(notationDir, "localkeys", certName+".key") 399 certPath := path.Join(notationDir, "localkeys", certName+".crt") 400 signingKeys := notconfig.SigningKeys{} 401 keySuite := notconfig.KeySuite{ 402 Name: certName, 403 X509KeyPair: ¬config.X509KeyPair{ 404 KeyPath: keyPath, 405 CertificatePath: certPath, 406 }, 407 } 408 signingKeys.Keys = []notconfig.KeySuite{keySuite} 409 signingKeysBuf, err := json.Marshal(signingKeys) 410 So(err, ShouldBeNil) 411 err = os.WriteFile(filePath, signingKeysBuf, 0o600) 412 So(err, ShouldBeNil) 413 414 signature.NotationPathLock.Lock() 415 defer signature.NotationPathLock.Unlock() 416 417 signature.LoadNotationPath(tempDir) 418 419 err = signature.GenerateNotationCerts(t.TempDir(), certName) 420 So(err, ShouldNotBeNil) 421 }) 422 Convey("truststore files", t, func() { 423 tempDir := t.TempDir() 424 425 notationDir := path.Join(tempDir, "notation") 426 err := os.Mkdir(notationDir, 0o777) 427 So(err, ShouldBeNil) 428 429 certName := "cert-test" 430 trustStorePath := path.Join(notationDir, fmt.Sprintf("truststore/x509/ca/%s", certName)) 431 err = os.MkdirAll(trustStorePath, 0o755) 432 So(err, ShouldBeNil) 433 err = os.Chmod(path.Join(notationDir, "truststore/x509"), 0o000) 434 So(err, ShouldBeNil) 435 436 signature.NotationPathLock.Lock() 437 defer signature.NotationPathLock.Unlock() 438 439 signature.LoadNotationPath(tempDir) 440 441 err = signature.GenerateNotationCerts(tempDir, certName) 442 So(err, ShouldNotBeNil) 443 444 err = os.RemoveAll(path.Join(notationDir, "localkeys")) 445 So(err, ShouldBeNil) 446 err = os.Chmod(path.Join(notationDir, "truststore/x509"), 0o755) 447 So(err, ShouldBeNil) 448 _, err = os.Create(path.Join(trustStorePath, "cert-test.crt")) 449 So(err, ShouldBeNil) 450 451 err = signature.GenerateNotationCerts(tempDir, certName) 452 So(err, ShouldNotBeNil) 453 454 err = os.RemoveAll(path.Join(notationDir, "localkeys")) 455 So(err, ShouldBeNil) 456 err = os.Remove(path.Join(trustStorePath, "cert-test.crt")) 457 So(err, ShouldBeNil) 458 err = os.Chmod(path.Join(notationDir, "truststore/x509/ca", certName), 0o555) 459 So(err, ShouldBeNil) 460 461 err = signature.GenerateNotationCerts(tempDir, certName) 462 So(err, ShouldNotBeNil) 463 }) 464 }