Example #1
0
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)
}
Example #2
0
func rootCertKey(gun string, privKey data.PrivateKey) (data.PublicKey, error) {
	// Hard-coded policy: the generated certificate expires in 10 years.
	startTime := time.Now()
	cert, err := cryptoservice.GenerateCertificate(
		privKey, gun, startTime, startTime.Add(notary.Year*10))
	if err != nil {
		return nil, err
	}

	x509PublicKey := trustmanager.CertToKey(cert)
	if x509PublicKey == nil {
		return nil, fmt.Errorf(
			"cannot use regenerated certificate: format %s", cert.PublicKeyAlgorithm)
	}

	return x509PublicKey, nil
}
Example #3
0
// SignRoot signs with all old roles with valid keys, and also optionally any old
// signatures we have keys for even if they aren't in an old root.  It ignores any
// root role whose version is higher than the current version.  If signing fails,
// it reverts back.
func TestSignRootOldRootRolesAndOldSigs(t *testing.T) {
	gun := "docker/test-sign-root"
	referenceTime := time.Now()

	cs := cryptoservice.NewCryptoService(trustmanager.NewKeyMemoryStore(
		passphrase.ConstantRetriever("password")))

	rootCertKeys := make([]data.PublicKey, 9)
	rootPrivKeys := make([]data.PrivateKey, cap(rootCertKeys))
	for i := 0; i < cap(rootCertKeys); i++ {
		rootPublicKey, err := cs.Create(data.CanonicalRootRole, gun, data.ECDSAKey)
		require.NoError(t, err)
		rootPrivateKey, _, err := cs.GetPrivateKey(rootPublicKey.ID())
		require.NoError(t, err)
		rootCert, err := cryptoservice.GenerateCertificate(rootPrivateKey, gun, referenceTime.AddDate(-9, 0, 0),
			referenceTime.AddDate(1, 0, 0))
		require.NoError(t, err)
		rootCertKeys[i] = trustmanager.CertToKey(rootCert)
		rootPrivKeys[i] = rootPrivateKey
	}

	repo := initRepoWithRoot(t, cs, rootCertKeys[6])
	// sign with key 0, which represents the key for the a version of the root we
	// no longer have a record of
	signedObj, err := repo.Root.ToSigned()
	require.NoError(t, err)
	signedObj, err = repo.sign(signedObj, nil, []data.PublicKey{rootCertKeys[0]})
	require.NoError(t, err)
	// should be signed with key 0
	verifySignatureList(t, signedObj, rootCertKeys[0])
	repo.Root.Signatures = signedObj.Signatures

	// bump root version and also add the above keys and extra roles to root
	repo.Root.Signed.Version = 6
	oldExpiry := repo.Root.Signed.Expires
	// add every key to the root's key list except 1
	for i, key := range rootCertKeys {
		if i != 1 {
			repo.Root.Signed.Keys[key.ID()] = key
		}
	}
	// invalid root role because key not included in the key map - valid root version name
	repo.Root.Signed.Roles["root.1"] = &data.RootRole{KeyIDs: []string{rootCertKeys[1].ID()}, Threshold: 1}
	// invalid root versions names, but valid roles
	repo.Root.Signed.Roles["2.root"] = &data.RootRole{KeyIDs: []string{rootCertKeys[2].ID()}, Threshold: 1}
	repo.Root.Signed.Roles["root3"] = &data.RootRole{KeyIDs: []string{rootCertKeys[3].ID()}, Threshold: 1}
	repo.Root.Signed.Roles["root.4a"] = &data.RootRole{KeyIDs: []string{rootCertKeys[4].ID()}, Threshold: 1}
	// valid old root role and version
	repo.Root.Signed.Roles["root.5"] = &data.RootRole{KeyIDs: []string{rootCertKeys[5].ID()}, Threshold: 1}
	// greater or equal to the current root version, so invalid name, but valid root role
	repo.Root.Signed.Roles["root.6"] = &data.RootRole{KeyIDs: []string{rootCertKeys[7].ID()}, Threshold: 1}

	lenRootRoles := len(repo.Root.Signed.Roles)

	// rotate the current key to key 8
	require.NoError(t, repo.ReplaceBaseKeys(data.CanonicalRootRole, rootCertKeys[8]))

	requiredKeys := []data.PrivateKey{
		rootPrivKeys[5], // we need an old valid root role - this was specified in root5
		rootPrivKeys[6], // we need the previous valid key prior to root rotation
		rootPrivKeys[8], // we need the new root key we've rotated to
	}

	for _, privKey := range requiredKeys {
		// if we can't sign with a previous root, we fail
		require.NoError(t, cs.RemoveKey(privKey.ID()))
		_, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
		require.Error(t, err)
		require.IsType(t, signed.ErrInsufficientSignatures{}, err)
		require.Contains(t, err.Error(), "signing keys not available")

		// add back for next test
		require.NoError(t, cs.AddKey(data.CanonicalRootRole, gun, privKey))
	}
	// we haven't saved any unsaved roles because there was an error signing,
	// nor have we bumped the version or altered the expiry
	require.Equal(t, 6, repo.Root.Signed.Version)
	require.Equal(t, oldExpiry, repo.Root.Signed.Expires)
	require.Len(t, repo.Root.Signed.Roles, lenRootRoles)

	// remove all the keys we don't need and demonstrate we can still sign
	for _, index := range []int{1, 2, 3, 4, 7} {
		require.NoError(t, cs.RemoveKey(rootPrivKeys[index].ID()))
	}

	// SignRoot will sign with all the old keys based on old root roles as well
	// as any old signatures
	signedObj, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
	require.NoError(t, err)
	expectedSigningKeys := []data.PublicKey{
		rootCertKeys[0], // old signature key, not in any role
		rootCertKeys[5], // root.5 key which is valid
		rootCertKeys[6], // previous key before rotation,
		rootCertKeys[8], //  newly rotated key
	}
	verifySignatureList(t, signedObj, expectedSigningKeys...)
	// verify that we saved the previous root (which overwrote an invalid saved root),
	// since it wasn't in the list of old valid roots, and we didn't save the newest
	// role
	require.NotNil(t, repo.Root.Signed.Roles["root.6"])
	require.Equal(t, data.RootRole{KeyIDs: []string{rootCertKeys[6].ID()}, Threshold: 1},
		*repo.Root.Signed.Roles["root.6"])
	require.Nil(t, repo.Root.Signed.Roles["root.7"])

	// bumped version, 1 new roles, but one overwrote the previous root.6, so actually no
	// additional roles
	require.Equal(t, 7, repo.Root.Signed.Version)
	require.Len(t, repo.Root.Signed.Roles, lenRootRoles)
	require.True(t, oldExpiry.Before(repo.Root.Signed.Expires))
	lenRootRoles = len(repo.Root.Signed.Roles)

	// remove the optional key
	require.NoError(t, cs.RemoveKey(rootPrivKeys[0].ID()))

	// SignRoot will still succeed even if the key that wasn't in a root isn't
	// available
	oldExpiry = repo.Root.Signed.Expires
	signedObj, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
	require.NoError(t, err)
	verifySignatureList(t, signedObj, expectedSigningKeys[1:]...)

	// no additional roles were added
	require.Len(t, repo.Root.Signed.Roles, lenRootRoles)
	require.Equal(t, 8, repo.Root.Signed.Version)               // bumped version
	require.True(t, oldExpiry.Before(repo.Root.Signed.Expires)) // expiry updated

	// now rotate a non-root key
	newTargetsKey, err := cs.Create(data.CanonicalTargetsRole, gun, data.ECDSAKey)
	require.NoError(t, err)
	require.NoError(t, repo.ReplaceBaseKeys(data.CanonicalTargetsRole, newTargetsKey))

	// we still sign with all old roles no additional roles were added
	oldExpiry = repo.Root.Signed.Expires
	signedObj, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
	require.NoError(t, err)
	verifySignatureList(t, signedObj, expectedSigningKeys[1:]...)
	require.Len(t, repo.Root.Signed.Roles, lenRootRoles)
	require.Equal(t, 9, repo.Root.Signed.Version)               // bumped version
	require.True(t, oldExpiry.Before(repo.Root.Signed.Expires)) // expiry updated

	// rotating a targets key again, if we are missing the previous root's keys, signing will fail
	newTargetsKey, err = cs.Create(data.CanonicalTargetsRole, gun, data.ECDSAKey)
	require.NoError(t, err)
	require.NoError(t, repo.ReplaceBaseKeys(data.CanonicalTargetsRole, newTargetsKey))

	require.NoError(t, cs.RemoveKey(rootPrivKeys[6].ID()))

	oldExpiry = repo.Root.Signed.Expires
	_, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
	require.Error(t, err)
	require.IsType(t, signed.ErrInsufficientSignatures{}, err)
	require.Contains(t, err.Error(), "signing keys not available")

	// no additional roles were saved, version has not changed
	require.Len(t, repo.Root.Signed.Roles, lenRootRoles)
	require.Equal(t, 9, repo.Root.Signed.Version) // version has not changed
	require.Equal(t, oldExpiry, repo.Root.Signed.Expires)
}