Beispiel #1
0
// If there is one key, asking to remove it will ask for confirmation.  Passing
// 'yes'/'y' response will continue the deletion.
func TestRemoveOneKeyConfirm(t *testing.T) {
	setUp(t)
	yesses := []string{"yes", " Y "}

	for _, yesAnswer := range yesses {
		store := trustmanager.NewKeyMemoryStore(ret)

		key, err := utils.GenerateED25519Key(rand.Reader)
		require.NoError(t, err)
		err = store.AddKey(trustmanager.KeyInfo{Role: data.CanonicalRootRole, Gun: ""}, key)
		require.NoError(t, err)

		var out bytes.Buffer
		in := bytes.NewBuffer([]byte(yesAnswer + "\n"))

		err = removeKeyInteractively(
			[]trustmanager.KeyStore{store}, key.ID(), in, &out)
		require.NoError(t, err)
		text, err := ioutil.ReadAll(&out)
		require.NoError(t, err)

		output := string(text)
		require.Contains(t, output, "Are you sure")
		require.Contains(t, output, "Deleted "+key.ID())
		require.Len(t, store.ListKeys(), 0)
	}
}
Beispiel #2
0
// If there is more than one key, removeKeyInteractively will ask which key to
// delete.  Then it will confirm whether they want to delete, and the user can
// abort at that confirmation.
func TestRemoveMultikeysAbortChoice(t *testing.T) {
	setUp(t)
	in := bytes.NewBuffer([]byte("1\nn\n"))

	key, err := utils.GenerateED25519Key(rand.Reader)
	require.NoError(t, err)

	stores := []trustmanager.KeyStore{
		trustmanager.NewKeyMemoryStore(ret),
		trustmanager.NewKeyMemoryStore(ret),
	}

	err = stores[0].AddKey(trustmanager.KeyInfo{Role: data.CanonicalRootRole, Gun: ""}, key)
	require.NoError(t, err)

	err = stores[1].AddKey(trustmanager.KeyInfo{Role: data.CanonicalTargetsRole, Gun: "gun"}, key)
	require.NoError(t, err)

	var out bytes.Buffer

	err = removeKeyInteractively(stores, key.ID(), in, &out)
	require.NoError(t, err) // no error to abort deleting
	text, err := ioutil.ReadAll(&out)
	require.NoError(t, err)

	require.Len(t, stores[0].ListKeys(), 1)
	require.Len(t, stores[1].ListKeys(), 1)

	// It should have listed the keys, asked whether the user really wanted to
	// delete, and then aborted.
	output := string(text)
	require.Contains(t, output, "Found the following matching keys")
	require.Contains(t, output, "Are you sure")
	require.Contains(t, output, "Aborting action")
}
Beispiel #3
0
// If there is one key, asking to remove it will ask for confirmation.  Passing
// anything other than 'yes'/'y'/'' response will abort the deletion and
// not delete the key.
func TestRemoveOneKeyAbort(t *testing.T) {
	setUp(t)
	nos := []string{"no", "NO", "AAAARGH", "   N    "}
	store := trustmanager.NewKeyMemoryStore(ret)

	key, err := utils.GenerateED25519Key(rand.Reader)
	require.NoError(t, err)
	err = store.AddKey(trustmanager.KeyInfo{Role: data.CanonicalRootRole, Gun: ""}, key)
	require.NoError(t, err)

	stores := []trustmanager.KeyStore{store}

	for _, noAnswer := range nos {
		var out bytes.Buffer
		in := bytes.NewBuffer([]byte(noAnswer + "\n"))

		err := removeKeyInteractively(stores, key.ID(), in, &out)
		require.NoError(t, err)
		text, err := ioutil.ReadAll(&out)
		require.NoError(t, err)

		output := string(text)
		require.Contains(t, output, "Are you sure")
		require.Contains(t, output, "Aborting action")
		require.Len(t, store.ListKeys(), 1)
	}
}
Beispiel #4
0
// AddGetKeyCryptoServiceInterfaceBehaviorTests tests expected behavior for
// adding keys in a signed.CryptoService and other read operations on the
// crypto service after keys are present
// 1.  Adding a key succeeds
// 2.  Getting the key should return the same key, without error
// 3.  Removing the key succeeds
func AddGetKeyCryptoServiceInterfaceBehaviorTests(t *testing.T, cs signed.CryptoService, algo string) {
	expectedRolesToKeys := make(map[string]string)
	for i := 0; i < 2; i++ {
		var (
			addedPrivKey data.PrivateKey
			err          error
		)
		role := data.BaseRoles[i+1]
		switch algo {
		case data.RSAKey:
			addedPrivKey, err = utils.GenerateRSAKey(rand.Reader, 2048)
		case data.ECDSAKey:
			addedPrivKey, err = utils.GenerateECDSAKey(rand.Reader)
		case data.ED25519Key:
			addedPrivKey, err = utils.GenerateED25519Key(rand.Reader)
		default:
			require.FailNow(t, "invalid algorithm %s", algo)
		}
		require.NoError(t, err)
		require.NotNil(t, addedPrivKey)
		require.NoError(t, cs.AddKey(role, "docker.io/notary", addedPrivKey))
		expectedRolesToKeys[role] = addedPrivKey.ID()
	}

	testGetKey(t, cs, expectedRolesToKeys, algo)
}
Beispiel #5
0
// 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{GenericKeyStore: *trustmanager.NewKeyMemoryStore(ret)},
	}

	longNameShortened := "..." + strings.Repeat("z", 37)

	keys := make([]data.PrivateKey, 4)
	for i := 0; i < 4; i++ {
		key, err := utils.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))
		}
	}
}
Beispiel #6
0
// Create generates a new key and returns the public part
func (e *Ed25519) Create(role, gun, algorithm string) (data.PublicKey, error) {
	if algorithm != data.ED25519Key {
		return nil, errors.New("only ED25519 supported by this cryptoservice")
	}

	private, err := utils.GenerateED25519Key(rand.Reader)
	if err != nil {
		return nil, err
	}

	e.addKey(role, private)
	return data.PublicKeyFromPrivate(private), nil
}
Beispiel #7
0
// If there is more than one key, removeKeyInteractively will ask which key to
// delete.  Then it will confirm whether they want to delete, and if the user
// confirms, will remove it from the correct key store.
func TestRemoveMultikeysRemoveOnlyChosenKey(t *testing.T) {
	setUp(t)
	in := bytes.NewBuffer([]byte("1\ny\n"))

	key, err := utils.GenerateED25519Key(rand.Reader)
	require.NoError(t, err)

	stores := []trustmanager.KeyStore{
		trustmanager.NewKeyMemoryStore(ret),
		trustmanager.NewKeyMemoryStore(ret),
	}

	err = stores[0].AddKey(trustmanager.KeyInfo{Role: data.CanonicalRootRole, Gun: ""}, key)
	require.NoError(t, err)

	err = stores[1].AddKey(trustmanager.KeyInfo{Role: data.CanonicalTargetsRole, Gun: "gun"}, key)
	require.NoError(t, err)

	var out bytes.Buffer

	err = removeKeyInteractively(stores, key.ID(), in, &out)
	require.NoError(t, err)
	text, err := ioutil.ReadAll(&out)
	require.NoError(t, err)

	// It should have listed the keys, asked whether the user really wanted to
	// delete, and then deleted.
	output := string(text)
	require.Contains(t, output, "Found the following matching keys")
	require.Contains(t, output, "Are you sure")
	require.Contains(t, output, "Deleted "+key.ID())

	// figure out which one we picked to delete, and assert it was deleted
	for _, line := range strings.Split(output, "\n") {
		if strings.HasPrefix(line, "\t1.") { // we picked the first item
			if strings.Contains(line, "root") { // first key store
				require.Len(t, stores[0].ListKeys(), 0)
				require.Len(t, stores[1].ListKeys(), 1)
			} else {
				require.Len(t, stores[0].ListKeys(), 1)
				require.Len(t, stores[1].ListKeys(), 0)
			}
		}
	}
}
Beispiel #8
0
// If there is more than one key, removeKeyInteractively will ask which key to
// delete and will do so over and over until the user quits if the answer is
// invalid.
func TestRemoveMultikeysInvalidInput(t *testing.T) {
	setUp(t)
	in := bytes.NewBuffer([]byte("notanumber\n9999\n-3\n0"))

	key, err := utils.GenerateED25519Key(rand.Reader)
	require.NoError(t, err)

	stores := []trustmanager.KeyStore{
		trustmanager.NewKeyMemoryStore(ret),
		trustmanager.NewKeyMemoryStore(ret),
	}

	err = stores[0].AddKey(trustmanager.KeyInfo{Role: data.CanonicalRootRole, Gun: ""}, key)
	require.NoError(t, err)

	err = stores[1].AddKey(trustmanager.KeyInfo{Role: data.CanonicalTargetsRole, Gun: "gun"}, key)
	require.NoError(t, err)

	var out bytes.Buffer

	err = removeKeyInteractively(stores, key.ID(), in, &out)
	require.Error(t, err)
	text, err := ioutil.ReadAll(&out)
	require.NoError(t, err)

	require.Len(t, stores[0].ListKeys(), 1)
	require.Len(t, stores[1].ListKeys(), 1)

	// It should have listed the keys over and over, asking which key the user
	// wanted to delete
	output := string(text)
	require.Contains(t, output, "Found the following matching keys")
	var rootCount, targetCount int
	for _, line := range strings.Split(output, "\n") {
		if strings.Contains(line, key.ID()) {
			if strings.Contains(line, "target") {
				targetCount++
			} else {
				rootCount++
			}
		}
	}
	require.Equal(t, rootCount, targetCount)
	require.Equal(t, 5, rootCount) // original + 1 for each of the 4 invalid inputs
}
Beispiel #9
0
// helper function to generate private keys for the signer databases - does not implement RSA since that is not
// supported by the signer
func generatePrivateKey(algorithm string) (data.PrivateKey, error) {
	var privKey data.PrivateKey
	var err error
	switch algorithm {
	case data.ECDSAKey:
		privKey, err = utils.GenerateECDSAKey(rand.Reader)
		if err != nil {
			return nil, fmt.Errorf("failed to generate EC key: %v", err)
		}
	case data.ED25519Key:
		privKey, err = utils.GenerateED25519Key(rand.Reader)
		if err != nil {
			return nil, fmt.Errorf("failed to generate ED25519 key: %v", err)
		}
	default:
		return nil, fmt.Errorf("private key type not supported for key generation: %s", algorithm)
	}
	return privKey, nil
}
Beispiel #10
0
// Create is used to generate keys for targets, snapshots and timestamps
func (cs *CryptoService) Create(role, gun, algorithm string) (data.PublicKey, error) {
	var privKey data.PrivateKey
	var err error

	switch algorithm {
	case data.RSAKey:
		privKey, err = utils.GenerateRSAKey(rand.Reader, notary.MinRSABitSize)
		if err != nil {
			return nil, fmt.Errorf("failed to generate RSA key: %v", err)
		}
	case data.ECDSAKey:
		privKey, err = utils.GenerateECDSAKey(rand.Reader)
		if err != nil {
			return nil, fmt.Errorf("failed to generate EC key: %v", err)
		}
	case data.ED25519Key:
		privKey, err = utils.GenerateED25519Key(rand.Reader)
		if err != nil {
			return nil, fmt.Errorf("failed to generate ED25519 key: %v", err)
		}
	default:
		return nil, fmt.Errorf("private key type not supported for key generation: %s", algorithm)
	}
	logrus.Debugf("generated new %s key for role: %s and keyID: %s", algorithm, role, privKey.ID())

	// Store the private key into our keystore
	for _, ks := range cs.keyStores {
		err = ks.AddKey(trustmanager.KeyInfo{Role: role, Gun: gun}, privKey)
		if err == nil {
			return data.PublicKeyFromPrivate(privKey), nil
		}
	}
	if err != nil {
		return nil, fmt.Errorf("failed to add key to filestore: %v", err)
	}

	return nil, fmt.Errorf("keystores would not accept new private keys for unknown reasons")
}