예제 #1
0
// If the timestamp role has a threshold > 1, validation fails.
func TestValidateRootInvalidTimestampThreshold(t *testing.T) {
	gun := "docker.com/notary"
	oldRepo, cs, err := testutils.EmptyRepo(gun)
	require.NoError(t, err)

	tsKey2, err := testutils.CreateKey(cs, gun, "timestamp2", data.ECDSAKey)
	require.NoError(t, err)
	oldRepo.AddBaseKeys(data.CanonicalTimestampRole, tsKey2)
	tsRole, ok := oldRepo.Root.Signed.Roles[data.CanonicalTimestampRole]
	require.True(t, ok)
	tsRole.Threshold = 2

	r, tg, sn, ts, err := testutils.Sign(oldRepo)
	require.NoError(t, err)
	root, targets, snapshot, _, err := getUpdates(r, tg, sn, ts)
	require.NoError(t, err)

	store := storage.NewMemStorage()
	updates := []storage.MetaUpdate{root, targets, snapshot}

	serverCrypto := testutils.CopyKeys(t, cs, data.CanonicalTimestampRole)
	_, err = validateUpdate(serverCrypto, gun, updates, store)
	require.Error(t, err)
	require.IsType(t, validation.ErrBadRoot{}, err)
}
예제 #2
0
func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType string) {
	gun := "docker.com/notary"

	memKeyStore := trustmanager.NewKeyMemoryStore(passphraseRetriever)
	cs := cryptoservice.NewCryptoService(memKeyStore)

	// TUF key with PEM-encoded x509 certificate
	origRootKey, err := testutils.CreateKey(cs, gun, data.CanonicalRootRole, keyAlg)
	require.NoError(t, err)

	origRootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{origRootKey.ID()}, nil)
	require.NoError(t, err)

	origTestRoot, err := data.NewRoot(
		map[string]data.PublicKey{origRootKey.ID(): origRootKey},
		map[string]*data.RootRole{
			data.CanonicalRootRole:      &origRootRole.RootRole,
			data.CanonicalTargetsRole:   &origRootRole.RootRole,
			data.CanonicalSnapshotRole:  &origRootRole.RootRole,
			data.CanonicalTimestampRole: &origRootRole.RootRole,
		},
		false,
	)
	origTestRoot.Signed.Version = 1
	require.NoError(t, err, "Failed to create new root")

	signedOrigTestRoot, err := origTestRoot.ToSigned()
	require.NoError(t, err)

	err = signed.Sign(cs, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
	require.NoError(t, err)
	prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
	require.NoError(t, err)

	// TUF key with PEM-encoded x509 certificate
	replRootKey, err := testutils.CreateKey(cs, gun, data.CanonicalRootRole, keyAlg)
	require.NoError(t, err)

	rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
	require.NoError(t, err)

	testRoot, err := data.NewRoot(
		map[string]data.PublicKey{replRootKey.ID(): replRootKey},
		map[string]*data.RootRole{
			data.CanonicalRootRole:      &rootRole.RootRole,
			data.CanonicalTargetsRole:   &rootRole.RootRole,
			data.CanonicalSnapshotRole:  &rootRole.RootRole,
			data.CanonicalTimestampRole: &rootRole.RootRole,
		},
		false,
	)
	require.NoError(t, err, "Failed to create new root")

	signedTestRoot, err := testRoot.ToSigned()
	require.NoError(t, err)

	// We only sign with the old key, and not with the new one
	err = signed.Sign(cs, signedTestRoot, []data.PublicKey{origRootKey}, 1, nil)
	require.NoError(t, err)

	// This call to trustpinning.ValidateRoot will succeed since we are using a valid PEM
	// encoded certificate, and have no other certificates for this CN
	_, err = trustpinning.ValidateRoot(prevRoot, signedTestRoot, gun, trustpinning.TrustPinConfig{})
	require.Error(t, err, "insuficient signatures on root")
}
예제 #3
0
// A root rotation must be signed with old and new root keys such that it satisfies
// the old and new roles, otherwise the new root fails to validate
func TestRootRotationNotSignedWithOldKeysForOldRole(t *testing.T) {
	gun := "docker.com/notary"
	repo, crypto, err := testutils.EmptyRepo(gun)
	require.NoError(t, err)
	store := storage.NewMemStorage()
	serverCrypto := testutils.CopyKeys(t, crypto, data.CanonicalTimestampRole)

	oldRootKeyID := repo.Root.Signed.Roles[data.CanonicalRootRole].KeyIDs[0]

	// make the original root have 2 keys with a threshold of 2
	pairedRootKeys := make([]data.PublicKey, 2)
	for i := 0; i < len(pairedRootKeys); i++ {
		pairedRootKeys[i], err = testutils.CreateKey(crypto, gun, data.CanonicalRootRole, data.ECDSAKey)
		require.NoError(t, err)
	}
	require.NoError(t, repo.ReplaceBaseKeys(data.CanonicalRootRole, pairedRootKeys...))
	repo.Root.Signed.Roles[data.CanonicalRootRole].Threshold = 2

	r, tg, sn, ts, err := testutils.Sign(repo)
	require.NoError(t, err)
	require.Len(t, r.Signatures, 3)
	root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts)
	require.NoError(t, err)

	updates := []storage.MetaUpdate{root, targets, snapshot, timestamp}
	require.NoError(t, store.UpdateMany(gun, updates))

	finalRootKey, err := testutils.CreateKey(crypto, gun, data.CanonicalRootRole, data.ECDSAKey)
	require.NoError(t, err)
	repo.Root.Signed.Roles[data.CanonicalRootRole].Threshold = 1
	require.NoError(t, repo.ReplaceBaseKeys(data.CanonicalRootRole, finalRootKey))

	r, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
	require.NoError(t, err)
	origSigs := r.Signatures

	// make sure it's signed with only one of the previous keys and the new key
	sigs := make([]data.Signature, 0, 2)
	for _, sig := range origSigs {
		if sig.KeyID == pairedRootKeys[0].ID() || sig.KeyID == finalRootKey.ID() {
			sigs = append(sigs, sig)
		}
	}
	require.Len(t, sigs, 2)
	repo.Root.Signatures = sigs
	r.Signatures = sigs

	sn, err = repo.SignSnapshot(data.DefaultExpires(data.CanonicalSnapshotRole))
	require.NoError(t, err)
	root, targets, snapshot, timestamp, err = getUpdates(r, tg, sn, ts)
	require.NoError(t, err)

	_, err = validateUpdate(serverCrypto, gun, []storage.MetaUpdate{root, snapshot}, store)
	require.Error(t, err)
	require.Contains(t, err.Error(), "could not rotate trust to a new trusted root")

	// now sign with both of the pair and the new one
	sigs = make([]data.Signature, 0, 3)
	for _, sig := range origSigs {
		if sig.KeyID != oldRootKeyID {
			sigs = append(sigs, sig)
		}
	}
	require.Len(t, sigs, 3)
	repo.Root.Signatures = sigs
	r.Signatures = sigs

	sn, err = repo.SignSnapshot(data.DefaultExpires(data.CanonicalSnapshotRole))
	require.NoError(t, err)
	root, _, snapshot, _, err = getUpdates(r, tg, sn, ts)
	require.NoError(t, err)

	_, err = validateUpdate(serverCrypto, gun, []storage.MetaUpdate{root, snapshot}, store)
	require.NoError(t, err)
}
예제 #4
0
// A valid root rotation requires the immediately previous root ROLE be satisfied,
// not just that there is a single root signature.  So if there were 2 keys, either
// of which can sign the root rotation, then either one of those keys can be used
// to sign the root rotation - not necessarily the one that signed the previous root.
func TestValidateRootRotationMultipleKeysThreshold1(t *testing.T) {
	gun := "docker.com/notary"
	repo, crypto, err := testutils.EmptyRepo(gun)
	require.NoError(t, err)
	serverCrypto := testutils.CopyKeys(t, crypto, data.CanonicalTimestampRole)
	store := storage.NewMemStorage()

	// add a new root key to the root so that either can sign have to sign
	additionalRootKey, err := testutils.CreateKey(crypto, gun, data.CanonicalRootRole, data.ECDSAKey)
	require.NoError(t, err)
	additionalRootID := additionalRootKey.ID()
	repo.Root.Signed.Keys[additionalRootID] = additionalRootKey
	repo.Root.Signed.Roles[data.CanonicalRootRole].KeyIDs = append(
		repo.Root.Signed.Roles[data.CanonicalRootRole].KeyIDs, additionalRootID)

	r, tg, sn, ts, err := testutils.Sign(repo)
	require.NoError(t, err)
	require.Len(t, r.Signatures, 2)
	// make sure the old root was just signed with the first key
	for _, sig := range r.Signatures {
		if sig.KeyID != additionalRootID {
			r.Signatures = []data.Signature{sig}
			break
		}
	}
	require.Len(t, r.Signatures, 1)
	root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts)
	require.NoError(t, err)

	// set the original root in the store
	updates := []storage.MetaUpdate{root, targets, snapshot, timestamp}
	require.NoError(t, store.UpdateMany(gun, updates))

	// replace the keys with just 1 key
	rotatedRootKey, err := testutils.CreateKey(crypto, gun, data.CanonicalRootRole, data.ECDSAKey)
	require.NoError(t, err)
	rotatedRootID := rotatedRootKey.ID()
	require.NoError(t, repo.ReplaceBaseKeys(data.CanonicalRootRole, rotatedRootKey))

	r, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
	require.NoError(t, err)
	require.Len(t, r.Signatures, 3)
	// delete all signatures except the additional key (which didn't sign the
	// previous root) and the new key
	sigs := make([]data.Signature, 0, 2)
	for _, sig := range repo.Root.Signatures {
		if sig.KeyID == additionalRootID || sig.KeyID == rotatedRootID {
			sigs = append(sigs, sig)
		}
	}
	require.Len(t, sigs, 2)
	repo.Root.Signatures = sigs
	r.Signatures = sigs

	sn, err = repo.SignSnapshot(data.DefaultExpires(data.CanonicalSnapshotRole))
	require.NoError(t, err)

	root, _, snapshot, _, err = getUpdates(r, tg, sn, ts)
	require.NoError(t, err)
	root.Version = repo.Root.Signed.Version
	snapshot.Version = repo.Snapshot.Signed.Version
	_, err = validateUpdate(serverCrypto, gun, []storage.MetaUpdate{root, snapshot}, store)
	require.NoError(t, err)
}
예제 #5
0
// A valid root rotation only cares about the immediately previous old root keys,
// whether or not there are old root roles
func TestValidateRootRotationWithOldSigs(t *testing.T) {
	gun := "docker.com/notary"
	repo, crypto, err := testutils.EmptyRepo(gun)
	require.NoError(t, err)
	serverCrypto := testutils.CopyKeys(t, crypto, data.CanonicalTimestampRole)
	store := storage.NewMemStorage()

	r, tg, sn, ts, err := testutils.Sign(repo)
	require.NoError(t, err)
	root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts)
	require.NoError(t, err)

	// set the original root in the store
	updates := []storage.MetaUpdate{root, targets, snapshot, timestamp}
	require.NoError(t, store.UpdateMany(gun, updates))

	// rotate the root key, sign with both keys, and update - update should succeed
	newRootKey, err := testutils.CreateKey(crypto, gun, data.CanonicalRootRole, data.ECDSAKey)
	require.NoError(t, err)
	newRootID := newRootKey.ID()

	require.NoError(t, repo.ReplaceBaseKeys(data.CanonicalRootRole, newRootKey))
	r, _, sn, _, err = testutils.Sign(repo)
	require.NoError(t, err)
	root, _, snapshot, _, err = getUpdates(r, tg, sn, ts)
	require.NoError(t, err)
	root.Version = repo.Root.Signed.Version
	snapshot.Version = repo.Snapshot.Signed.Version

	updates, err = validateUpdate(serverCrypto, gun, []storage.MetaUpdate{root, snapshot}, store)
	require.NoError(t, err)
	require.NoError(t, store.UpdateMany(gun, updates))

	// the next root does NOT need to be signed by both keys, because we only care
	// about signing with both keys if the root keys have changed (signRoot again to bump the version)

	r, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
	require.NoError(t, err)
	// delete all signatures except the one with the new key
	for _, sig := range repo.Root.Signatures {
		if sig.KeyID == newRootID {
			r.Signatures = []data.Signature{sig}
			repo.Root.Signatures = r.Signatures
			break
		}
	}
	sn, err = repo.SignSnapshot(data.DefaultExpires(data.CanonicalSnapshotRole))
	require.NoError(t, err)

	root, _, snapshot, _, err = getUpdates(r, tg, sn, ts)
	require.NoError(t, err)
	root.Version = repo.Root.Signed.Version
	snapshot.Version = repo.Snapshot.Signed.Version
	updates, err = validateUpdate(serverCrypto, gun, []storage.MetaUpdate{root, snapshot}, store)
	require.NoError(t, err)
	require.NoError(t, store.UpdateMany(gun, updates))

	// another root rotation requires only the previous and new keys, and not the
	// original root key even though that original role is still in the metadata

	newRootKey2, err := testutils.CreateKey(crypto, gun, data.CanonicalRootRole, data.ECDSAKey)
	require.NoError(t, err)
	newRootID2 := newRootKey2.ID()

	require.NoError(t, repo.ReplaceBaseKeys(data.CanonicalRootRole, newRootKey2))
	r, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
	require.NoError(t, err)
	// delete all signatures except the ones with the first and second new keys
	sigs := make([]data.Signature, 0, 2)
	for _, sig := range repo.Root.Signatures {
		if sig.KeyID == newRootID || sig.KeyID == newRootID2 {
			sigs = append(sigs, sig)
		}
	}
	require.Len(t, sigs, 2)
	repo.Root.Signatures = sigs
	r.Signatures = sigs

	sn, err = repo.SignSnapshot(data.DefaultExpires(data.CanonicalSnapshotRole))
	require.NoError(t, err)

	root, _, snapshot, _, err = getUpdates(r, tg, sn, ts)
	require.NoError(t, err)
	root.Version = repo.Root.Signed.Version
	snapshot.Version = repo.Snapshot.Signed.Version
	_, err = validateUpdate(serverCrypto, gun, []storage.MetaUpdate{root, snapshot}, store)
	require.NoError(t, err)
}
예제 #6
0
// If the parent, either from the DB or from an update, does not contain the role
// of the delegation update, validation fails
func TestValidateTargetsRoleNotInParent(t *testing.T) {
	// no delegation at first
	gun := "docker.com/notary"
	repo, cs, err := testutils.EmptyRepo(gun)
	require.NoError(t, err)

	meta, err := testutils.SignAndSerialize(repo)
	require.NoError(t, err)

	// load the root into the builder, else we can't load anything else
	builder := tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{})
	require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false))

	// prepare the original targets file, without a delegation role, as an update
	origTargetsUpdate := storage.MetaUpdate{
		Role:    data.CanonicalTargetsRole,
		Version: 1,
		Data:    meta[data.CanonicalTargetsRole],
	}
	emptyStore := storage.NewMemStorage()
	storeWithParent := storage.NewMemStorage()
	storeWithParent.UpdateCurrent(gun, origTargetsUpdate)

	// add a delegation role now
	delgName := "targets/level1"
	level1Key, err := testutils.CreateKey(cs, gun, delgName, data.ECDSAKey)
	require.NoError(t, err)
	require.NoError(t, repo.UpdateDelegationKeys(delgName, []data.PublicKey{level1Key}, []string{}, 1))
	// create the delegation metadata too
	repo.InitTargets(delgName)

	// re-serialize
	meta, err = testutils.SignAndSerialize(repo)
	require.NoError(t, err)
	delgMeta, ok := meta[delgName]
	require.True(t, ok)

	delgUpdate := storage.MetaUpdate{
		Role:    delgName,
		Version: 1,
		Data:    delgMeta,
	}

	// parent in update does not have this role, whether or not there's a parent in the store,
	// so validation fails
	roles := map[string]storage.MetaUpdate{
		delgName:                  delgUpdate,
		data.CanonicalTargetsRole: origTargetsUpdate,
	}
	for _, metaStore := range []storage.MetaStore{emptyStore, storeWithParent} {
		updates, err := loadAndValidateTargets(gun, builder, roles, metaStore)
		require.Error(t, err)
		require.Empty(t, updates)
		require.IsType(t, validation.ErrBadTargets{}, err)
	}

	// if the update is provided without the parent, then the parent from the
	// store is loaded - if it doesn't have the role, then the update fails
	updates, err := loadAndValidateTargets(gun, builder,
		map[string]storage.MetaUpdate{delgName: delgUpdate}, storeWithParent)
	require.Error(t, err)
	require.Empty(t, updates)
	require.IsType(t, validation.ErrBadTargets{}, err)
}