From 9da40f07da30b68f781ad3898a63c5811c2b6fe1 Mon Sep 17 00:00:00 2001
From: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
Date: Thu, 21 Apr 2016 11:18:35 -0700
Subject: [PATCH] Foundation for removing certstore

Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
---
 client/client.go           |  26 ++++-
 trustpinning/certs.go      |  74 +++----------
 trustpinning/certs_test.go | 218 ++++++++++++++++---------------------
 3 files changed, 134 insertions(+), 184 deletions(-)

diff --git a/client/client.go b/client/client.go
index 19284a3219..8a7c7230c3 100644
--- a/client/client.go
+++ b/client/client.go
@@ -812,7 +812,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Cl
 	rootJSON, cachedRootErr := r.fileStore.GetMeta(data.CanonicalRootRole, -1)
 
 	if cachedRootErr == nil {
-		signedRoot, cachedRootErr = r.validateRoot(rootJSON)
+		signedRoot, cachedRootErr = r.validateRoot(rootJSON, false)
 	}
 
 	remote, remoteErr := getRemoteStore(r.baseURL, r.gun, r.roundTrip)
@@ -833,7 +833,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Cl
 		if cachedRootErr != nil {
 			// we always want to use the downloaded root if there was a cache
 			// error.
-			signedRoot, err = r.validateRoot(tmpJSON)
+			signedRoot, err = r.validateRoot(tmpJSON, true)
 			if err != nil {
 				return nil, err
 			}
@@ -868,7 +868,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Cl
 // signatures of the root based on known keys, not expiry or other metadata.
 // This is so that an out of date root can be loaded to be used in a rotation
 // should the TUF update process detect a problem.
-func (r *NotaryRepository) validateRoot(rootJSON []byte) (*data.SignedRoot, error) {
+func (r *NotaryRepository) validateRoot(rootJSON []byte, fromRemote bool) (*data.SignedRoot, error) {
 	// can't just unmarshal into SignedRoot because validate root
 	// needs the root.Signed field to still be []byte for signature
 	// validation
@@ -878,7 +878,25 @@ func (r *NotaryRepository) validateRoot(rootJSON []byte) (*data.SignedRoot, erro
 		return nil, err
 	}
 
-	err = trustpinning.ValidateRoot(r.CertStore, root, r.gun, r.trustPinning)
+	// If we're downloading a root from a remote source, attempt to load a local root
+	// to ensure that we consider old roots when validating this new one
+	var prevRoot *data.SignedRoot
+	if fromRemote {
+		prevRootJSON, err := r.fileStore.GetMeta(data.CanonicalRootRole, -1)
+		if err == nil {
+			prevSignedRoot := &data.Signed{}
+			err = json.Unmarshal(prevRootJSON, prevSignedRoot)
+			if err == nil {
+				prevRoot, err = data.RootFromSigned(prevSignedRoot)
+			}
+		}
+	}
+	// If we had any errors while trying to retrieve the previous root, just set it to nil
+	if err != nil {
+		prevRoot = nil
+	}
+
+	err = trustpinning.ValidateRoot(prevRoot, root, r.gun, r.trustPinning)
 	if err != nil {
 		return nil, err
 	}
diff --git a/trustpinning/certs.go b/trustpinning/certs.go
index bcfb27201e..fc9432de40 100644
--- a/trustpinning/certs.go
+++ b/trustpinning/certs.go
@@ -86,7 +86,7 @@ We shall call this: TOFUS.
 
 Validation failure at any step will result in an ErrValidationFailed error.
 */
-func ValidateRoot(certStore trustmanager.X509Store, root *data.Signed, gun string, trustPinning TrustPinConfig) error {
+func ValidateRoot(prevRoot *data.SignedRoot, root *data.Signed, gun string, trustPinning TrustPinConfig) error {
 	logrus.Debugf("entered ValidateRoot with dns: %s", gun)
 	signedRoot, err := data.RootFromSigned(root)
 	if err != nil {
@@ -100,30 +100,23 @@ func ValidateRoot(certStore trustmanager.X509Store, root *data.Signed, gun strin
 
 	// Retrieve all the leaf and intermediate certificates in root for which the CN matches the GUN
 	allLeafCerts, allIntCerts := parseAllCerts(signedRoot)
-	certsFromRoot, err := validRootLeafCerts(allLeafCerts, gun)
+	certsFromRoot, err := validRootLeafCerts(allLeafCerts, gun, true)
 	if err != nil {
 		logrus.Debugf("error retrieving valid leaf certificates for: %s, %v", gun, err)
 		return &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"}
 	}
 
-	// Retrieve all the trusted certificates that match this gun
-	trustedCerts, err := certStore.GetCertificatesByCN(gun)
-	if err != nil {
-		// If the error that we get back is different than ErrNoCertificatesFound
-		// we couldn't check if there are any certificates with this CN already
-		// trusted. Let's take the conservative approach and return a failed validation
-		if _, ok := err.(*trustmanager.ErrNoCertificatesFound); !ok {
-			logrus.Debugf("error retrieving trusted certificates for: %s, %v", gun, err)
-			return &ErrValidationFail{Reason: "unable to retrieve trusted certificates"}
-		}
-	}
+	// Retrieve all the trusted certificates from our previous root
+	// Note that we do not validate expiries here since our originally trusted root might have expired certs
+	allTrustedLeafCerts, allTrustedIntCerts := parseAllCerts(prevRoot)
+	trustedLeafCerts, err := validRootLeafCerts(allTrustedLeafCerts, gun, false)
 	// If we have certificates that match this specific GUN, let's make sure to
 	// use them first to validate that this new root is valid.
-	if len(trustedCerts) != 0 {
-		logrus.Debugf("found %d valid root certificates for %s: %s", len(trustedCerts), gun,
-			prettyFormatCertIDs(trustedCerts))
+	if len(trustedLeafCerts) != 0 {
+		logrus.Debugf("found %d valid root leaf certificates for %s: %s", len(trustedLeafCerts), gun,
+			prettyFormatCertIDs(trustedLeafCerts))
 		err = signed.VerifySignatures(
-			root, data.BaseRole{Keys: trustmanager.CertsToKeys(trustedCerts, allIntCerts), Threshold: 1})
+			root, data.BaseRole{Keys: trustmanager.CertsToKeys(trustedLeafCerts, allTrustedIntCerts), Threshold: 1})
 		if err != nil {
 			logrus.Debugf("failed to verify TUF data for: %s, %v", gun, err)
 			return &ErrValidationFail{Reason: "failed to validate data with current trusted certificates"}
@@ -162,49 +155,14 @@ func ValidateRoot(certStore trustmanager.X509Store, root *data.Signed, gun strin
 		return &ErrValidationFail{Reason: "failed to validate integrity of roots"}
 	}
 
-	// Getting here means:
-	// A) we had trusted certificates and both the old and new validated this root.
-	// or
-	// B) we had no trusted certificates but the new set of certificates has integrity (self-signed).
-	logrus.Debugf("entering root certificate rotation for: %s", gun)
-
-	// Do root certificate rotation: we trust only the certs present in the new root
-	// First we add all the new certificates (even if they already exist)
-	for _, cert := range certsFromRoot {
-		err := certStore.AddCert(cert)
-		if err != nil {
-			// If the error is already exists we don't fail the rotation
-			if _, ok := err.(*trustmanager.ErrCertExists); ok {
-				logrus.Debugf("ignoring certificate addition to: %s", gun)
-				continue
-			}
-			logrus.Debugf("error adding new trusted certificate for: %s, %v", gun, err)
-		}
-	}
-
-	// Now we delete old certificates that aren't present in the new root
-	oldCertsToRemove, err := certsToRemove(trustedCerts, certsFromRoot)
-	if err != nil {
-		logrus.Debugf("inconsistency when removing old certificates: %v", err)
-		return err
-	}
-	for certID, cert := range oldCertsToRemove {
-		logrus.Debugf("removing certificate with certID: %s", certID)
-		err = certStore.RemoveCert(cert)
-		if err != nil {
-			logrus.Debugf("failed to remove trusted certificate with keyID: %s, %v", certID, err)
-			return &ErrRootRotationFail{Reason: "failed to rotate root keys"}
-		}
-	}
-
 	logrus.Debugf("Root validation succeeded for %s", gun)
 	return nil
 }
 
-// validRootLeafCerts returns a list of non-expired, non-sha1 certificates
+// validRootLeafCerts returns a list of possibly (if checkExpiry is true) non-expired, non-sha1 certificates
 // found in root whose Common-Names match the provided GUN. Note that this
 // "validity" alone does not imply any measure of trust.
-func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun string) ([]*x509.Certificate, error) {
+func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun string, checkExpiry bool) ([]*x509.Certificate, error) {
 	var validLeafCerts []*x509.Certificate
 
 	// Go through every leaf certificate and check that the CN matches the gun
@@ -215,8 +173,8 @@ func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun string) (
 				cert.Subject.CommonName, gun)
 			continue
 		}
-		// Make sure the certificate is not expired
-		if time.Now().After(cert.NotAfter) {
+		// Make sure the certificate is not expired if checkExpiry is true
+		if checkExpiry && time.Now().After(cert.NotAfter) {
 			logrus.Debugf("error leaf certificate is expired")
 			continue
 		}
@@ -246,6 +204,10 @@ func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun string) (
 // parseAllCerts returns two maps, one with all of the leafCertificates and one
 // with all the intermediate certificates found in signedRoot
 func parseAllCerts(signedRoot *data.SignedRoot) (map[string]*x509.Certificate, map[string][]*x509.Certificate) {
+	if signedRoot == nil {
+		return nil, nil
+	}
+
 	leafCerts := make(map[string]*x509.Certificate)
 	intCerts := make(map[string][]*x509.Certificate)
 
diff --git a/trustpinning/certs_test.go b/trustpinning/certs_test.go
index 4b64778931..d2f5a1fee3 100644
--- a/trustpinning/certs_test.go
+++ b/trustpinning/certs_test.go
@@ -18,7 +18,6 @@ import (
 
 	"time"
 
-	"github.com/docker/notary"
 	"github.com/docker/notary/cryptoservice"
 	"github.com/docker/notary/trustmanager"
 	"github.com/docker/notary/tuf/data"
@@ -133,14 +132,6 @@ func TestValidateRoot(t *testing.T) {
 	defer os.RemoveAll(tempBaseDir)
 	require.NoError(t, err, "failed to create a temporary directory: %s", err)
 
-	// Create a X509Store
-	trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
-	certStore, err := trustmanager.NewX509FilteredFileStore(
-		trustPath,
-		trustmanager.FilterCertsExpiredSha1,
-	)
-	require.NoError(t, err)
-
 	// Execute our template
 	templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
 	templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
@@ -150,12 +141,12 @@ func TestValidateRoot(t *testing.T) {
 
 	// This call to ValidateRoot will succeed since we are using a valid PEM
 	// encoded certificate, and have no other certificates for this CN
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
 	require.NoError(t, err)
 
 	// This call to ValidateRoot will fail since we are passing in a dnsName that
 	// doesn't match the CN of the certificate.
-	err = ValidateRoot(certStore, &testSignedRoot, "diogomonica.com/notary", TrustPinConfig{})
+	err = ValidateRoot(nil, &testSignedRoot, "diogomonica.com/notary", TrustPinConfig{})
 	require.Error(t, err, "An error was expected")
 	require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
 
@@ -169,7 +160,7 @@ func TestValidateRoot(t *testing.T) {
 	// Unmarshal our signedroot
 	json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
 
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
 	require.Error(t, err, "illegal base64 data at input byte")
 
 	//
@@ -182,7 +173,7 @@ func TestValidateRoot(t *testing.T) {
 	// Unmarshal our signedroot
 	json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
 
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
 	require.Error(t, err, "An error was expected")
 	require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
 
@@ -197,7 +188,7 @@ func TestValidateRoot(t *testing.T) {
 	// Unmarshal our signedroot
 	json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
 
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
 	require.Error(t, err, "An error was expected")
 	require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
 
@@ -216,7 +207,7 @@ func TestValidateRoot(t *testing.T) {
 	// Unmarshal our signedroot
 	json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
 
-	err = ValidateRoot(certStore, &testSignedRoot, "secure.example.com", TrustPinConfig{})
+	err = ValidateRoot(nil, &testSignedRoot, "secure.example.com", TrustPinConfig{})
 	require.Error(t, err, "An error was expected")
 	require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
 }
@@ -230,14 +221,6 @@ func TestValidateRootWithoutTOFUS(t *testing.T) {
 	defer os.RemoveAll(tempBaseDir)
 	require.NoError(t, err, "failed to create a temporary directory: %s", err)
 
-	// Create a X509Store
-	trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
-	certStore, err := trustmanager.NewX509FilteredFileStore(
-		trustPath,
-		trustmanager.FilterCertsExpiredSha1,
-	)
-	require.NoError(t, err)
-
 	// Execute our template
 	templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
 	templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
@@ -246,7 +229,7 @@ func TestValidateRootWithoutTOFUS(t *testing.T) {
 	json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
 
 	// This call to ValidateRoot will fail since we are explicitly disabling TOFU and have no local certs
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{DisableTOFU: true})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{DisableTOFU: true})
 	require.Error(t, err)
 }
 
@@ -259,14 +242,6 @@ func TestValidateRootWithPinnedCert(t *testing.T) {
 	defer os.RemoveAll(tempBaseDir)
 	require.NoError(t, err, "failed to create a temporary directory: %s", err)
 
-	// Create a X509Store
-	trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
-	certStore, err := trustmanager.NewX509FilteredFileStore(
-		trustPath,
-		trustmanager.FilterCertsExpiredSha1,
-	)
-	require.NoError(t, err)
-
 	// Execute our template
 	templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
 	templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
@@ -275,14 +250,11 @@ func TestValidateRootWithPinnedCert(t *testing.T) {
 	json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
 
 	// This call to ValidateRoot should succeed with the correct Cert ID (same as root public key ID)
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {rootPubKeyID}}, DisableTOFU: true})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {rootPubKeyID}}, DisableTOFU: true})
 	require.NoError(t, err)
 
-	// purge the cert store to check another valid certs trust pinning
-	certStore.RemoveAll()
-
 	// This call to ValidateRoot should also succeed with the correct Cert ID (same as root public key ID), even though we passed an extra bad one
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {rootPubKeyID, "invalidID"}}, DisableTOFU: true})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {rootPubKeyID, "invalidID"}}, DisableTOFU: true})
 	require.NoError(t, err)
 }
 
@@ -439,16 +411,9 @@ func TestValidateRootWithPinnerCertAndIntermediates(t *testing.T) {
 	tempBaseDir, err := ioutil.TempDir("", "notary-test-")
 	defer os.RemoveAll(tempBaseDir)
 	require.NoError(t, err, "failed to create a temporary directory: %s", err)
-	// Create a X509Store
-	trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
-	certStore, err := trustmanager.NewX509FilteredFileStore(
-		trustPath,
-		trustmanager.FilterCertsExpiredSha1,
-	)
-	require.NoError(t, err)
 
 	err = ValidateRoot(
-		certStore,
+		nil,
 		signedRoot,
 		"docker.io/notary/test",
 		TrustPinConfig{
@@ -470,14 +435,6 @@ func TestValidateRootFailuresWithPinnedCert(t *testing.T) {
 	defer os.RemoveAll(tempBaseDir)
 	require.NoError(t, err, "failed to create a temporary directory: %s", err)
 
-	// Create a X509Store
-	trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
-	certStore, err := trustmanager.NewX509FilteredFileStore(
-		trustPath,
-		trustmanager.FilterCertsExpiredSha1,
-	)
-	require.NoError(t, err)
-
 	// Execute our template
 	templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
 	templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
@@ -486,23 +443,23 @@ func TestValidateRootFailuresWithPinnedCert(t *testing.T) {
 	json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
 
 	// This call to ValidateRoot should fail due to an incorrect cert ID
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {"ABSOLUTELY NOT A CERT ID"}}, DisableTOFU: true})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {"ABSOLUTELY NOT A CERT ID"}}, DisableTOFU: true})
 	require.Error(t, err)
 
 	// This call to ValidateRoot should fail due to an empty cert ID
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {""}}, DisableTOFU: true})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {""}}, DisableTOFU: true})
 	require.Error(t, err)
 
 	// This call to ValidateRoot should fail due to an invalid GUN (even though the cert ID is correct), and TOFUS is set to false
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"not_a_gun": {rootPubKeyID}}, DisableTOFU: true})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"not_a_gun": {rootPubKeyID}}, DisableTOFU: true})
 	require.Error(t, err)
 
 	// This call to ValidateRoot should fail due to an invalid cert ID, even though it's a valid key ID for targets
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {targetsPubKeyID}}, DisableTOFU: true})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {targetsPubKeyID}}, DisableTOFU: true})
 	require.Error(t, err)
 
 	// This call to ValidateRoot should succeed because we fall through to TOFUS because we have no matching GUNs under Certs
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"not_a_gun": {rootPubKeyID}}, DisableTOFU: false})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"not_a_gun": {rootPubKeyID}}, DisableTOFU: false})
 	require.NoError(t, err)
 }
 
@@ -515,44 +472,35 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
 	defer os.RemoveAll(tempBaseDir)
 	require.NoError(t, err, "failed to create a temporary directory: %s", err)
 
-	// Create a X509Store
-	trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
-	certStore, err := trustmanager.NewX509FilteredFileStore(
-		trustPath,
-		trustmanager.FilterCertsExpiredSha1,
-	)
-	require.NoError(t, err)
-
 	templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
 	templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
 	// Unmarshal our signedRoot
 	json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
 
 	// This call to ValidateRoot will fail because we have an invalid path for the CA
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"docker.com/notary": filepath.Join(tempBaseDir, "nonexistent")}})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"docker.com/notary": filepath.Join(tempBaseDir, "nonexistent")}})
 	require.Error(t, err)
 
 	// This call to ValidateRoot will fail because we have no valid GUNs to use, and TOFUS is disabled
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: true})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: true})
 	require.Error(t, err)
 
 	// This call to ValidateRoot will succeed because we have no valid GUNs to use and we fall back to enabled TOFUS
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: false})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: false})
 	require.NoError(t, err)
-	require.NoError(t, certStore.RemoveAll())
 
 	// Write an invalid CA cert (not even a PEM) to the tempDir and ensure validation fails when using it
 	invalidCAFilepath := filepath.Join(tempBaseDir, "invalid.ca")
 	require.NoError(t, ioutil.WriteFile(invalidCAFilepath, []byte("ABSOLUTELY NOT A PEM"), 0644))
 
 	// Using this invalid CA cert should fail on ValidateRoot
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"docker.com/notary": invalidCAFilepath}, DisableTOFU: true})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"docker.com/notary": invalidCAFilepath}, DisableTOFU: true})
 	require.Error(t, err)
 
 	validCAFilepath := "../fixtures/root-ca.crt"
 
 	// If we pass an invalid Certs entry in addition to this valid CA entry, since Certs has priority for pinning we will fail
-	err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {"invalidID"}}, CA: map[string]string{"docker.com/notary": validCAFilepath}, DisableTOFU: true})
+	err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {"invalidID"}}, CA: map[string]string{"docker.com/notary": validCAFilepath}, DisableTOFU: true})
 	require.Error(t, err)
 
 	// Now construct a new root with a valid cert chain, such that signatures are correct over the 'notary-signer' GUN.  Pin the root-ca and validate
@@ -602,11 +550,10 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
 	require.NoError(t, err)
 
 	// Check that we validate correctly against a pinned CA and provided bundle
-	err = ValidateRoot(certStore, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": validCAFilepath}, DisableTOFU: true})
+	err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": validCAFilepath}, DisableTOFU: true})
 	require.NoError(t, err)
 
 	// Add an expired CA for the same gun to our previous pinned bundle, ensure that we still validate correctly
-	certStore.RemoveAll()
 	goodRootCABundle, err := trustmanager.LoadCertBundleFromFile(validCAFilepath)
 	require.NoError(t, err)
 	memKeyStore := trustmanager.NewKeyMemoryStore(passphraseRetriever)
@@ -623,10 +570,9 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
 	require.NoError(t, ioutil.WriteFile(bundleWithExpiredCertPath, bundleWithExpiredCert, 0644))
 
 	// Check that we validate correctly against a pinned CA and provided bundle
-	err = ValidateRoot(certStore, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithExpiredCertPath}, DisableTOFU: true})
+	err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithExpiredCertPath}, DisableTOFU: true})
 	require.NoError(t, err)
 
-	certStore.RemoveAll()
 	testPubKey2, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
 	require.NoError(t, err)
 	testPrivKey2, _, err := memKeyStore.GetKey(testPubKey2.ID())
@@ -638,11 +584,10 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
 	allExpiredCertPath := filepath.Join(tempBaseDir, "all_expired_cert.pem")
 	require.NoError(t, ioutil.WriteFile(allExpiredCertPath, allExpiredCertBundle, 0644))
 	// Now only use expired certs in the bundle, we should fail
-	err = ValidateRoot(certStore, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": allExpiredCertPath}, DisableTOFU: true})
+	err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": allExpiredCertPath}, DisableTOFU: true})
 	require.Error(t, err)
 
 	// Add a CA cert for a that won't validate against the root leaf certificate
-	certStore.RemoveAll()
 	testPubKey3, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
 	require.NoError(t, err)
 	testPrivKey3, _, err := memKeyStore.GetKey(testPubKey3.ID())
@@ -653,7 +598,7 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
 	require.NoError(t, err)
 	bundleWithWrongCertPath := filepath.Join(tempBaseDir, "bundle_with_expired_cert.pem")
 	require.NoError(t, ioutil.WriteFile(bundleWithWrongCertPath, bundleWithWrongCert, 0644))
-	err = ValidateRoot(certStore, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithWrongCertPath}, DisableTOFU: true})
+	err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithWrongCertPath}, DisableTOFU: true})
 	require.Error(t, err)
 }
 
@@ -666,11 +611,10 @@ func TestValidateSuccessfulRootRotation(t *testing.T) {
 	}
 }
 
-// Generates a X509Store in a temporary directory and returns the
-// store and certificates for two keys which have been added to the keystore.
+// Generates certificates for two keys which have been added to the keystore.
 // Also returns the temporary directory so it can be cleaned up.
-func filestoreWithTwoCerts(t *testing.T, gun, keyAlg string) (
-	string, trustmanager.X509Store, *cryptoservice.CryptoService, []*x509.Certificate) {
+func generateTwoCerts(t *testing.T, gun, keyAlg string) (
+	string, *cryptoservice.CryptoService, []*x509.Certificate) {
 	tempBaseDir, err := ioutil.TempDir("", "notary-test-")
 	require.NoError(t, err, "failed to create a temporary directory: %s", err)
 
@@ -679,14 +623,6 @@ func filestoreWithTwoCerts(t *testing.T, gun, keyAlg string) (
 
 	cryptoService := cryptoservice.NewCryptoService(fileKeyStore)
 
-	// Create a store
-	trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
-	certStore, err := trustmanager.NewX509FilteredFileStore(
-		trustPath,
-		trustmanager.FilterCertsExpiredSha1,
-	)
-	require.NoError(t, err)
-
 	certificates := make([]*x509.Certificate, 2)
 	for i := 0; i < 2; i++ {
 		pubKey, err := cryptoService.Create("root", gun, keyAlg)
@@ -700,21 +636,18 @@ func filestoreWithTwoCerts(t *testing.T, gun, keyAlg string) (
 
 		certificates[i] = cert
 	}
-	return tempBaseDir, certStore, cryptoService, certificates
+	return tempBaseDir, cryptoService, certificates
 }
 
 func testValidateSuccessfulRootRotation(t *testing.T, keyAlg, rootKeyType string) {
 	// The gun to test
 	gun := "docker.com/notary"
 
-	tempBaseDir, certStore, cs, certificates := filestoreWithTwoCerts(t, gun, keyAlg)
+	tempBaseDir, cs, certificates := generateTwoCerts(t, gun, keyAlg)
 	defer os.RemoveAll(tempBaseDir)
 	origRootCert := certificates[0]
 	replRootCert := certificates[1]
 
-	// Add the old root cert part of trustedCertificates
-	certStore.AddCert(origRootCert)
-
 	// We need the PEM representation of the replacement key to put it into the TUF data
 	origRootPEMCert := trustmanager.CertToPEM(origRootCert)
 	replRootPEMCert := trustmanager.CertToPEM(replRootCert)
@@ -745,13 +678,8 @@ func testValidateSuccessfulRootRotation(t *testing.T, keyAlg, rootKeyType string
 
 	// This call to ValidateRoot will succeed since we are using a valid PEM
 	// encoded certificate, and have no other certificates for this CN
-	err = ValidateRoot(certStore, signedTestRoot, gun, TrustPinConfig{})
+	err = ValidateRoot(nil, signedTestRoot, gun, TrustPinConfig{})
 	require.NoError(t, err)
-
-	// Finally, validate the only trusted certificate that exists is the new one
-	certificates = certStore.GetCertificates()
-	require.Len(t, certificates, 1)
-	require.Equal(t, certificates[0], replRootCert)
 }
 
 // TestValidateRootRotationMissingOrigSig runs through a full root certificate rotation
@@ -767,14 +695,42 @@ func TestValidateRootRotationMissingOrigSig(t *testing.T) {
 func testValidateRootRotationMissingOrigSig(t *testing.T, keyAlg, rootKeyType string) {
 	gun := "docker.com/notary"
 
-	tempBaseDir, certStore, cryptoService, certificates := filestoreWithTwoCerts(
+	tempBaseDir, cryptoService, certificates := generateTwoCerts(
 		t, gun, keyAlg)
 	defer os.RemoveAll(tempBaseDir)
 	origRootCert := certificates[0]
 	replRootCert := certificates[1]
 
-	// Add the old root cert part of trustedCertificates
-	certStore.AddCert(origRootCert)
+	// Set up the previous root prior to rotating
+	// We need the PEM representation of the original key to put it into the TUF data
+	origRootPEMCert := trustmanager.CertToPEM(origRootCert)
+
+	// Tuf key with PEM-encoded x509 certificate
+	origRootKey := data.NewPublicKey(rootKeyType, origRootPEMCert)
+
+	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,
+	)
+	require.NoError(t, err, "Failed to create new root")
+
+	signedOrigTestRoot, err := origTestRoot.ToSigned()
+	require.NoError(t, err)
+
+	// We only sign with the new key, and not with the original one.
+	err = signed.Sign(cryptoService, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
+	require.NoError(t, err)
+	prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
+	require.NoError(t, err)
 
 	// We need the PEM representation of the replacement key to put it into the TUF data
 	replRootPEMCert := trustmanager.CertToPEM(replRootCert)
@@ -806,14 +762,8 @@ func testValidateRootRotationMissingOrigSig(t *testing.T, keyAlg, rootKeyType st
 
 	// This call to ValidateRoot will succeed since we are using a valid PEM
 	// encoded certificate, and have no other certificates for this CN
-	err = ValidateRoot(certStore, signedTestRoot, gun, TrustPinConfig{})
+	err = ValidateRoot(prevRoot, signedTestRoot, gun, TrustPinConfig{})
 	require.Error(t, err, "insuficient signatures on root")
-
-	// Finally, validate the only trusted certificate that exists is still
-	// the old one
-	certificates = certStore.GetCertificates()
-	require.Len(t, certificates, 1)
-	require.Equal(t, certificates[0], origRootCert)
 }
 
 // TestValidateRootRotationMissingNewSig runs through a full root certificate rotation
@@ -829,21 +779,47 @@ func TestValidateRootRotationMissingNewSig(t *testing.T) {
 func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType string) {
 	gun := "docker.com/notary"
 
-	tempBaseDir, certStore, cryptoService, certificates := filestoreWithTwoCerts(
+	tempBaseDir, cryptoService, certificates := generateTwoCerts(
 		t, gun, keyAlg)
 	defer os.RemoveAll(tempBaseDir)
 	origRootCert := certificates[0]
 	replRootCert := certificates[1]
 
-	// Add the old root cert part of trustedCertificates
-	certStore.AddCert(origRootCert)
-
 	// We need the PEM representation of the replacement key to put it into the TUF data
-	origRootPEMCert := trustmanager.CertToPEM(origRootCert)
 	replRootPEMCert := trustmanager.CertToPEM(replRootCert)
 
+	// Set up the previous root prior to rotating
+	// We need the PEM representation of the original key to put it into the TUF data
+	origRootPEMCert := trustmanager.CertToPEM(origRootCert)
+
 	// Tuf key with PEM-encoded x509 certificate
 	origRootKey := data.NewPublicKey(rootKeyType, origRootPEMCert)
+
+	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,
+	)
+	require.NoError(t, err, "Failed to create new root")
+
+	signedOrigTestRoot, err := origTestRoot.ToSigned()
+	require.NoError(t, err)
+
+	// We only sign with the new key, and not with the original one.
+	err = signed.Sign(cryptoService, 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 := data.NewPublicKey(rootKeyType, replRootPEMCert)
 
 	rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
@@ -870,14 +846,8 @@ func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType str
 
 	// This call to ValidateRoot will succeed since we are using a valid PEM
 	// encoded certificate, and have no other certificates for this CN
-	err = ValidateRoot(certStore, signedTestRoot, gun, TrustPinConfig{})
+	err = ValidateRoot(prevRoot, signedTestRoot, gun, TrustPinConfig{})
 	require.Error(t, err, "insuficient signatures on root")
-
-	// Finally, validate the only trusted certificate that exists is still
-	// the old one
-	certificates = certStore.GetCertificates()
-	require.Len(t, certificates, 1)
-	require.Equal(t, certificates[0], origRootCert)
 }
 
 func generateTestingCertificate(rootKey data.PrivateKey, gun string) (*x509.Certificate, error) {