"veyron/runtimes/google/security": Add persistence to PublicIDStore

This CL modifies the NewPublicIDStore factory function to create
PublicIDStore that persists all updates to the provided directory.
Additionally it modifies rt.Init() to create a persisting-PublicIDStore
if a directory location is provided via the VEYRON_PUBLICID_STORE env
variable.

Change-Id: I154e1040536fd5fd2be0354e1417013ddb9e741c
diff --git a/runtimes/google/rt/ipc.go b/runtimes/google/rt/ipc.go
index 150bfdf..5784f44 100644
--- a/runtimes/google/rt/ipc.go
+++ b/runtimes/google/rt/ipc.go
@@ -35,7 +35,9 @@
 	return s.id, nil
 }
 
-func (fixedPublicIDStore) SetDefaultPrincipalPattern(pattern security.PrincipalPattern) {}
+func (fixedPublicIDStore) SetDefaultPrincipalPattern(pattern security.PrincipalPattern) error {
+	return errors.New("SetDefaultPrincipalPattern is disallowed on a fixed PublicIDStore")
+}
 
 // localID is an option for passing a PrivateID and PublicIDStore
 // to a server or client.
diff --git a/runtimes/google/rt/ipc_test.go b/runtimes/google/rt/ipc_test.go
index e99e8c9..804e4fc 100644
--- a/runtimes/google/rt/ipc_test.go
+++ b/runtimes/google/rt/ipc_test.go
@@ -146,7 +146,10 @@
 		return fmt.Sprintf("TestCase{clientPublicIDStore: %v, serverPublicIDStore: %v, client option: %v, server option: %v}", clientR.PublicIDStore(), serverR.PublicIDStore(), t.client, t.server)
 	}
 	for _, test := range tests {
-		serverR.PublicIDStore().SetDefaultPrincipalPattern(test.defaultPattern)
+		if err := serverR.PublicIDStore().SetDefaultPrincipalPattern(test.defaultPattern); err != nil {
+			t.Errorf("serverR.PublicIDStore.SetDefaultPrincipalPattern failed: %s", err)
+			continue
+		}
 		server, err := serverR.NewServer(veyron2.LocalID(test.server))
 		if err != nil {
 			t.Errorf("serverR.NewServer(...) failed: %s", err)
diff --git a/runtimes/google/rt/security.go b/runtimes/google/rt/security.go
index 5326b2c..b50be5f 100644
--- a/runtimes/google/rt/security.go
+++ b/runtimes/google/rt/security.go
@@ -27,15 +27,17 @@
 	if err := rt.initIdentity(); err != nil {
 		return err
 	}
-	if rt.store == nil {
-		rt.store = isecurity.NewPublicIDStore()
-		// TODO(ashankar,ataly): What should the tag for the runtime's PublicID in the
-		// runtime's store be? Below we use security.AllPrincipals but this means that
-		// the PublicID *always* gets used for any peer. This may not be desirable.
-		if err := rt.store.Add(rt.id.PublicID(), security.AllPrincipals); err != nil {
-			return fmt.Errorf("could not initialize a PublicIDStore for the runtime: %s", err)
-		}
+	if err := rt.initPublicIDStore(); err != nil {
+		return err
 	}
+	// Initialize the runtime's PublicIDStore with the runtime's PublicID.
+	// TODO(ashankar,ataly): What should be the tag for the PublicID? Below we use
+	// security.AllPrincipals but this means that the PublicID *always* gets used
+	// for any peer. This may not be desirable.
+	if err := rt.store.Add(rt.id.PublicID(), security.AllPrincipals); err != nil {
+		return fmt.Errorf("could not initialize a PublicIDStore for the runtime: %s", err)
+	}
+
 	// Always trust our own identity providers.
 	// TODO(ataly, ashankar): We should trust the identity providers of all PublicIDs in the store.
 	trustIdentityProviders(rt.id)
@@ -61,6 +63,24 @@
 	return nil
 }
 
+func (rt *vrt) initPublicIDStore() error {
+	if rt.store != nil {
+		return nil
+	}
+
+	var backup *isecurity.PublicIDStoreParams
+	// TODO(ataly): Get rid of this environment variable and have a single variable for
+	// all security related initialization.
+	if dir := os.Getenv("VEYRON_PUBLICID_STORE"); len(dir) > 0 {
+		backup = &isecurity.PublicIDStoreParams{dir, rt.id}
+	}
+	var err error
+	if rt.store, err = isecurity.NewPublicIDStore(backup); err != nil {
+		return fmt.Errorf("Could not create PublicIDStore for runtime: %v", err)
+	}
+	return nil
+}
+
 func defaultIdentityName() string {
 	var name string
 	if user, _ := user.Current(); user != nil && len(user.Username) > 0 {
diff --git a/runtimes/google/security/identity_chain.go b/runtimes/google/security/identity_chain.go
index 87f55ac..7351b41 100644
--- a/runtimes/google/security/identity_chain.go
+++ b/runtimes/google/security/identity_chain.go
@@ -13,6 +13,7 @@
 
 	"veyron/runtimes/google/security/keys"
 	"veyron/security/caveat"
+	"veyron/security/signing"
 
 	"veyron2/security"
 	"veyron2/security/wire"
@@ -146,7 +147,7 @@
 		PublicKey: *id.publicID.publicKey,
 		D:         new(big.Int).SetBytes(w.Secret),
 	}
-	id.Signer = NewClearSigner(id.privateKey)
+	id.Signer = signing.NewClearSigner(id.privateKey)
 	return nil
 }
 
@@ -234,7 +235,7 @@
 		if err != nil {
 			return nil, err
 		}
-		signer = NewClearSigner(privKey)
+		signer = signing.NewClearSigner(privKey)
 	}
 
 	id := &chainPrivateID{
diff --git a/runtimes/google/security/publicid_store.go b/runtimes/google/security/publicid_store.go
index 70dcd7d..4ce543c 100644
--- a/runtimes/google/security/publicid_store.go
+++ b/runtimes/google/security/publicid_store.go
@@ -1,14 +1,24 @@
 package security
 
 import (
-	"bytes"
 	"crypto/ecdsa"
 	"errors"
 	"fmt"
+	"os"
+	"path"
 	"reflect"
 	"sync"
 
+	"veyron/security/serialization"
+
 	"veyron2/security"
+	"veyron2/security/wire"
+	"veyron2/vom"
+)
+
+const (
+	dataFile      = "blessingstore.data"
+	signatureFile = "blessingstore.sig"
 )
 
 var (
@@ -20,44 +30,86 @@
 	return fmt.Errorf("could not combine matching PublicIDs: %s", err)
 }
 
+func saveErr(err error) error {
+	return fmt.Errorf("could not save PublicIDStore: %s", err)
+}
+
 type taggedIDStore map[security.PublicID][]security.PrincipalPattern
 
+type persistentState struct {
+	// Store contains a set of PublicIDs mapped to a set of (peer) patterns. The
+	// patterns indicate the set of peers against whom the PublicID can be used.
+	// All PublicIDs in the store must have the same public key.
+	Store taggedIDStore
+	// DefaultPattern is the default PrincipalPattern to be used to select
+	// PublicIDs from the store in absence of any other search criterea.
+	DefaultPattern security.PrincipalPattern
+}
+
 // publicIDStore implements security.PublicIDStore.
 type publicIDStore struct {
-	// store contains a set of PublicIDs mapped to a set of (peer) patterns. The patterns
-	// indicate the set of peers against whom the PublicID can be used. All PublicIDs in
-	// the store must have the same public key.
-	store taggedIDStore
-	// publicKey is the common public key of all PublicIDs held in the store.
+	state     persistentState
 	publicKey *ecdsa.PublicKey
-	// defaultPattern is the default PrincipalPattern to be used to select
-	// PublicIDs from the store in absence of any other search criterea.
-	defaultPattern security.PrincipalPattern
-	mu             sync.RWMutex
+	params    *PublicIDStoreParams
+	mu        sync.RWMutex
 }
 
-func (s *publicIDStore) addTaggedID(id security.PublicID, peerPattern security.PrincipalPattern) {
+func (s *publicIDStore) addTaggedID(id security.PublicID, peerPattern security.PrincipalPattern) ([]security.PublicID, error) {
+	var updatedIDs []security.PublicID
 	switch p := id.(type) {
 	case *setPublicID:
 		for _, ip := range *p {
-			s.addTaggedID(ip, peerPattern)
+			ids, err := s.addTaggedID(ip, peerPattern)
+			if err != nil {
+				return updatedIDs, err
+			}
+			updatedIDs = append(updatedIDs, ids...)
 		}
+	case *chainPublicID:
+		for _, pattern := range s.state.Store[id] {
+			if pattern == peerPattern {
+				return updatedIDs, nil
+			}
+		}
+		s.state.Store[id] = append(s.state.Store[id], peerPattern)
+		updatedIDs = append(updatedIDs, id)
 	default:
-		// TODO(ataly): Should we restrict this case to just PublicIDs of type *chainPublicID?
-		s.store[id] = append(s.store[id], peerPattern)
+		return updatedIDs, fmt.Errorf("PublicID of type %T cannot be added to the store", id)
+	}
+	return updatedIDs, nil
+}
+
+func (s *publicIDStore) revert(updatedIDs []security.PublicID) {
+	for _, id := range updatedIDs {
+		s.state.Store[id] = s.state.Store[id][:len(s.state.Store[id])-1]
 	}
 }
 
 func (s *publicIDStore) Add(id security.PublicID, peerPattern security.PrincipalPattern) error {
 	s.mu.Lock()
 	defer s.mu.Unlock()
-	if s.publicKey != nil && !reflect.DeepEqual(id.PublicKey(), s.publicKey) {
+
+	publicKeyIsNil := s.publicKey == nil
+	if !publicKeyIsNil && !reflect.DeepEqual(id.PublicKey(), s.publicKey) {
 		return errStoreAddMismatch
 	}
-	if s.publicKey == nil {
+	if publicKeyIsNil {
 		s.publicKey = id.PublicKey()
 	}
-	s.addTaggedID(id, peerPattern)
+
+	updatedIDs, err := s.addTaggedID(id, peerPattern)
+	if err != nil {
+		s.revert(updatedIDs)
+		return err
+	}
+
+	if err := s.save(); err != nil {
+		s.revert(updatedIDs)
+		if publicKeyIsNil {
+			s.publicKey = nil
+		}
+		return saveErr(err)
+	}
 	return nil
 }
 
@@ -65,7 +117,7 @@
 	s.mu.RLock()
 	defer s.mu.RUnlock()
 	var matchingIDs []security.PublicID
-	for id, peerPatterns := range s.store {
+	for id, peerPatterns := range s.state.Store {
 		for _, peerPattern := range peerPatterns {
 			if peer.Match(peerPattern) {
 				matchingIDs = append(matchingIDs, id)
@@ -87,8 +139,8 @@
 	s.mu.RLock()
 	defer s.mu.RUnlock()
 	var matchingIDs []security.PublicID
-	for id, _ := range s.store {
-		if id.Match(s.defaultPattern) {
+	for id, _ := range s.state.Store {
+		if id.Match(s.state.DefaultPattern) {
 			matchingIDs = append(matchingIDs, id)
 		}
 	}
@@ -102,31 +154,126 @@
 	return id, nil
 }
 
-func (s *publicIDStore) SetDefaultPrincipalPattern(pattern security.PrincipalPattern) {
+func (s *publicIDStore) SetDefaultPrincipalPattern(pattern security.PrincipalPattern) error {
+	if err := wire.ValidatePrincipalPattern(pattern); err != nil {
+		return err
+	}
 	s.mu.Lock()
 	defer s.mu.Unlock()
-	// TODO(ataly, ashankar): Should we check that the pattern is well-formed?
-	s.defaultPattern = pattern
+
+	oldPattern := s.state.DefaultPattern
+	s.state.DefaultPattern = pattern
+
+	if err := s.save(); err != nil {
+		s.state.DefaultPattern = oldPattern
+		return saveErr(err)
+	}
+	return nil
+}
+
+func (s *publicIDStore) save() error {
+	if s.params == nil {
+		return nil
+	}
+
+	// Save the state to temporary data and signature files, and then move
+	// those files to the actually data and signature file. This reduces the
+	// risk of loosing all saved data on disk in the event of a Write failure.
+	dataPath := path.Join(s.params.Dir, dataFile)
+	tempDataPath := dataPath + "_tmp"
+	sigPath := path.Join(s.params.Dir, signatureFile)
+	tempSigPath := sigPath + "_tmp"
+
+	data, err := os.OpenFile(tempDataPath, os.O_WRONLY|os.O_CREATE, 0600)
+	if err != nil {
+		return err
+	}
+	defer os.Remove(tempDataPath)
+	sig, err := os.OpenFile(tempSigPath, os.O_WRONLY|os.O_CREATE, 0600)
+	if err != nil {
+		return err
+	}
+	defer os.Remove(tempSigPath)
+
+	swc, err := serialization.NewSigningWriteCloser(data, sig, s.params.Signer, nil)
+	if err != nil {
+		return err
+	}
+	if err := vom.NewEncoder(swc).Encode(s.state); err != nil {
+		defer swc.Close()
+		return err
+	}
+	if err := swc.Close(); err != nil {
+		return err
+	}
+
+	if err := os.Rename(tempDataPath, dataPath); err != nil {
+		return err
+	}
+	return os.Rename(tempSigPath, sigPath)
 }
 
 func (s *publicIDStore) String() string {
-	var buf bytes.Buffer
-	buf.WriteString("&publicIDStore{\n")
-	buf.WriteString("  store: {\n")
-	for id, peerPatterns := range s.store {
-		buf.WriteString(fmt.Sprintf("    %s: %s,\n", id, peerPatterns))
-	}
-	buf.WriteString(fmt.Sprintf("  },\n"))
-	buf.WriteString(fmt.Sprintf("  defaultPattern: %s,\n", s.defaultPattern))
-	buf.WriteString("}")
-	return buf.String()
+	return fmt.Sprintf("{state: %v, params: %v}", s.state, s.params)
 }
 
-// NewPublicIDStore returns a new security.PublicIDStore with an empty
-// set of PublicIDs, and the default pattern "*" matched by all PublicIDs.
-func NewPublicIDStore() security.PublicIDStore {
-	return &publicIDStore{
-		store:          make(taggedIDStore),
-		defaultPattern: security.AllPrincipals,
+// PublicIDStoreParams specifies persistent storage where a PublicIDStore can be
+// saved and loaded.
+type PublicIDStoreParams struct {
+	// Dir specifies a path to a directory in which a serialized PublicIDStore
+	// can be saved and loaded.
+	Dir string
+	// Signer provides a mechanism to sign and verify the serialized bytes.
+	Signer security.Signer
+}
+
+// NewPublicIDStore returns a security.PublicIDStore based on params.
+// * If params is nil, a new store with an empty set of PublicIDs and the default
+//   pattern "*" (matched by all PublicIDs) is returned. The store only lives in
+//   memory and is never persisted.
+// * If params is non-nil, then a store obtained from the serialized data present
+//   in params.Dir is returned if the data exists, or else a new store with an
+//   empty set of PublicIDs and the default pattern "*" is returned. Any subsequent
+//   modifications to the returned store are always signed (using params.Signer)
+//   and persisted in params.Dir.
+func NewPublicIDStore(params *PublicIDStoreParams) (security.PublicIDStore, error) {
+	store := &publicIDStore{
+		state:  persistentState{make(taggedIDStore), security.AllPrincipals},
+		params: params,
 	}
+	if store.params == nil {
+		return store, nil
+	}
+
+	data, dataErr := os.Open(path.Join(store.params.Dir, dataFile))
+	defer data.Close()
+	sig, sigErr := os.Open(path.Join(store.params.Dir, signatureFile))
+	defer sig.Close()
+
+	switch {
+	case os.IsNotExist(dataErr) && os.IsNotExist(sigErr):
+		// No params exists, returning an empty PublicIDStore.
+		return store, nil
+	case dataErr != nil:
+		return nil, dataErr
+	case sigErr != nil:
+		return nil, sigErr
+	}
+
+	vr, err := serialization.NewVerifyingReader(data, sig, store.params.Signer.PublicKey())
+	if err != nil {
+		return nil, err
+	}
+	if vr == nil {
+		return nil, errors.New("could not construct VerifyingReader for reading params data")
+	}
+	if err := vom.NewDecoder(vr).Decode(&store.state); err != nil {
+		return nil, err
+	}
+
+	for id, _ := range store.state.Store {
+		store.publicKey = id.PublicKey()
+		break
+	}
+	return store, nil
 }
diff --git a/runtimes/google/security/publicid_store_test.go b/runtimes/google/security/publicid_store_test.go
index 14b2f4c..0c01787 100644
--- a/runtimes/google/security/publicid_store_test.go
+++ b/runtimes/google/security/publicid_store_test.go
@@ -2,6 +2,8 @@
 
 import (
 	"crypto/ecdsa"
+	"io/ioutil"
+	"os"
 	"reflect"
 	"testing"
 
@@ -33,29 +35,68 @@
 		cBob         = newChain("bob")
 		cVeyronAlice = derive(bless(cAlice.PublicID(), veyronChain, "alice", nil), cAlice)
 
-		sAlice = newSetPublicID(cAlice.PublicID(), cVeyronAlice.PublicID())
+		sAlice    = newSetPublicID(cAlice.PublicID(), cVeyronAlice.PublicID())
+		fakeID    = security.FakePublicID("alice")
+		fakeSetID = newSetPublicID(security.FakePublicID("bob"), fakeID)
 	)
-	s := NewPublicIDStore()
+	s, err := NewPublicIDStore(nil)
+	if err != nil {
+		t.Fatalf("NewPublicIDStore failed: %s", err)
+	}
 	// First Add should succeed for any PublicID (cAlice.PublicID() below)
 	if err := s.Add(cAlice.PublicID(), "alice/*"); err != nil {
-		t.Fatalf("%q.Add(%q, ...) failed unexpectedly: %s", s, cAlice, err)
+		t.Fatalf("%s.Add(%q, ...) failed unexpectedly: %s", s, cAlice.PublicID(), err)
 	}
 	// Subsequent Adds must succeed only for PublicIDs with cAlice's public key.
 	if err := s.Add(cVeyronAlice.PublicID(), "*"); err != nil {
-		t.Fatalf("%q.Add(%q, ...) failed unexpectedly: %s", s, cVeyronAlice, err)
+		t.Fatalf("%s.Add(%q, ...) failed unexpectedly: %s", s, cVeyronAlice.PublicID(), err)
 	}
 	if err := s.Add(sAlice, "alice/*"); err != nil {
-		t.Fatalf("%q.Add(%q, ...) failed unexpectedly: %s", s, sAlice, err)
+		t.Fatalf("%s.Add(%q, ...) failed unexpectedly: %s", s, sAlice, err)
 	}
 	if got, want := s.Add(cBob.PublicID(), "bob/*"), errStoreAddMismatch; got != want {
-		t.Fatalf("%q.Add(%q, ...): got: %s, want: %s", s, cBob, got, want)
+		t.Fatalf("%s.Add(%q, ...): got: %s, want: %s", s, cBob, got, want)
+	}
+	// Adding non-chain PublicIDs or sets containing non-chain PublicIDs should fail.
+	if err := s.Add(fakeID, "*"); err == nil {
+		t.Fatalf("Unexpectedly added PublicID of type %T to the store", fakeID)
+	}
+	if err := s.Add(fakeSetID, "*"); err == nil {
+		t.Fatalf("Unexpectedly added PublicID of type %T to the store", fakeSetID)
+	}
+}
+
+func TestSetDefaultPattern(t *testing.T) {
+	s, err := NewPublicIDStore(nil)
+	if err != nil {
+		t.Fatalf("NewPublicIDStore failed: %s", err)
+	}
+	defaultPatterns := []struct {
+		pattern security.PrincipalPattern
+		success bool
+	}{
+		{"veyron", true},
+		{"veyron/alice@google", true},
+		{"veyron/alice@google/bob", true},
+		{"veyron/alice@google/*", true},
+		{"", false},
+		{"veyron*", false},
+		{"*veyron", false},
+		{"/veyron", false},
+		{"veyron/", false},
+		{"veyron/*/alice", false},
+	}
+	for _, d := range defaultPatterns {
+		if got := s.SetDefaultPrincipalPattern(d.pattern); d.success != (got == nil) {
+			t.Errorf("%s.SetDefaultPattern(%q) returned: %v, expected it to succeed: %v", s, d.pattern, got, d.success)
+		}
 	}
 }
 
 func TestStoreGetters(t *testing.T) {
 	add := func(s security.PublicIDStore, id security.PublicID, peers security.PrincipalPattern) {
 		if err := s.Add(id, peers); err != nil {
-			t.Fatalf("Add(%q, %q) failed unexpectedly: %s", id, peers, err)
+			t.Fatalf("%s.Add(%q, %q) failed unexpectedly: %s", s, id, peers, err)
 		}
 	}
 	var (
@@ -80,7 +121,10 @@
 	)
 
 	// Create a new PublicIDStore and add Add Alice's PublicIDs to the store.
-	s := NewPublicIDStore()
+	s, err := NewPublicIDStore(nil)
+	if err != nil {
+		t.Fatalf("NewPublicIDStore failed: %s", err)
+	}
 	add(s, cGoogleAlice, "google")                  // use cGoogleAlice against all peers matching "google/*"
 	add(s, cGoogleAlice, "veyron")                  // use cGoogleAlice against all peers matching "veyron/*" as well
 	add(s, cVeyronAlice, "veyron/*")                // use cVeyronAlice against peers matching "veyron/*"
@@ -93,7 +137,7 @@
 	pkey := cAlice.PublicID().PublicKey()
 
 	// Test ForPeer.
-	testDataByPeer := []struct {
+	testDataForPeer := []struct {
 		peer  security.PublicID
 		names []string
 	}{
@@ -104,7 +148,7 @@
 		{cGoogleServiceApp.PublicID(), []string{"google/service/user-42"}},
 		{cBob.PublicID(), nil},
 	}
-	for _, d := range testDataByPeer {
+	for _, d := range testDataForPeer {
 		if got, err := s.ForPeer(d.peer); !verifyNamesAndPublicKey(got, err, d.names, pkey) {
 			t.Errorf("%s.ForPeer(%s): got: %q, want PublicID with the exact set of names %q", s, d.peer, got, d.names)
 		}
@@ -139,3 +183,72 @@
 		}
 	}
 }
+
+func TestPublicIDStorePersistence(t *testing.T) {
+	newTempDir := func(name string) string {
+		dir, err := ioutil.TempDir("", name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		return dir
+	}
+
+	var (
+		signer = newChain("signer")
+
+		cAlice       = newChain("alice")
+		cBob         = newChain("bob")
+		cVeyronAlice = bless(cAlice.PublicID(), veyronChain, "alice", nil)
+		cGoogleAlice = bless(cAlice.PublicID(), googleChain, "alice", nil)
+		sAllAlice    = newSetPublicID(cGoogleAlice, cVeyronAlice)
+
+		pkey = cAlice.PublicID().PublicKey()
+	)
+
+	// Create a new PublicIDStore that saves all mutations to the provided directory.
+	dir := newTempDir("publicid_store")
+	defer os.RemoveAll(dir)
+
+	s, err := NewPublicIDStore(&PublicIDStoreParams{dir, signer})
+	if err != nil {
+		t.Fatalf("NewPublicIDStore failed: %s", err)
+	}
+	if err := s.Add(sAllAlice, "google/*"); err != nil {
+		t.Fatalf("%s.Add(%q, ...) failed unexpectedly: %s", s, sAllAlice, err)
+	}
+	if err := s.SetDefaultPrincipalPattern("veyron/*"); err != nil {
+		t.Fatalf("%s.SetDefaultPrincipalPattern failed: %s", s, err)
+	}
+
+	// Test that all mutations are appropriately reflected in a PublicIDStore read from
+	// the directory.
+	s, err = NewPublicIDStore(&PublicIDStoreParams{dir, signer})
+	if err != nil {
+		t.Fatalf("NewPublicIDStore failed: %s", err)
+	}
+
+	testDataForPeer := []struct {
+		peer  security.PublicID
+		names []string
+	}{
+		{googleChain.PublicID(), []string{"veyron/alice", "google/alice"}},
+		{veyronChain.PublicID(), nil},
+		{cBob.PublicID(), nil},
+	}
+	for _, d := range testDataForPeer {
+		if got, err := s.ForPeer(d.peer); !verifyNamesAndPublicKey(got, err, d.names, pkey) {
+			t.Errorf("%s.ForPeer(%s): got: %q, want PublicID with the exact set of names %q", s, d.peer, got, d.names)
+		}
+	}
+
+	wantDefaultNames := []string{"veyron/alice"}
+	if got, err := s.DefaultPublicID(); !verifyNamesAndPublicKey(got, err, wantDefaultNames, pkey) {
+		t.Errorf("%s.DefaultPublicID(): got: %s, want PublicID with the exact set of names: %s", s, got, wantDefaultNames)
+	}
+
+	diffPubKeyID := newChain("immaterial").PublicID()
+	if got, want := s.Add(diffPubKeyID, security.AllPrincipals), errStoreAddMismatch; got != want {
+		t.Fatalf("%s.Add(%q, ...): got: %v, want: %v", s, diffPubKeyID, got, want)
+	}
+
+}
diff --git a/security/serialization/serialization_test.go b/security/serialization/serialization_test.go
index 524e6f3..7cc7a8b 100644
--- a/security/serialization/serialization_test.go
+++ b/security/serialization/serialization_test.go
@@ -3,6 +3,8 @@
 import (
 	"bytes"
 	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -12,8 +14,8 @@
 	"testing"
 
 	"veyron/lib/testutil"
+	"veyron/security/signing"
 
-	"veyron2/rt"
 	"veyron2/security"
 )
 
@@ -50,17 +52,11 @@
 }
 
 func newSigner() security.Signer {
-	// TODO(ashankar,ataly): Remove use of "rt" here and replace with a factory
-	// function for PrivateID/Signer when possible.
-	r, err := rt.New()
+	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
 	if err != nil {
 		panic(err)
 	}
-	id, err := r.NewIdentity("irrelevant")
-	if err != nil {
-		panic(err)
-	}
-	return id
+	return signing.NewClearSigner(key)
 }
 
 func matchesErrorPattern(err error, pattern string) bool {
diff --git a/runtimes/google/security/signer.go b/security/signing/signer.go
similarity index 97%
rename from runtimes/google/security/signer.go
rename to security/signing/signer.go
index 91e87f1..d96f471 100644
--- a/runtimes/google/security/signer.go
+++ b/security/signing/signer.go
@@ -1,4 +1,4 @@
-package security
+package signing
 
 import (
 	"crypto/ecdsa"
diff --git a/runtimes/google/security/signer_test.go b/security/signing/signer_test.go
similarity index 97%
rename from runtimes/google/security/signer_test.go
rename to security/signing/signer_test.go
index cd81097..835e065 100644
--- a/runtimes/google/security/signer_test.go
+++ b/security/signing/signer_test.go
@@ -1,4 +1,4 @@
-package security
+package signing
 
 import (
 	"crypto/ecdsa"