veyron2/security, veyron/security: Refactor veyron2/security/util.go.

Specifics:
 - Move Label and LabelSet methods to veyron2/security/label.go
 - Move PrincipalPattern methods to veyron2/security/pattern.go
 - Move ACL methods to veyron2/security/acl.go
 - Make Matches(PublicID, PrincipalPattern) a method on PrincipalPattern,
   and add a test.
 - Rename acl.Matches to acl.CanAccess
 - Move load/save utilities into veyron/security

Change-Id: I742c5856cc4a2a1e23c26c0304c38dd2e4757930
diff --git a/examples/bank/bank/main.go b/examples/bank/bank/main.go
index 1145486..efbcce9 100644
--- a/examples/bank/bank/main.go
+++ b/examples/bank/bank/main.go
@@ -11,6 +11,7 @@
 	"strings"
 
 	"veyron/examples/bank"
+	vsecurity "veyron/security"
 	idutil "veyron/services/identity/util"
 
 	"veyron2"
@@ -85,7 +86,7 @@
 		if err != nil {
 			log.Fatalf("failed to open identity file for writing: %s\n", err)
 		}
-		err = security.SaveIdentity(f, derivedIdentity)
+		err = vsecurity.SaveIdentity(f, derivedIdentity)
 		if err != nil {
 			log.Fatalf("failed to save identity: %s\n", err)
 		}
diff --git a/examples/boxes/android/src/boxesp2p/main.go b/examples/boxes/android/src/boxesp2p/main.go
index 674fc4c..34c2ccd 100644
--- a/examples/boxes/android/src/boxesp2p/main.go
+++ b/examples/boxes/android/src/boxesp2p/main.go
@@ -233,7 +233,7 @@
 }
 
 func (gs *goState) registerAsPeer() {
-	auth := vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
+	auth := vsecurity.NewACLAuthorizer(vsecurity.NewWhitelistACL(
 		map[security.PrincipalPattern]security.LabelSet{
 			security.AllPrincipals: security.LabelSet(security.AdminLabel),
 		}))
@@ -335,7 +335,7 @@
 	}
 
 	// Create ACL Authorizer with read/write permissions for the identity
-	acl, err := security.LoadACL(bytes.NewBufferString("{\"" + publicID.Names()[0] + "\":\"RW\"}"))
+	acl, err := vsecurity.LoadACL(bytes.NewBufferString("{\"" + publicID.Names()[0] + "\":\"RW\"}"))
 	if err != nil {
 		panic(fmt.Errorf("LoadACL failed:%v", err))
 	}
@@ -392,7 +392,7 @@
 	myIdentity := "_4EEGgFCAP-DNBoBQwEudmV5cm9uL3J1bnRpbWVzL2dvb2dsZS9zZWN1cml0eS5jaGFpblByaXZhdGVJRAD_hVEYAQIBRAEIUHVibGljSUQAAQQBBlNlY3JldAABM3ZleXJvbi9ydW50aW1lcy9nb29nbGUvc2VjdXJpdHkvd2lyZS5DaGFpblByaXZhdGVJRAD_hwQaAUUA_4lJGAEBAUYBDENlcnRpZmljYXRlcwABMnZleXJvbi9ydW50aW1lcy9nb29nbGUvc2VjdXJpdHkvd2lyZS5DaGFpblB1YmxpY0lEAP-LBBIBRwD_jWcYAQQBAwEETmFtZQABSAEJUHVibGljS2V5AAFJAQdDYXZlYXRzAAFKAQlTaWduYXR1cmUAATB2ZXlyb24vcnVudGltZXMvZ29vZ2xlL3NlY3VyaXR5L3dpcmUuQ2VydGlmaWNhdGUA_49FGAECAUsBBUN1cnZlAAEEAQJYWQABLnZleXJvbi9ydW50aW1lcy9nb29nbGUvc2VjdXJpdHkvd2lyZS5QdWJsaWNLZXkA_5UzEAEyAS12ZXlyb24vcnVudGltZXMvZ29vZ2xlL3NlY3VyaXR5L3dpcmUua2V5Q3VydmUA_5EEEgFMAP-XRxgBAgFNAQdTZXJ2aWNlAAEEAQVCeXRlcwABK3ZleXJvbi9ydW50aW1lcy9nb29nbGUvc2VjdXJpdHkvd2lyZS5DYXZlYXQA_5knEAEDASF2ZXlyb24yL3NlY3VyaXR5LlByaW5jaXBhbFBhdHRlcm4A_5NAGAECAQQBAVIAAQQBAVMAAS52ZXlyb24vcnVudGltZXMvZ29vZ2xlL3NlY3VyaXR5L3dpcmUuU2lnbmF0dXJlAP-C_8ABAwEFAQEBCGdhdXRoYW10AQJBBL1M858IVO3sxJTYFxv1EiDVLFG6WdH-l4OpOHQXlZn5MO8LXNdnRhJ_r_Zwe92VHpbemsPNek_SJOfsSmsVRA8AAgEgm5eZNI1lUqwPCqlQOgesp-7zx0zLxvJe9IcwRbnMycoBINYA7GSPqFxDkbWYScL3Kj0k4AZK-e9sF01a7RAjcGMRAAAAASBldL9q-34I_W5yrapTmqaItm66RGNGtiUrFTlfh8VaNwA="
 
 	// Load identity that has been generated.
-	privateID, err := security.LoadIdentity(strings.NewReader(myIdentity))
+	privateID, err := vsecurity.LoadIdentity(strings.NewReader(myIdentity))
 	if err != nil {
 		panic(fmt.Errorf("Failed to load identity:%v\n", err))
 	}
diff --git a/lib/testutil/security/util.go b/lib/testutil/security/util.go
index ddd65e5..5e8e5d4 100644
--- a/lib/testutil/security/util.go
+++ b/lib/testutil/security/util.go
@@ -10,6 +10,7 @@
 
 	"veyron/lib/testutil"
 	isecurity "veyron/runtimes/google/security"
+	vsecurity "veyron/security"
 
 	"veyron2/security"
 )
@@ -44,7 +45,7 @@
 		panic(err)
 	}
 	defer f.Close()
-	if err := security.SaveACL(f, acl); err != nil {
+	if err := vsecurity.SaveACL(f, acl); err != nil {
 		defer os.Remove(f.Name())
 		panic(err)
 	}
@@ -64,7 +65,7 @@
 	defer f.Close()
 	filePath := f.Name()
 
-	if err := security.SaveIdentity(f, id); err != nil {
+	if err := vsecurity.SaveIdentity(f, id); err != nil {
 		os.Remove(filePath)
 		panic(err)
 	}
diff --git a/lib/testutil/security/util_test.go b/lib/testutil/security/util_test.go
index 3f2a38e..856606b 100644
--- a/lib/testutil/security/util_test.go
+++ b/lib/testutil/security/util_test.go
@@ -7,6 +7,7 @@
 	"testing"
 
 	isecurity "veyron/runtimes/google/security"
+	vsecurity "veyron/security"
 
 	"veyron2/rt"
 	"veyron2/security"
@@ -67,7 +68,7 @@
 		t.Fatalf("os.Open(%v) failed: %v", filePath, err)
 	}
 	defer f.Close()
-	loadedACL, err := security.LoadACL(f)
+	loadedACL, err := vsecurity.LoadACL(f)
 	if err != nil {
 		t.Fatalf("LoadACL failed: %v", err)
 	}
@@ -95,7 +96,7 @@
 		t.Fatalf("os.Open(%v) failed: %v", filePath, err)
 	}
 	defer f.Close()
-	loadedID, err := security.LoadIdentity(f)
+	loadedID, err := vsecurity.LoadIdentity(f)
 	if err != nil {
 		t.Fatalf("LoadIdentity failed: %v", err)
 	}
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 2b982c4..a33a242 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -197,7 +197,7 @@
 	for _, o := range opts {
 		switch v := o.(type) {
 		case veyron2.RemoteID:
-			if !security.Matches(authID, security.PrincipalPattern(v)) {
+			if !security.PrincipalPattern(v).MatchedBy(authID) {
 				return nil, fmt.Errorf("server %q does not match the provided pattern %q", authID, v)
 			}
 		case ipc.Granter:
diff --git a/runtimes/google/ipc/discharges.go b/runtimes/google/ipc/discharges.go
index e8504cb..5e72ea8 100644
--- a/runtimes/google/ipc/discharges.go
+++ b/runtimes/google/ipc/discharges.go
@@ -24,7 +24,7 @@
 
 	var caveats []security.ThirdPartyCaveat
 	for _, cav := range blessing.ThirdPartyCaveats() {
-		if security.Matches(server, cav.Service) {
+		if cav.Service.MatchedBy(server) {
 			caveats = append(caveats, cav.Caveat.(security.ThirdPartyCaveat))
 		}
 	}
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index d62f1cc..5b0af71 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -129,14 +129,14 @@
 
 type dischargeServer struct{}
 
-func (*dischargeServer) Discharge(ctx ipc.ServerCall, caveat vdlutil.Any, _ security.DischargeImpetus) (vdlutil.Any, error) {
-	c, ok := caveat.(security.ThirdPartyCaveat)
+func (*dischargeServer) Discharge(ctx ipc.ServerCall, cav vdlutil.Any, _ security.DischargeImpetus) (vdlutil.Any, error) {
+	c, ok := cav.(security.ThirdPartyCaveat)
 	if !ok {
-		return nil, fmt.Errorf("discharger: unknown caveat(%T)", caveat)
+		return nil, fmt.Errorf("discharger: unknown caveat(%T)", cav)
 	}
 	// Add a fakeTimeCaveat to allow the discharge to expire
 	expiry := fakeTimeCaveat(clock.Now())
-	return serverID.MintDischarge(c, ctx, time.Hour, []security.ServiceCaveat{security.UniversalCaveat(expiry)})
+	return serverID.MintDischarge(c, ctx, time.Hour, []security.ServiceCaveat{caveat.UniversalCaveat(expiry)})
 }
 
 type testServerAuthorizer struct{}
@@ -161,7 +161,7 @@
 		authorizer = nil
 	case "aclAuth":
 		// Only authorize clients matching patterns "client" or "server/*".
-		authorizer = vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
+		authorizer = vsecurity.NewACLAuthorizer(vsecurity.NewWhitelistACL(
 			map[security.PrincipalPattern]security.LabelSet{
 				"server/*": security.LabelSet(security.AdminLabel),
 				"client":   security.LabelSet(security.AdminLabel),
@@ -381,7 +381,7 @@
 // ignores the first if it is invalid.
 func deriveForThirdPartyCaveats(blessor security.PrivateID, name string, caveats ...security.ServiceCaveat) security.PrivateID {
 	id := derive(blessor, name, caveats...)
-	dischargeID, err := id.Derive(bless(blessor, id.PublicID(), name, security.UniversalCaveat(caveat.MethodRestriction{"Discharge"})))
+	dischargeID, err := id.Derive(bless(blessor, id.PublicID(), name, caveat.UniversalCaveat(caveat.MethodRestriction{"Discharge"})))
 	if err != nil {
 		panic(err)
 	}
@@ -453,7 +453,7 @@
 	)
 	var (
 		now        = time.Now()
-		cavOnlyV1  = security.UniversalCaveat(caveat.PeerIdentity{"client/v1"})
+		cavOnlyV1  = caveat.UniversalCaveat(caveat.PeerIdentity{"client/v1"})
 		cavExpired = security.ServiceCaveat{
 			Service: security.AllPrincipals,
 			Caveat:  &caveat.Expiry{IssueTime: now, ExpiryTime: now},
@@ -669,7 +669,7 @@
 			if err != nil {
 				t.Fatalf("Failed to create ThirdPartyCaveat: %v", err)
 			}
-			caveat := security.UniversalCaveat(tpc)
+			caveat := caveat.UniversalCaveat(tpc)
 			return deriveForThirdPartyCaveats(serverID, "client", caveat)
 		}
 	)
@@ -841,8 +841,8 @@
 func TestDischargePurgeFromCache(t *testing.T) {
 	var (
 		dischargerID = serverID.PublicID()
-		caveat       = mkThirdPartyCaveat(dischargerID, "mountpoint/server/discharger", alwaysValidCaveat{})
-		clientCID    = deriveForThirdPartyCaveats(serverID, "client", security.UniversalCaveat(caveat))
+		c            = mkThirdPartyCaveat(dischargerID, "mountpoint/server/discharger", alwaysValidCaveat{})
+		clientCID    = deriveForThirdPartyCaveats(serverID, "client", caveat.UniversalCaveat(c))
 	)
 	b := createBundle(t, clientCID, serverID, &testServer{})
 	defer b.cleanup(t)
@@ -1275,7 +1275,7 @@
 	if err != nil {
 		vlog.Fatalf("failed to open %v: %v", file, err)
 	}
-	id, err := security.LoadIdentity(f)
+	id, err := vsecurity.LoadIdentity(f)
 	f.Close()
 	if err != nil {
 		vlog.Fatalf("Failed to load identity from %v: %v", file, err)
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index b8642b5..470fd1f 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -386,7 +386,7 @@
 	for _, n := range id.Names() {
 		in[security.PrincipalPattern(n+security.ChainSeparator+security.AllPrincipals)] = security.AllLabels
 	}
-	return security.NewWhitelistACL(in)
+	return vsecurity.NewWhitelistACL(in)
 }
 
 func (fs *flowServer) serve() error {
diff --git a/runtimes/google/rt/ipc_test.go b/runtimes/google/rt/ipc_test.go
index f7e1e52..d9938d8 100644
--- a/runtimes/google/rt/ipc_test.go
+++ b/runtimes/google/rt/ipc_test.go
@@ -162,7 +162,7 @@
 		}
 		defer stopServer(server)
 		if err := server.Serve("", ipc.LeafDispatcher(&testService{},
-			vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
+			vsecurity.NewACLAuthorizer(vsecurity.NewWhitelistACL(
 				map[security.PrincipalPattern]security.LabelSet{
 					security.AllPrincipals: security.AllLabels,
 				})))); err != nil {
diff --git a/runtimes/google/rt/security.go b/runtimes/google/rt/security.go
index b50be5f..a69b33c 100644
--- a/runtimes/google/rt/security.go
+++ b/runtimes/google/rt/security.go
@@ -6,6 +6,7 @@
 	"os/user"
 
 	isecurity "veyron/runtimes/google/security"
+	vsecurity "veyron/security"
 
 	"veyron2/security"
 	"veyron2/vlog"
@@ -102,5 +103,5 @@
 		return nil, err
 	}
 	defer f.Close()
-	return security.LoadIdentity(f)
+	return vsecurity.LoadIdentity(f)
 }
diff --git a/runtimes/google/security/identity_chain.go b/runtimes/google/security/identity_chain.go
index a16447d..e130058 100644
--- a/runtimes/google/security/identity_chain.go
+++ b/runtimes/google/security/identity_chain.go
@@ -156,7 +156,7 @@
 		return nil, err
 	}
 	now := time.Now()
-	caveats = append(caveats, security.UniversalCaveat(&caveat.Expiry{IssueTime: now, ExpiryTime: now.Add(duration)}))
+	caveats = append(caveats, caveat.UniversalCaveat(&caveat.Expiry{IssueTime: now, ExpiryTime: now.Add(duration)}))
 	var err error
 	if cert.Caveats, err = wire.EncodeCaveats(caveats); err != nil {
 		return nil, err
diff --git a/runtimes/google/security/identity_test.go b/runtimes/google/security/identity_test.go
index 065f351..a9961a9 100644
--- a/runtimes/google/security/identity_test.go
+++ b/runtimes/google/security/identity_test.go
@@ -137,7 +137,7 @@
 	}
 	for _, d := range testdata {
 		for _, m := range d.matchData {
-			if got := security.Matches(d.id, m.pattern); got != m.want {
+			if got := m.pattern.MatchedBy(d.id); got != m.want {
 				t.Errorf("%q.Match(%s), Got %t, want %t", d.id, m.pattern, got, m.want)
 			}
 		}
@@ -447,7 +447,7 @@
 		if err != nil {
 			t.Fatal(err)
 		}
-		return []security.ServiceCaveat{security.UniversalCaveat(c)}
+		return []security.ServiceCaveat{caveat.UniversalCaveat(c)}
 	}
 	var (
 		alice = newChain("alice")
@@ -593,7 +593,7 @@
 
 		// Caveats
 		tpCavService   = security.ServiceCaveat{Service: "someService", Caveat: mkTPCaveat(alice.PublicID())}
-		tpCavUniversal = security.UniversalCaveat(mkTPCaveat(alice.PublicID()))
+		tpCavUniversal = caveat.UniversalCaveat(mkTPCaveat(alice.PublicID()))
 		cav            = methodRestrictionCaveat("someService", nil)[0]
 	)
 
diff --git a/runtimes/google/security/publicid_store.go b/runtimes/google/security/publicid_store.go
index d3d4f4a..fd87035 100644
--- a/runtimes/google/security/publicid_store.go
+++ b/runtimes/google/security/publicid_store.go
@@ -119,7 +119,7 @@
 	var matchingIDs []security.PublicID
 	for id, peerPatterns := range s.state.Store {
 		for _, peerPattern := range peerPatterns {
-			if security.Matches(peer, peerPattern) {
+			if peerPattern.MatchedBy(peer) {
 				matchingIDs = append(matchingIDs, id)
 				break
 			}
@@ -140,7 +140,7 @@
 	defer s.mu.RUnlock()
 	var matchingIDs []security.PublicID
 	for id, _ := range s.state.Store {
-		if security.Matches(id, s.state.DefaultPattern) {
+		if s.state.DefaultPattern.MatchedBy(id) {
 			matchingIDs = append(matchingIDs, id)
 		}
 	}
diff --git a/runtimes/google/security/util_test.go b/runtimes/google/security/util_test.go
index 4c495c9..1cc0a29 100644
--- a/runtimes/google/security/util_test.go
+++ b/runtimes/google/security/util_test.go
@@ -116,7 +116,7 @@
 }
 
 func peerIdentityCaveat(p security.PrincipalPattern) []security.ServiceCaveat {
-	return []security.ServiceCaveat{security.UniversalCaveat(caveat.PeerIdentity{p})}
+	return []security.ServiceCaveat{caveat.UniversalCaveat(caveat.PeerIdentity{p})}
 }
 
 func init() {
diff --git a/security/acl_authorizer.go b/security/acl_authorizer.go
index 9d88e13..9cda0e3 100644
--- a/security/acl_authorizer.go
+++ b/security/acl_authorizer.go
@@ -18,7 +18,6 @@
 	errACL          = errors.New("no matching ACL entry found")
 	errInvalidLabel = errors.New("label is invalid")
 	errNilID        = errors.New("identity being matched is nil")
-	nullACL         security.ACL
 )
 
 // aclAuthorizer implements Authorizer.
@@ -81,8 +80,17 @@
 	if id == nil {
 		return errNilID
 	}
-	if acl.Matches(id, label) {
-		return nil
+	names := id.Names()
+	if len(names) == 0 {
+		// If id.Names() is empty, create a list of one empty name to force a
+		// call to CanAccess. Otherwise, ids with no names will not have access
+		// on an AllPrincipals ACL.
+		names = make([]string, 1)
+	}
+	for _, name := range names {
+		if acl.CanAccess(name, label) {
+			return nil
+		}
 	}
 	return errACL
 }
@@ -93,5 +101,5 @@
 		return nullACL, err
 	}
 	defer f.Close()
-	return security.LoadACL(f)
+	return LoadACL(f)
 }
diff --git a/security/acl_authorizer_test.go b/security/acl_authorizer_test.go
index 8e58b33..07da673 100644
--- a/security/acl_authorizer_test.go
+++ b/security/acl_authorizer_test.go
@@ -37,7 +37,7 @@
 		panic(err)
 	}
 	defer f.Close()
-	if err := security.SaveACL(f, acl); err != nil {
+	if err := SaveACL(f, acl); err != nil {
 		defer os.Remove(f.Name())
 		panic(err)
 	}
@@ -50,7 +50,7 @@
 		panic(err)
 	}
 	defer f.Close()
-	if err := security.SaveACL(f, acl); err != nil {
+	if err := SaveACL(f, acl); err != nil {
 		panic(err)
 	}
 }
diff --git a/security/caveat/caveat.go b/security/caveat/caveat.go
index d3da712..6ad9f25 100644
--- a/security/caveat/caveat.go
+++ b/security/caveat/caveat.go
@@ -9,6 +9,11 @@
 	"veyron2/vom"
 )
 
+// UniversalCaveat takes a Caveat and returns a ServiceCaveat bound to all principals.
+func UniversalCaveat(cav security.Caveat) security.ServiceCaveat {
+	return security.ServiceCaveat{Service: security.AllPrincipals, Caveat: cav}
+}
+
 // Expiry is a security.Caveat that restricts the validity period of
 // the credential bearing this caveat.
 type Expiry struct {
@@ -52,7 +57,7 @@
 // identified by the PrincipalPatterns on the caveat.
 func (c PeerIdentity) Validate(ctx security.Context) error {
 	for _, p := range c {
-		if ctx.LocalID() != nil && security.Matches(ctx.LocalID(), p) {
+		if ctx.LocalID() != nil && p.MatchedBy(ctx.LocalID()) {
 			return nil
 		}
 	}
diff --git a/security/caveat/public_key_caveat.go b/security/caveat/public_key_caveat.go
index 636d89b..30cbf74 100644
--- a/security/caveat/public_key_caveat.go
+++ b/security/caveat/public_key_caveat.go
@@ -193,7 +193,7 @@
 	}
 	now := time.Now()
 	expiryCaveat := &Expiry{IssueTime: now, ExpiryTime: now.Add(duration)}
-	caveats = append(caveats, security.UniversalCaveat(expiryCaveat))
+	caveats = append(caveats, UniversalCaveat(expiryCaveat))
 	encodedCaveats, err := wire.EncodeCaveats(caveats)
 	if err != nil {
 		return nil, fmt.Errorf("failed to encode caveats in discharge: %v", err)
diff --git a/security/flag/flag.go b/security/flag/flag.go
index 11dfcca..88eceb0 100644
--- a/security/flag/flag.go
+++ b/security/flag/flag.go
@@ -31,7 +31,7 @@
 	if len(*aclFile) != 0 {
 		return vsecurity.NewFileACLAuthorizer(*aclFile)
 	}
-	a, err := security.LoadACL(bytes.NewBufferString(*acl))
+	a, err := vsecurity.LoadACL(bytes.NewBufferString(*acl))
 	if err != nil {
 		return nil
 	}
diff --git a/security/flag/flag_test.go b/security/flag/flag_test.go
index 0f7ff63..a52bf26 100644
--- a/security/flag/flag_test.go
+++ b/security/flag/flag_test.go
@@ -30,7 +30,7 @@
 	}
 	var (
 		acl1 = security.ACL{}
-		acl2 = security.NewWhitelistACL(map[security.PrincipalPattern]security.LabelSet{
+		acl2 = vsecurity.NewWhitelistACL(map[security.PrincipalPattern]security.LabelSet{
 			"veyron/alice": security.LabelSet(security.ReadLabel | security.WriteLabel),
 			"veyron/bob":   security.LabelSet(security.ReadLabel),
 		})
diff --git a/security/util.go b/security/util.go
new file mode 100644
index 0000000..afdfd87
--- /dev/null
+++ b/security/util.go
@@ -0,0 +1,58 @@
+package security
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"io"
+
+	"veyron2/security"
+	"veyron2/vom"
+)
+
+var nullACL security.ACL
+
+// NewWhitelistACL creates an ACL that grants access to only the provided
+// principals.
+func NewWhitelistACL(principals map[security.PrincipalPattern]security.LabelSet) security.ACL {
+	acl := security.ACL{}
+	acl.In.Principals = principals
+	return acl
+}
+
+// LoadIdentity reads a PrivateID from r, assuming that it was written using
+// SaveIdentity.
+func LoadIdentity(r io.Reader) (security.PrivateID, error) {
+	var id security.PrivateID
+	if err := vom.NewDecoder(base64.NewDecoder(base64.URLEncoding, r)).Decode(&id); err != nil {
+		return nil, err
+	}
+	return id, nil
+}
+
+// SaveIdentity writes a serialized form of a PrivateID to w, which can be
+// recovered using LoadIdentity.
+func SaveIdentity(w io.Writer, id security.PrivateID) error {
+	closer := base64.NewEncoder(base64.URLEncoding, w)
+	if err := vom.NewEncoder(closer).Encode(id); err != nil {
+		return err
+	}
+	// Must close the base64 encoder to flush out any partially written blocks.
+	if err := closer.Close(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// LoadACL reads an ACL from the provided Reader containing a JSON encoded ACL.
+func LoadACL(r io.Reader) (security.ACL, error) {
+	var acl security.ACL
+	if err := json.NewDecoder(r).Decode(&acl); err != nil {
+		return nullACL, err
+	}
+	return acl, nil
+}
+
+// SaveACL encodes an ACL in JSON format and writes it to the provided Writer.
+func SaveACL(w io.Writer, acl security.ACL) error {
+	return json.NewEncoder(w).Encode(acl)
+}
diff --git a/security/util_test.go b/security/util_test.go
new file mode 100644
index 0000000..5fd6252
--- /dev/null
+++ b/security/util_test.go
@@ -0,0 +1,51 @@
+package security
+
+import (
+	"bytes"
+	"reflect"
+	"testing"
+
+	"veyron2/security"
+)
+
+func TestLoadSaveIdentity(t *testing.T) {
+	id := security.FakePrivateID("test")
+
+	var buf bytes.Buffer
+	if err := SaveIdentity(&buf, id); err != nil {
+		t.Fatalf("Failed to save PrivateID %q: %v", id, err)
+	}
+
+	loadedID, err := LoadIdentity(&buf)
+	if err != nil {
+		t.Fatalf("Failed to load PrivateID: %v", err)
+	}
+	if !reflect.DeepEqual(loadedID, id) {
+		t.Fatalf("Got Identity %v, but want %v", loadedID, id)
+	}
+}
+
+func TestLoadSaveACL(t *testing.T) {
+	acl := security.ACL{}
+	acl.In.Principals = map[security.PrincipalPattern]security.LabelSet{
+		"veyron/*":     security.LabelSet(security.ReadLabel),
+		"veyron/alice": security.LabelSet(security.ReadLabel | security.WriteLabel),
+		"veyron/bob":   security.LabelSet(security.AdminLabel),
+	}
+	acl.NotIn.Principals = map[security.PrincipalPattern]security.LabelSet{
+		"veyron/che": security.LabelSet(security.ReadLabel),
+	}
+
+	var buf bytes.Buffer
+	if err := SaveACL(&buf, acl); err != nil {
+		t.Fatalf("Failed to save ACL %q: %v", acl, err)
+	}
+
+	loadedACL, err := LoadACL(&buf)
+	if err != nil {
+		t.Fatalf("Failed to load ACL: %v", err)
+	}
+	if !reflect.DeepEqual(loadedACL, acl) {
+		t.Fatalf("Got ACL %v, but want %v", loadedACL, acl)
+	}
+}
diff --git a/services/identity/identityd/main.go b/services/identity/identityd/main.go
index a411982..d440bf3 100644
--- a/services/identity/identityd/main.go
+++ b/services/identity/identityd/main.go
@@ -134,7 +134,7 @@
 	if err != nil {
 		return nil, nil, fmt.Errorf("server.Listen(%q, %q) failed: %v", "tcp", *address, err)
 	}
-	allowEveryoneACL := security.NewWhitelistACL(map[security.PrincipalPattern]security.LabelSet{
+	allowEveryoneACL := vsecurity.NewWhitelistACL(map[security.PrincipalPattern]security.LabelSet{
 		security.AllPrincipals: security.AllLabels,
 	})
 	objectname := fmt.Sprintf("identity/%s/google", r.Identity().PublicID().Names()[0])
diff --git a/services/wsprd/identity/identity.go b/services/wsprd/identity/identity.go
index 989be61..b947a21 100644
--- a/services/wsprd/identity/identity.go
+++ b/services/wsprd/identity/identity.go
@@ -137,7 +137,7 @@
 	defer i.mu.Unlock()
 	result := []string{}
 	for name, id := range i.state.Accounts {
-		if security.Matches(id.PublicID(), trustedRoot) {
+		if trustedRoot.MatchedBy(id.PublicID()) {
 			result = append(result, name)
 		}
 	}
diff --git a/services/wsprd/ipc/server/server.go b/services/wsprd/ipc/server/server.go
index 5349086..989a053 100644
--- a/services/wsprd/ipc/server/server.go
+++ b/services/wsprd/ipc/server/server.go
@@ -177,7 +177,7 @@
 
 	if s.dispatcher == nil {
 		s.dispatcher = newDispatcher(invoker,
-			vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
+			vsecurity.NewACLAuthorizer(vsecurity.NewWhitelistACL(
 				map[security.PrincipalPattern]security.LabelSet{
 					security.AllPrincipals: security.AllLabels,
 				})))