// Non-roles and delegation keys can't be rotated with the command line func TestRotateKeyInvalidRoles(t *testing.T) { setUp(t) invalids := []string{ "notevenARole", "targets/a", } for _, role := range invalids { for _, serverManaged := range []bool{true, false} { k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() notary.PassRetriever { return passphrase.ConstantRetriever("pass") }, rotateKeyRole: role, rotateKeyServerManaged: serverManaged, } commands := []string{"gun", role} if serverManaged { commands = append(commands, "-r") } err := k.keysRotate(&cobra.Command{}, commands) require.Error(t, err) require.Contains(t, err.Error(), fmt.Sprintf("does not currently permit rotating the %s key", role)) } } }
// Zips up the keys in the old repo, and assert that we can import it and use // said keys. The 0.1 exported format is just a zip file of all the keys func TestImport0Dot1Zip(t *testing.T) { ks, ret, _ := get0Dot1(t) zipFile, err := ioutil.TempFile("", "notary-test-zipFile") defer os.RemoveAll(zipFile.Name()) zipWriter := zip.NewWriter(zipFile) require.NoError(t, err) require.NoError(t, addKeysToArchive(zipWriter, ks)) zipWriter.Close() zipFile.Close() origKeys := make(map[string]string) for keyID, keyInfo := range ks.ListKeys() { origKeys[keyID] = keyInfo.Role } require.Len(t, origKeys, 3) // now import the zip file into a new cryptoservice tempDir, err := ioutil.TempDir("", "notary-test-import") defer os.RemoveAll(tempDir) require.NoError(t, err) ks, err = trustmanager.NewKeyFileStore(tempDir, ret) require.NoError(t, err) cs := NewCryptoService(ks) zipReader, err := zip.OpenReader(zipFile.Name()) require.NoError(t, err) defer zipReader.Close() require.NoError(t, cs.ImportKeysZip(zipReader.Reader, passphrase.ConstantRetriever("randompass"))) assertHasKeys(t, cs, origKeys) }
// Export all the keys of a cryptoservice to a zipfile, and import it into a // new cryptoService, and return that new cryptoService func importExportedZip(t *testing.T, original *CryptoService, ret notary.PassRetriever, gun string) (*CryptoService, string) { // Temporary directory where test files will be created tempBaseDir, err := ioutil.TempDir("", "notary-test-") require.NoError(t, err, "failed to create a temporary directory: %s", err) ks, err := trustmanager.NewKeyFileStore(tempBaseDir, ret) require.NoError(t, err) var cs *CryptoService // export keys zipFile, err := ioutil.TempFile("", "notary-test-zipFile") defer os.RemoveAll(zipFile.Name()) if gun != "" { err = original.ExportKeysByGUN(zipFile, gun, ret) require.NoError(t, err) cs = NewCryptoService(ks) } else { err = original.ExportAllKeys(zipFile, ret) require.NoError(t, err) cs = NewCryptoService(ks) } zipFile.Close() // import keys into the cryptoservice now zipReader, err := zip.OpenReader(zipFile.Name()) require.NoError(t, err) defer zipReader.Close() require.NoError(t, cs.ImportKeysZip(zipReader.Reader, passphrase.ConstantRetriever("randompass"))) return cs, tempBaseDir }
// The command line uses NotaryRepository's RotateKey - this is just testing // that the correct config variables are passed for the client to request a key // from the remote server. func TestRotateKeyRemoteServerManagesKey(t *testing.T) { // Temporary directory where test files will be created tempBaseDir, err := ioutil.TempDir("/tmp", "notary-test-") defer os.RemoveAll(tempBaseDir) assert.NoError(t, err, "failed to create a temporary directory: %s", err) gun := "docker.com/notary" ret := passphrase.ConstantRetriever("pass") ts, initialKeys := setUpRepo(t, tempBaseDir, gun, ret) defer ts.Close() k := &keyCommander{ configGetter: func() (*viper.Viper, error) { v := viper.New() v.SetDefault("trust_dir", tempBaseDir) v.SetDefault("remote_server.url", ts.URL) return v, nil }, getRetriever: func() passphrase.Retriever { return ret }, rotateKeyRole: data.CanonicalSnapshotRole, rotateKeyServerManaged: true, } err = k.keysRotate(&cobra.Command{}, []string{gun}) assert.NoError(t, err) repo, err := client.NewNotaryRepository(tempBaseDir, gun, ts.URL, nil, ret) assert.NoError(t, err, "error creating repo: %s", err) cl, err := repo.GetChangelist() assert.NoError(t, err, "unable to get changelist: %v", err) assert.Len(t, cl.List(), 1) // no keys have been created, since a remote key was specified assert.Equal(t, initialKeys, repo.CryptoService.ListAllKeys()) }
// Given a list of key stores, the keys should be pretty-printed with their // roles, locations, IDs, and guns first in sorted order in the key store func TestPrettyPrintRootAndSigningKeys(t *testing.T) { ret := passphrase.ConstantRetriever("pass") keyStores := []trustmanager.KeyStore{ trustmanager.NewKeyMemoryStore(ret), &otherMemoryStore{KeyMemoryStore: *trustmanager.NewKeyMemoryStore(ret)}, } longNameShortened := "..." + strings.Repeat("z", 37) keys := make([]data.PrivateKey, 4) for i := 0; i < 4; i++ { key, err := trustmanager.GenerateED25519Key(rand.Reader) require.NoError(t, err) keys[i] = key } root := data.CanonicalRootRole // add keys to the key stores require.NoError(t, keyStores[0].AddKey(trustmanager.KeyInfo{Role: root, Gun: ""}, keys[0])) require.NoError(t, keyStores[1].AddKey(trustmanager.KeyInfo{Role: root, Gun: ""}, keys[0])) require.NoError(t, keyStores[0].AddKey(trustmanager.KeyInfo{Role: data.CanonicalTargetsRole, Gun: strings.Repeat("/a", 30)}, keys[1])) require.NoError(t, keyStores[1].AddKey(trustmanager.KeyInfo{Role: data.CanonicalSnapshotRole, Gun: "short/gun"}, keys[1])) require.NoError(t, keyStores[0].AddKey(trustmanager.KeyInfo{Role: "targets/a", Gun: ""}, keys[3])) require.NoError(t, keyStores[0].AddKey(trustmanager.KeyInfo{Role: "invalidRole", Gun: ""}, keys[2])) expected := [][]string{ // root always comes first {root, keys[0].ID(), keyStores[0].Name()}, {root, keys[0].ID(), longNameShortened}, // these have no gun, so they come first {"invalidRole", keys[2].ID(), keyStores[0].Name()}, {"targets/a", keys[3].ID(), keyStores[0].Name()}, // these have guns, and are sorted then by guns {data.CanonicalTargetsRole, "..." + strings.Repeat("/a", 11), keys[1].ID(), keyStores[0].Name()}, {data.CanonicalSnapshotRole, "short/gun", keys[1].ID(), longNameShortened}, } var b bytes.Buffer prettyPrintKeys(keyStores, &b) text, err := ioutil.ReadAll(&b) require.NoError(t, err) lines := strings.Split(strings.TrimSpace(string(text)), "\n") require.Len(t, lines, len(expected)+2) // starts with headers require.True(t, reflect.DeepEqual(strings.Fields(lines[0]), []string{"ROLE", "GUN", "KEY", "ID", "LOCATION"})) require.Equal(t, "----", lines[1][:4]) for i, line := range lines[2:] { // we are purposely not putting spaces in test data so easier to split splitted := strings.Fields(line) for j, v := range splitted { require.Equal(t, expected[i][j], strings.TrimSpace(v)) } } }
func init() { NewNotaryCommand = func() *cobra.Command { commander := ¬aryCommander{ getRetriever: func() passphrase.Retriever { return passphrase.ConstantRetriever("pass") }, } return commander.GetCommand() } }
// We can read and publish from notary0.1 repos func Test0Dot1RepoFormat(t *testing.T) { // make a temporary directory and copy the fixture into it, since updating // and publishing will modify the files tmpDir, err := ioutil.TempDir("", "notary-backwards-compat-test") defer os.RemoveAll(tmpDir) require.NoError(t, err) require.NoError(t, recursiveCopy("../fixtures/compatibility/notary0.1", tmpDir)) gun := "docker.com/notary0.1/samplerepo" passwd := "randompass" ts := fullTestServer(t) defer ts.Close() repo, err := NewFileCachedNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) // targets should have 1 target, and it should be readable offline targets, err := repo.ListTargets() require.NoError(t, err) require.Len(t, targets, 1) require.Equal(t, "LICENSE", targets[0].Name) // ok, now that everything has been loaded, verify that the fixture is valid requireValidFixture(t, repo) // delete the timestamp metadata, since the server will ignore the uploaded // one and try to create a new one from scratch, which will be the wrong version require.NoError(t, repo.cache.Remove(data.CanonicalTimestampRole)) // rotate the timestamp key, since the server doesn't have that one err = repo.RotateKey(data.CanonicalTimestampRole, true) require.NoError(t, err) require.NoError(t, repo.Publish()) targets, err = repo.ListTargets() require.NoError(t, err) require.Len(t, targets, 2) // Also check that we can add/remove keys by rotating keys oldTargetsKeys := repo.CryptoService.ListKeys(data.CanonicalTargetsRole) require.NoError(t, repo.RotateKey(data.CanonicalTargetsRole, false)) require.NoError(t, repo.Publish()) newTargetsKeys := repo.CryptoService.ListKeys(data.CanonicalTargetsRole) require.Len(t, oldTargetsKeys, 1) require.Len(t, newTargetsKeys, 1) require.NotEqual(t, oldTargetsKeys[0], newTargetsKeys[0]) // rotate the snapshot key to the server and ensure that the server can re-generate the snapshot // and we can download the snapshot require.NoError(t, repo.RotateKey(data.CanonicalSnapshotRole, true)) require.NoError(t, repo.Publish()) err = repo.Update(false) require.NoError(t, err) }
// The command line uses NotaryRepository's RotateKey - this is just testing // that multiple keys can be rotated at once locally func TestRotateKeyBothKeys(t *testing.T) { setUp(t) // Temporary directory where test files will be created tempBaseDir, err := ioutil.TempDir("/tmp", "notary-test-") defer os.RemoveAll(tempBaseDir) require.NoError(t, err, "failed to create a temporary directory: %s", err) gun := "docker.com/notary" ret := passphrase.ConstantRetriever("pass") ts, initialKeys := setUpRepo(t, tempBaseDir, gun, ret) defer ts.Close() k := &keyCommander{ configGetter: func() (*viper.Viper, error) { v := viper.New() v.SetDefault("trust_dir", tempBaseDir) v.SetDefault("remote_server.url", ts.URL) return v, nil }, getRetriever: func() notary.PassRetriever { return ret }, } require.NoError(t, k.keysRotate(&cobra.Command{}, []string{gun, data.CanonicalTargetsRole})) require.NoError(t, k.keysRotate(&cobra.Command{}, []string{gun, data.CanonicalSnapshotRole})) repo, err := client.NewNotaryRepository(tempBaseDir, gun, ts.URL, nil, ret, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) cl, err := repo.GetChangelist() require.NoError(t, err, "unable to get changelist: %v", err) require.Len(t, cl.List(), 0) // two new keys have been created, and the old keys should still be gone newKeys := repo.CryptoService.ListAllKeys() // there should be 3 keys - snapshot, targets, and root require.Len(t, newKeys, 3) // the old snapshot/targets keys should be gone for keyID, role := range initialKeys { r, ok := newKeys[keyID] switch r { case data.CanonicalSnapshotRole, data.CanonicalTargetsRole: require.False(t, ok, "original key %s still there", keyID) case data.CanonicalRootRole: require.Equal(t, role, r) require.True(t, ok, "old root key has changed") } } found := make(map[string]bool) for _, role := range newKeys { found[role] = true } require.True(t, found[data.CanonicalTargetsRole], "targets key was not created") require.True(t, found[data.CanonicalSnapshotRole], "snapshot key was not created") require.True(t, found[data.CanonicalRootRole], "root key was removed somehow") }
func TestSignRootOldKeyCertMissing(t *testing.T) { gun := "docker/test-sign-root" referenceTime := time.Now() cs := cryptoservice.NewCryptoService(trustmanager.NewKeyMemoryStore( passphrase.ConstantRetriever("password"))) rootPublicKey, err := cs.Create(data.CanonicalRootRole, gun, data.ECDSAKey) require.NoError(t, err) rootPrivateKey, _, err := cs.GetPrivateKey(rootPublicKey.ID()) require.NoError(t, err) oldRootCert, err := cryptoservice.GenerateCertificate(rootPrivateKey, gun, referenceTime.AddDate(-9, 0, 0), referenceTime.AddDate(1, 0, 0)) require.NoError(t, err) oldRootCertKey := trustmanager.CertToKey(oldRootCert) repo := initRepoWithRoot(t, cs, oldRootCertKey) // Create a first signature, using the old key. signedRoot, err := repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole)) require.NoError(t, err) verifySignatureList(t, signedRoot, oldRootCertKey) err = verifyRootSignatureAgainstKey(t, signedRoot, oldRootCertKey) require.NoError(t, err) // Create a new certificate newRootCert, err := cryptoservice.GenerateCertificate(rootPrivateKey, gun, referenceTime, referenceTime.AddDate(10, 0, 0)) require.NoError(t, err) newRootCertKey := trustmanager.CertToKey(newRootCert) require.NotEqual(t, oldRootCertKey.ID(), newRootCertKey.ID()) // Only trust the new certificate err = repo.ReplaceBaseKeys(data.CanonicalRootRole, newRootCertKey) require.NoError(t, err) updatedRootRole, err := repo.GetBaseRole(data.CanonicalRootRole) require.NoError(t, err) updatedRootKeyIDs := updatedRootRole.ListKeyIDs() require.Equal(t, 1, len(updatedRootKeyIDs)) require.Equal(t, newRootCertKey.ID(), updatedRootKeyIDs[0]) // Now forget all about the old certificate: drop it from the Root carried keys delete(repo.Root.Signed.Keys, oldRootCertKey.ID()) repo2 := NewRepo(cs) repo2.Root = repo.Root repo2.originalRootRole = updatedRootRole // Create a second signature signedRoot, err = repo2.SignRoot(data.DefaultExpires(data.CanonicalRootRole)) require.NoError(t, err) verifySignatureList(t, signedRoot, newRootCertKey) // Without oldRootCertKey // Verify that the signature can be verified when trusting the new certificate err = verifyRootSignatureAgainstKey(t, signedRoot, newRootCertKey) require.NoError(t, err) err = verifyRootSignatureAgainstKey(t, signedRoot, oldRootCertKey) require.Error(t, err) }
func TestChangeKeyPassphraseInvalidID(t *testing.T) { k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() passphrase.Retriever { return passphrase.ConstantRetriever("pass") }, } err := k.keyPassphraseChange(&cobra.Command{}, []string{"too_short"}) assert.Error(t, err) assert.Contains(t, err.Error(), "invalid key ID provided") }
func TestChangeKeyPassphraseInvalidNumArgs(t *testing.T) { k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() passphrase.Retriever { return passphrase.ConstantRetriever("pass") }, } err := k.keyPassphraseChange(&cobra.Command{}, []string{}) assert.Error(t, err) assert.Contains(t, err.Error(), "must specify the key ID") }
// Given a list of key stores, the keys should be pretty-printed with their // roles, locations, IDs, and guns first in sorted order in the key store func TestPrettyPrintRootAndSigningKeys(t *testing.T) { ret := passphrase.ConstantRetriever("pass") keyStores := []trustmanager.KeyStore{ trustmanager.NewKeyMemoryStore(ret), &otherMemoryStore{KeyMemoryStore: *trustmanager.NewKeyMemoryStore(ret)}, } longNameShortened := "..." + strings.Repeat("z", 37) // just use the same key for testing key, err := trustmanager.GenerateED25519Key(rand.Reader) assert.NoError(t, err) root := data.CanonicalRootRole // add keys to the key stores err = keyStores[0].AddKey(key.ID(), root, key) assert.NoError(t, err) err = keyStores[1].AddKey(key.ID(), root, key) assert.NoError(t, err) err = keyStores[0].AddKey(strings.Repeat("a/", 30)+key.ID(), "targets", key) assert.NoError(t, err) err = keyStores[1].AddKey("short/gun/"+key.ID(), "snapshot", key) assert.NoError(t, err) expected := [][]string{ {root, key.ID(), keyStores[0].Name()}, {root, key.ID(), longNameShortened}, {"targets", "..." + strings.Repeat("/a", 11), key.ID(), keyStores[0].Name()}, {"snapshot", "short/gun", key.ID(), longNameShortened}, } var b bytes.Buffer prettyPrintKeys(keyStores, &b) text, err := ioutil.ReadAll(&b) assert.NoError(t, err) lines := strings.Split(strings.TrimSpace(string(text)), "\n") assert.Len(t, lines, len(expected)+2) // starts with headers assert.True(t, reflect.DeepEqual(strings.Fields(lines[0]), []string{"ROLE", "GUN", "KEY", "ID", "LOCATION"})) assert.Equal(t, "----", lines[1][:4]) for i, line := range lines[2:] { // we are purposely not putting spaces in test data so easier to split splitted := strings.Fields(line) for j, v := range splitted { assert.Equal(t, expected[i][j], strings.TrimSpace(v)) } } }
func get0Dot1(t *testing.T) (*trustmanager.KeyFileStore, passphrase.Retriever, string) { gun := "docker.io/notary0.1/samplerepo" ret := passphrase.ConstantRetriever("randompass") // produce the zip file ks, err := trustmanager.NewKeyFileStore("../fixtures/compatibility/notary0.1", ret) assert.NoError(t, err) return ks, ret, gun }
func TestChangeKeyPassphraseNonexistentID(t *testing.T) { k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() passphrase.Retriever { return passphrase.ConstantRetriever("pass") }, } // Valid ID size, but does not exist as a key ID err := k.keyPassphraseChange(&cobra.Command{}, []string{strings.Repeat("x", notary.Sha256HexSize)}) assert.Error(t, err) assert.Contains(t, err.Error(), "could not retrieve local key for key ID provided") }
func newBlankRepo(t *testing.T, url string) *NotaryRepository { // Temporary directory where test files will be created tempBaseDir, err := ioutil.TempDir("", "notary-test-") require.NoError(t, err, "failed to create a temporary directory: %s", err) repo, err := NewNotaryRepository(tempBaseDir, "docker.com/notary", url, http.DefaultTransport, passphrase.ConstantRetriever("pass")) require.NoError(t, err) return repo }
// rotate key must be provided with a gun func TestRotateKeyNoGUN(t *testing.T) { k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() passphrase.Retriever { return passphrase.ConstantRetriever("pass") }, rotateKeyRole: data.CanonicalTargetsRole, } err := k.keysRotate(&cobra.Command{}, []string{}) assert.Error(t, err) assert.Contains(t, err.Error(), "Must specify a GUN") }
// The command line uses NotaryRepository's RotateKey - this is just testing // that the correct config variables are passed for the client to rotate // both the targets and snapshot key, and create them locally func TestRotateKeyBothKeys(t *testing.T) { // Temporary directory where test files will be created tempBaseDir, err := ioutil.TempDir("/tmp", "notary-test-") defer os.RemoveAll(tempBaseDir) assert.NoError(t, err, "failed to create a temporary directory: %s", err) gun := "docker.com/notary" ret := passphrase.ConstantRetriever("pass") ts, initialKeys := setUpRepo(t, tempBaseDir, gun, ret) // we won't need this anymore since we are creating keys locally ts.Close() k := &keyCommander{ configGetter: func() (*viper.Viper, error) { v := viper.New() v.SetDefault("trust_dir", tempBaseDir) // won't need a remote server URL, since we are creating local keys return v, nil }, getRetriever: func() passphrase.Retriever { return ret }, } err = k.keysRotate(&cobra.Command{}, []string{gun}) assert.NoError(t, err) repo, err := client.NewNotaryRepository(tempBaseDir, gun, ts.URL, nil, ret) assert.NoError(t, err, "error creating repo: %s", err) cl, err := repo.GetChangelist() assert.NoError(t, err, "unable to get changelist: %v", err) assert.Len(t, cl.List(), 2) // two new keys have been created, and the old keys should still be there newKeys := repo.CryptoService.ListAllKeys() for keyID, role := range initialKeys { r, ok := newKeys[keyID] assert.True(t, ok, "original key %s missing", keyID) assert.Equal(t, role, r) delete(newKeys, keyID) } // there should be 2 keys left assert.Len(t, newKeys, 2) // one for each role var targetsFound, snapshotFound bool for _, role := range newKeys { switch role { case data.CanonicalTargetsRole: targetsFound = true case data.CanonicalSnapshotRole: snapshotFound = true } } assert.True(t, targetsFound, "targets key was not created") assert.True(t, snapshotFound, "snapshot key was not created") }
// CopyKeys copies keys of a particular role to a new cryptoservice, and returns that cryptoservice func CopyKeys(t *testing.T, from signed.CryptoService, roles ...string) signed.CryptoService { memKeyStore := trustmanager.NewKeyMemoryStore(passphrase.ConstantRetriever("pass")) for _, role := range roles { for _, keyID := range from.ListKeys(role) { key, _, err := from.GetPrivateKey(keyID) require.NoError(t, err) memKeyStore.AddKey(trustmanager.KeyInfo{Role: role}, key) } } return cryptoservice.NewCryptoService(memKeyStore) }
func Test0Dot3Migration(t *testing.T) { // make a temporary directory and copy the fixture into it, since updating // and publishing will modify the files tmpDir, err := ioutil.TempDir("", "notary-backwards-compat-test") defer os.RemoveAll(tmpDir) require.NoError(t, err) require.NoError(t, recursiveCopy("../fixtures/compatibility/notary0.3", tmpDir)) gun := "docker.com/notary0.3/samplerepo" passwd := "randompass" ts := fullTestServer(t) defer ts.Close() _, err = NewFileCachedNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) // check that root_keys and tuf_keys are gone and that all corect keys are present and have the correct headers files, _ := ioutil.ReadDir(filepath.Join(tmpDir, notary.PrivDir)) require.Equal(t, files[0].Name(), "041b64dab281324ef2b62fd2d04f4758269e120ff063b7bc78709272821a0a02.key") targKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "041b64dab281324ef2b62fd2d04f4758269e120ff063b7bc78709272821a0a02.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer targKey.Close() targBytes, _ := ioutil.ReadAll(targKey) targString := string(targBytes) require.Contains(t, targString, "gun: docker.com/notary0.3/tst") require.Contains(t, targString, "role: targets") require.Equal(t, files[1].Name(), "85559599cf3cf681ff193f432a7ca6d128182bd1cfa8ede2c70761deac8bc2dc.key") snapKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "85559599cf3cf681ff193f432a7ca6d128182bd1cfa8ede2c70761deac8bc2dc.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer snapKey.Close() snapBytes, _ := ioutil.ReadAll(snapKey) snapString := string(snapBytes) require.Contains(t, snapString, "gun: docker.com/notary0.3/tst") require.Contains(t, snapString, "role: snapshot") require.Equal(t, files[2].Name(), "f4eaf871a74aa3b3a0ff95cef2455a1e4d461639f5625418e76756fc5c948690.key") rootKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "f4eaf871a74aa3b3a0ff95cef2455a1e4d461639f5625418e76756fc5c948690.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer rootKey.Close() rootBytes, _ := ioutil.ReadAll(rootKey) rootString := string(rootBytes) require.Contains(t, rootString, "role: root") require.NotContains(t, rootString, "gun") require.Equal(t, files[3].Name(), "fa842f66cac2dc898677a8660789dcff0e3b0b93b73f8952491f6493199936d3.key") delKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "fa842f66cac2dc898677a8660789dcff0e3b0b93b73f8952491f6493199936d3.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer delKey.Close() delBytes, _ := ioutil.ReadAll(delKey) delString := string(delBytes) require.Contains(t, delString, "role: targets/releases") require.NotContains(t, delString, "gun") require.Len(t, files, 4) }
// the default location for the config file is in ~/.notary/config.json - even if it doesn't exist. func TestNotaryConfigFileDefault(t *testing.T) { commander := ¬aryCommander{ getRetriever: func() notary.PassRetriever { return passphrase.ConstantRetriever("pass") }, } config, err := commander.parseConfig() require.NoError(t, err) configFileUsed := config.ConfigFileUsed() require.True(t, strings.HasSuffix(configFileUsed, filepath.Join(".notary", "config.json")), "Unknown config file: %s", configFileUsed) }
func TestGetImporters(t *testing.T) { if !yubikey.IsAccessible() { t.Skip("Must have Yubikey access.") } tempBaseDir, err := ioutil.TempDir("", "notary-test-") require.NoError(t, err) defer os.RemoveAll(tempBaseDir) importers, err := getImporters(tempBaseDir, passphrase.ConstantRetriever("pass")) require.NoError(t, err) require.Len(t, importers, 2) }
func TestKeyImportNoGUNForSnapshotPEM(t *testing.T) { k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() passphrase.Retriever { return passphrase.ConstantRetriever("pass") }, } tempFileName := generateTempTestKeyFile(t, "snapshot") defer os.Remove(tempFileName) err := k.keysImport(&cobra.Command{}, []string{tempFileName}) assert.Error(t, err) assert.Contains(t, err.Error(), "Must specify GUN") }
func TestKeyImportNoRole(t *testing.T) { k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() passphrase.Retriever { return passphrase.ConstantRetriever("pass") }, } tempFileName := generateTempTestKeyFile(t, "") defer os.Remove(tempFileName) err := k.keysImport(&cobra.Command{}, []string{tempFileName}) assert.Error(t, err) assert.Contains(t, err.Error(), "Could not infer role, and no role was specified for key") }
// Cannot rotate a targets key and require that the server manage it func TestRotateKeyTargetCannotBeServerManaged(t *testing.T) { k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() passphrase.Retriever { return passphrase.ConstantRetriever("pass") }, rotateKeyRole: data.CanonicalTargetsRole, rotateKeyServerManaged: true, } err := k.keysRotate(&cobra.Command{}, []string{"gun"}) assert.Error(t, err) assert.Contains(t, err.Error(), "remote signing/key management is only supported for the snapshot key") }
// Cannot rotate a timestamp key and require that it is locally managed func TestRotateKeyTimestampCannotBeLocallyManaged(t *testing.T) { setUp(t) k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() notary.PassRetriever { return passphrase.ConstantRetriever("pass") }, rotateKeyRole: data.CanonicalTimestampRole, rotateKeyServerManaged: false, } err := k.keysRotate(&cobra.Command{}, []string{"gun", data.CanonicalTimestampRole}) require.Error(t, err) require.IsType(t, client.ErrInvalidLocalRole{}, err) }
// The command line uses NotaryRepository's RotateKey - this is just testing // that the correct config variables are passed for the client to request a key // from the remote server. func TestRotateKeyRemoteServerManagesKey(t *testing.T) { for _, role := range []string{data.CanonicalSnapshotRole, data.CanonicalTimestampRole} { setUp(t) // Temporary directory where test files will be created tempBaseDir, err := ioutil.TempDir("/tmp", "notary-test-") defer os.RemoveAll(tempBaseDir) require.NoError(t, err, "failed to create a temporary directory: %s", err) gun := "docker.com/notary" ret := passphrase.ConstantRetriever("pass") ts, initialKeys := setUpRepo(t, tempBaseDir, gun, ret) defer ts.Close() require.Len(t, initialKeys, 3) k := &keyCommander{ configGetter: func() (*viper.Viper, error) { v := viper.New() v.SetDefault("trust_dir", tempBaseDir) v.SetDefault("remote_server.url", ts.URL) return v, nil }, getRetriever: func() notary.PassRetriever { return ret }, rotateKeyServerManaged: true, } require.NoError(t, k.keysRotate(&cobra.Command{}, []string{gun, role, "-r"})) repo, err := client.NewNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, ret, trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) cl, err := repo.GetChangelist() require.NoError(t, err, "unable to get changelist: %v", err) require.Len(t, cl.List(), 0, "expected the changes to have been published") finalKeys := repo.CryptoService.ListAllKeys() // no keys have been created, since a remote key was specified if role == data.CanonicalSnapshotRole { require.Len(t, finalKeys, 2) for k, r := range initialKeys { if r != data.CanonicalSnapshotRole { _, ok := finalKeys[k] require.True(t, ok) } } } else { require.Len(t, finalKeys, 3) for k := range initialKeys { _, ok := finalKeys[k] require.True(t, ok) } } } }
func TestKeyImportNoGUNForTargetsPEM(t *testing.T) { setUp(t) k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() notary.PassRetriever { return passphrase.ConstantRetriever("pass") }, } tempFileName := generateTempTestKeyFile(t, "targets") defer os.Remove(tempFileName) err := k.keysImport(&cobra.Command{}, []string{tempFileName}) require.Error(t, err) require.Contains(t, err.Error(), "Must specify GUN") }
func TestKeyImportMismatchingRoles(t *testing.T) { k := &keyCommander{ configGetter: func() (*viper.Viper, error) { return viper.New(), nil }, getRetriever: func() passphrase.Retriever { return passphrase.ConstantRetriever("pass") }, keysImportRole: "targets", } tempFileName := generateTempTestKeyFile(t, "snapshot") defer os.Remove(tempFileName) err := k.keysImport(&cobra.Command{}, []string{tempFileName}) assert.Error(t, err) assert.Contains(t, err.Error(), "does not match role") }
// If there are no keys in any of the key stores, a message that there are no // signing keys should be displayed. func TestPrettyPrintZeroKeys(t *testing.T) { ret := passphrase.ConstantRetriever("pass") emptyKeyStore := trustmanager.NewKeyMemoryStore(ret) var b bytes.Buffer prettyPrintKeys([]trustmanager.KeyStore{emptyKeyStore}, &b) text, err := ioutil.ReadAll(&b) assert.NoError(t, err) lines := strings.Split(strings.TrimSpace(string(text)), "\n") assert.Len(t, lines, 1) assert.Equal(t, "No signing keys found.", lines[0]) }
func setupServerHandler(metaStore storage.MetaStore) http.Handler { ctx := context.WithValue(context.Background(), "metaStore", metaStore) ctx = context.WithValue(ctx, "keyAlgorithm", data.ECDSAKey) // Eat the logs instead of spewing them out var b bytes.Buffer l := logrus.New() l.Out = &b ctx = ctxu.WithLogger(ctx, logrus.NewEntry(l)) cryptoService := cryptoservice.NewCryptoService(trustmanager.NewKeyMemoryStore(passphrase.ConstantRetriever("pass"))) return server.RootHandler(nil, ctx, cryptoService, nil, nil, nil) }