"veyron2/security": Caveat and CaveatValidator

In accordance with the plan in
https://veyron-review.googlesource.com/#/c/4102/ this CL makes the
following changes:
1) Removes the ServiceCaveat type
2) Renames the Caveat type to CaveatValidator
3) Adds new Caveat and ThirdPartyCaveat types
4) Minor method renames in security.Context

Notes:
* CaveatValidator is an interface with a method Validate. All
concrete caveat implemenations must implement this interface.

* A Caveat is a serialized caveat implementation obtained using
the security.NewCaveat(CaveatValidator) factory function.

* A ThirPartyCaveat is an interface that embeds CaveatValidator along
with other methods for obtaining the ID, Location and requirements of
a third-party caveat.

* Bless and MintDischarge methods now directly take Caveat objects and
embed them in the PublicID and Discharge respectively. The caller of
Bless and MintDischarge need not have the CaveatValidator implementation
from which the Caveat objects were obtained.

* While validating a PublicID or a Discharge, any Caveats that fail to
decode to a CaveatValidator are considered invalid, in other words, all
caveats are universally enforced.

Change-Id: I9430bb90af3267d1b6f235be9056175c30f4d2da
diff --git a/examples/bank/pbankd/main.go b/examples/bank/pbankd/main.go
index 46caabf..d8a7e3a 100644
--- a/examples/bank/pbankd/main.go
+++ b/examples/bank/pbankd/main.go
@@ -177,7 +177,7 @@
 // 			context.RemoteID(),
 // 			fmt.Sprintf("%d", randID),
 // 			BLESS_DURATION,
-// 			[]security.ServiceCaveat{security.UniversalCaveat(caveat.PeerIdentity{pp})},
+// 			[]security.ServiceCaveat{security.UniversalCaveat(caveat.PeerBlessings{pp})},
 // 		)
 // 		if err != nil {
 // 			vlog.Fatal(err)
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 072a6fa..d31f0da 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -53,7 +53,7 @@
 		streamMgr:      streamMgr,
 		ns:             ns,
 		vcMap:          make(map[string]*vcInfo),
-		dischargeCache: dischargeCache{CaveatDischargeMap: make(security.CaveatDischargeMap)},
+		dischargeCache: dischargeCache{cache: make(map[string]security.Discharge)},
 	}
 	for _, opt := range opts {
 		// Collect all client opts that are also vc opts.
@@ -240,14 +240,14 @@
 	flow     stream.Flow  // the underlying flow
 	response ipc.Response // each decoded response message is kept here
 
-	discharges     []security.ThirdPartyDischarge // discharges used for this request
-	dischargeCache *dischargeCache                // client-global discharge cache reference type
+	discharges     []security.Discharge // discharges used for this request
+	dischargeCache *dischargeCache      // client-global discharge cache reference type
 
 	sendClosedMu sync.Mutex
 	sendClosed   bool // is the send side already closed? GUARDED_BY(sendClosedMu)
 }
 
-func newFlowClient(flow stream.Flow, dischargeCache *dischargeCache, discharges []security.ThirdPartyDischarge) *flowClient {
+func newFlowClient(flow stream.Flow, dischargeCache *dischargeCache, discharges []security.Discharge) *flowClient {
 	return &flowClient{
 		// TODO(toddw): Support different codecs
 		dec:            vom.NewDecoder(flow),
@@ -284,7 +284,7 @@
 	}
 	for _, d := range fc.discharges {
 		if err := fc.enc.Encode(d); err != nil {
-			return fc.close(verror.BadProtocolf("ipc: failed to encode discharge for %x: %v", d.CaveatID(), err))
+			return fc.close(verror.BadProtocolf("ipc: failed to encode discharge for %x: %v", d.ID(), err))
 		}
 	}
 	for ix, arg := range args {
diff --git a/runtimes/google/ipc/discharges.go b/runtimes/google/ipc/discharges.go
index 173ecd9..eac483e 100644
--- a/runtimes/google/ipc/discharges.go
+++ b/runtimes/google/ipc/discharges.go
@@ -15,7 +15,7 @@
 // options, or requested from the discharge issuer indicated on the caveat.
 // Note that requesting a discharge is an ipc call, so one copy of this
 // function must be able to successfully terminate while another is blocked.
-func (c *client) prepareDischarges(ctx context.T, blessing, server security.PublicID, method string, args []interface{}, opts []ipc.CallOpt) (ret []security.ThirdPartyDischarge) {
+func (c *client) prepareDischarges(ctx context.T, blessing, server security.PublicID, method string, args []interface{}, opts []ipc.CallOpt) (ret []security.Discharge) {
 	// TODO(andreser,ataly): figure out whether this should return an error and how that should be handled
 	// Missing discharges do not necessarily mean the blessing is invalid (e.g., SetID)
 	if blessing == nil {
@@ -24,15 +24,13 @@
 
 	var caveats []security.ThirdPartyCaveat
 	for _, cav := range blessing.ThirdPartyCaveats() {
-		if cav.Service.MatchedBy(server.Names()...) {
-			caveats = append(caveats, cav.Caveat.(security.ThirdPartyCaveat))
-		}
+		caveats = append(caveats, cav)
 	}
 	if len(caveats) == 0 {
 		return
 	}
 
-	discharges := make([]security.ThirdPartyDischarge, len(caveats))
+	discharges := make([]security.Discharge, len(caveats))
 	dischargesFromOpts(caveats, opts, discharges)
 	c.dischargeCache.Discharges(caveats, discharges)
 	if shouldFetchDischarges(opts) {
@@ -49,25 +47,25 @@
 // dischargeCache is a concurrency-safe cache for third party caveat discharges.
 type dischargeCache struct {
 	sync.RWMutex
-	security.CaveatDischargeMap // GUARDED_BY(RWMutex)
+	cache map[string]security.Discharge // GUARDED_BY(RWMutex)
 }
 
 // Add inserts the argument to the cache, possibly overwriting previous
 // discharges for the same caveat.
-func (dcc *dischargeCache) Add(discharges ...security.ThirdPartyDischarge) {
+func (dcc *dischargeCache) Add(discharges ...security.Discharge) {
 	dcc.Lock()
 	for _, d := range discharges {
-		dcc.CaveatDischargeMap[d.CaveatID()] = d
+		dcc.cache[d.ID()] = d
 	}
 	dcc.Unlock()
 }
 
 // Invalidate removes discharges from the cache.
-func (dcc *dischargeCache) Invalidate(discharges ...security.ThirdPartyDischarge) {
+func (dcc *dischargeCache) Invalidate(discharges ...security.Discharge) {
 	dcc.Lock()
 	for _, d := range discharges {
-		if dcc.CaveatDischargeMap[d.CaveatID()] == d {
-			delete(dcc.CaveatDischargeMap, d.CaveatID())
+		if dcc.cache[d.ID()] == d {
+			delete(dcc.cache, d.ID())
 		}
 	}
 	dcc.Unlock()
@@ -77,13 +75,13 @@
 // length and fills in nil entries in the discharges slice with discharges
 // from the cache (if there are any).
 // REQUIRES: len(caveats) == len(out)
-func (dcc *dischargeCache) Discharges(caveats []security.ThirdPartyCaveat, out []security.ThirdPartyDischarge) {
+func (dcc *dischargeCache) Discharges(caveats []security.ThirdPartyCaveat, out []security.Discharge) {
 	dcc.Lock()
 	for i, d := range out {
 		if d != nil {
 			continue
 		}
-		out[i] = dcc.CaveatDischargeMap[caveats[i].ID()]
+		out[i] = dcc.cache[caveats[i].ID()]
 	}
 	dcc.Unlock()
 }
@@ -92,14 +90,14 @@
 // opts that match the caveat at the same index in caveats.
 // REQUIRES: len(caveats) == len(out)
 func dischargesFromOpts(caveats []security.ThirdPartyCaveat, opts []ipc.CallOpt,
-	out []security.ThirdPartyDischarge) {
+	out []security.Discharge) {
 	for _, opt := range opts {
 		d, ok := opt.(veyron2.DischargeOpt)
 		if !ok {
 			continue
 		}
 		for i, cav := range caveats {
-			if out[i] == nil && d.CaveatID() == cav.ID() {
+			if out[i] == nil && d.ID() == cav.ID() {
 				out[i] = d
 			}
 		}
@@ -111,13 +109,13 @@
 // caveats, fetchDischarges keeps retrying until either all discharges can be
 // fetched or no new discharges are fetched.
 // REQUIRES: len(caveats) == len(out)
-func (c *client) fetchDischarges(ctx context.T, caveats []security.ThirdPartyCaveat, server security.PublicID, method string, args []interface{}, opts []ipc.CallOpt, out []security.ThirdPartyDischarge) {
+func (c *client) fetchDischarges(ctx context.T, caveats []security.ThirdPartyCaveat, server security.PublicID, method string, args []interface{}, opts []ipc.CallOpt, out []security.Discharge) {
 	opts = append([]ipc.CallOpt{dontFetchDischarges{}}, opts...)
 	var wg sync.WaitGroup
 	for {
 		type fetched struct {
 			idx       int
-			discharge security.ThirdPartyDischarge
+			discharge security.Discharge
 		}
 		discharges := make(chan fetched, len(caveats))
 		for i := range caveats {
@@ -140,9 +138,9 @@
 					vlog.VI(3).Infof("Discharge fetch for caveat %T from %v failed: (%v, %v)", cav, cav.Location(), err, ierr)
 					return
 				}
-				d, ok := dAny.(security.ThirdPartyDischarge)
+				d, ok := dAny.(security.Discharge)
 				if !ok {
-					vlog.Errorf("fetchDischarges: server at %s sent a %T (%v) instead of a ThirdPartyDischarge", cav.Location(), dAny, dAny)
+					vlog.Errorf("fetchDischarges: server at %s sent a %T (%v) instead of a Discharge", cav.Location(), dAny, dAny)
 				}
 				discharges <- fetched{i, d}
 			}(i, caveats[i])
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index c450b81..8f3f127 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -136,7 +136,7 @@
 	}
 	// Add a fakeTimeCaveat to allow the discharge to expire
 	expiry := fakeTimeCaveat(clock.Now())
-	return serverID.MintDischarge(c, ctx, time.Hour, []security.ServiceCaveat{caveat.UniversalCaveat(expiry)})
+	return serverID.MintDischarge(c, ctx, time.Hour, newCaveat(expiry))
 }
 
 type testServerAuthorizer struct{}
@@ -357,7 +357,7 @@
 	return
 }
 
-func bless(blessor security.PrivateID, blessee security.PublicID, name string, caveats ...security.ServiceCaveat) security.PublicID {
+func bless(blessor security.PrivateID, blessee security.PublicID, name string, caveats ...security.Caveat) security.PublicID {
 	blessed, err := blessor.Bless(blessee, name, 24*time.Hour, caveats)
 	if err != nil {
 		panic(err)
@@ -365,7 +365,7 @@
 	return blessed
 }
 
-func derive(blessor security.PrivateID, name string, caveats ...security.ServiceCaveat) security.PrivateID {
+func derive(blessor security.PrivateID, name string, caveats ...security.Caveat) security.PrivateID {
 	id := newID("irrelevant")
 	derivedID, err := id.Derive(bless(blessor, id.PublicID(), name, caveats...))
 	if err != nil {
@@ -382,9 +382,9 @@
 // have the caveats, the second will always be valid, but only for getting
 // discharges. The client presents both blessings in both cases, the discharger
 // ignores the first if it is invalid.
-func deriveForThirdPartyCaveats(blessor security.PrivateID, name string, caveats ...security.ServiceCaveat) security.PrivateID {
+func deriveForThirdPartyCaveats(blessor security.PrivateID, name string, caveats ...security.Caveat) security.PrivateID {
 	id := derive(blessor, name, caveats...)
-	dischargeID, err := id.Derive(bless(blessor, id.PublicID(), name, caveat.UniversalCaveat(caveat.MethodRestriction{"Discharge"})))
+	dischargeID, err := id.Derive(bless(blessor, id.PublicID(), name, newCaveat(caveat.MethodRestriction{"Discharge"})...))
 	if err != nil {
 		panic(err)
 	}
@@ -455,18 +455,18 @@
 		nameErr      = "does not match the provided pattern"
 	)
 	var (
-	// TODO(ataly, ashankar): Uncomment the following once server authorization
-	// is enabled.
-	// now        = time.Now()
-	// cavOnlyV1  = caveat.UniversalCaveat(caveat.PeerIdentity{"client/v1"})
-	// cavExpired = security.ServiceCaveat{
-	//	Service: security.AllPrincipals,
-	//	Caveat:  &caveat.Expiry{IssueTime: now, ExpiryTime: now},
-	// }
-	// clientV1ID      = derive(clientID, "v1")
-	// clientV2ID      = derive(clientID, "v2")
-	// serverV1ID      = derive(serverID, "v1", cavOnlyV1)
-	// serverExpiredID = derive(serverID, "expired", cavExpired)
+		// TODO(ataly, ashankar): Uncomment the following once server authorization
+		// is enabled.
+		// now        = time.Now()
+		// cavOnlyV1  = caveat.UniversalCaveat(caveat.PeerIdentity{"client/v1"})
+		// cavExpired = security.ServiceCaveat{
+		//	Service: security.AllPrincipals,
+		//	Caveat:  &caveat.Expiry{IssueTime: now, ExpiryTime: now},
+		// }
+		// clientV1ID      = derive(clientID, "v1")
+		// clientV2ID      = derive(clientID, "v2")
+		// serverV1ID      = derive(serverID, "v1", cavOnlyV1)
+		// serverExpiredID = derive(serverID, "expired", cavExpired)
 	)
 
 	tests := []struct {
@@ -643,7 +643,7 @@
 }
 
 func mkThirdPartyCaveat(discharger security.PublicID, location string, c security.Caveat) security.ThirdPartyCaveat {
-	tpc, err := caveat.NewPublicKeyCaveat(c, discharger, location, security.ThirdPartyRequirements{})
+	tpc, err := caveat.NewPublicKeyCaveat(c, discharger.PublicKey(), location, security.ThirdPartyRequirements{})
 	if err != nil {
 		panic(err)
 	}
@@ -671,12 +671,12 @@
 		dischargerID = serverID.PublicID()
 
 		mkClientID = func(req security.ThirdPartyRequirements) security.PrivateID {
-			tpc, err := caveat.NewPublicKeyCaveat(alwaysValidCaveat{}, dischargerID, "mountpoint/discharger", req)
+			tpc, err := caveat.NewPublicKeyCaveat(newCaveat(alwaysValidCaveat{})[0], dischargerID.PublicKey(), "mountpoint/discharger", req)
 			if err != nil {
 				t.Fatalf("Failed to create ThirdPartyCaveat: %v", err)
 			}
-			caveat := caveat.UniversalCaveat(tpc)
-			return deriveForThirdPartyCaveats(serverID, "client", caveat)
+			caveat := newCaveat(tpc)
+			return deriveForThirdPartyCaveats(serverID, "client", caveat...)
 		}
 	)
 	sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
@@ -734,32 +734,20 @@
 	var (
 		now = time.Now()
 		// First-party caveats
-		cavOnlyEcho = security.ServiceCaveat{
-			Service: security.AllPrincipals,
-			Caveat:  caveat.MethodRestriction{"Echo"},
-		}
-		cavExpired = security.ServiceCaveat{
-			Service: security.AllPrincipals,
-			Caveat:  &caveat.Expiry{IssueTime: now, ExpiryTime: now},
-		}
+		cavOnlyEcho = newCaveat(caveat.MethodRestriction{"Echo"})
+		cavExpired  = newCaveat(&caveat.Expiry{IssueTime: now, ExpiryTime: now})
 		// Third-party caveats
 		// The Discharge service can be run by any identity, but in our tests the same server runs
 		// a Discharge service as well.
 		dischargerID = serverID.PublicID()
-		cavTPValid   = security.ServiceCaveat{
-			Service: security.BlessingPattern(serverID.PublicID().Names()[0]),
-			Caveat:  mkThirdPartyCaveat(dischargerID, "mountpoint/server/discharger", &caveat.Expiry{ExpiryTime: now.Add(24 * time.Hour)}),
-		}
-		cavTPExpired = security.ServiceCaveat{
-			Service: security.BlessingPattern(serverID.PublicID().Names()[0]),
-			Caveat:  mkThirdPartyCaveat(dischargerID, "mountpoint/server/discharger", &caveat.Expiry{IssueTime: now, ExpiryTime: now}),
-		}
+		cavTPValid   = newCaveat(mkThirdPartyCaveat(dischargerID, "mountpoint/server/discharger", newCaveat(&caveat.Expiry{ExpiryTime: now.Add(24 * time.Hour)})[0]))
+		cavTPExpired = newCaveat(mkThirdPartyCaveat(dischargerID, "mountpoint/server/discharger", newCaveat(&caveat.Expiry{IssueTime: now, ExpiryTime: now})[0]))
 
 		// Client blessings that will be tested
-		blessedByServerOnlyEcho  = derive(serverID, "onlyEcho", cavOnlyEcho)
-		blessedByServerExpired   = derive(serverID, "expired", cavExpired)
-		blessedByServerTPValid   = deriveForThirdPartyCaveats(serverID, "tpvalid", cavTPValid)
-		blessedByServerTPExpired = deriveForThirdPartyCaveats(serverID, "tpexpired", cavTPExpired)
+		blessedByServerOnlyEcho  = derive(serverID, "onlyEcho", cavOnlyEcho...)
+		blessedByServerExpired   = derive(serverID, "expired", cavExpired...)
+		blessedByServerTPValid   = deriveForThirdPartyCaveats(serverID, "tpvalid", cavTPValid...)
+		blessedByServerTPExpired = deriveForThirdPartyCaveats(serverID, "tpexpired", cavTPExpired...)
 		blessedByClient          = derive(clientID, "blessed")
 	)
 	const (
@@ -847,8 +835,8 @@
 func TestDischargePurgeFromCache(t *testing.T) {
 	var (
 		dischargerID = serverID.PublicID()
-		c            = mkThirdPartyCaveat(dischargerID, "mountpoint/server/discharger", alwaysValidCaveat{})
-		clientCID    = deriveForThirdPartyCaveats(serverID, "client", caveat.UniversalCaveat(c))
+		c            = mkThirdPartyCaveat(dischargerID, "mountpoint/server/discharger", newCaveat(alwaysValidCaveat{})[0])
+		clientCID    = deriveForThirdPartyCaveats(serverID, "client", newCaveat(c)...)
 	)
 	b := createBundle(t, clientCID, serverID, &testServer{})
 	defer b.cleanup(t)
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index c5a0b4a..3457328 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -379,7 +379,7 @@
 	blessing           security.PublicID
 	method, suffix     string
 	label              security.Label
-	discharges         security.CaveatDischargeMap
+	discharges         map[string]security.Discharge
 	deadline           time.Time
 	endStreamArgs      bool // are the stream args at EOF?
 }
@@ -395,7 +395,7 @@
 		dec:        vom.NewDecoder(flow),
 		enc:        vom.NewEncoder(flow),
 		flow:       flow,
-		discharges: make(security.CaveatDischargeMap),
+		discharges: make(map[string]security.Discharge),
 	}
 }
 
@@ -529,11 +529,11 @@
 	}
 	// Receive third party caveat discharges the client sent
 	for i := uint64(0); i < req.NumDischarges; i++ {
-		var d security.ThirdPartyDischarge
+		var d security.Discharge
 		if err := fs.dec.Decode(&d); err != nil {
 			return nil, verror.BadProtocolf("ipc: decoding discharge %d of %d failed: %v", i, req.NumDischarges, err)
 		}
-		fs.discharges[d.CaveatID()] = d
+		fs.discharges[d.ID()] = d
 	}
 	// Lookup the invoker.
 	invoker, auth, suffix, verr := fs.lookup(req.Suffix, req.Method)
@@ -642,7 +642,7 @@
 
 // Implementations of ipc.ServerContext methods.
 
-func (fs *flowServer) CaveatDischarges() security.CaveatDischargeMap { return fs.discharges }
+func (fs *flowServer) Discharges() map[string]security.Discharge { return fs.discharges }
 
 func (fs *flowServer) Server() ipc.Server { return fs.server }
 func (fs *flowServer) Method() string     { return fs.method }
diff --git a/runtimes/google/ipc/testutil_test.go b/runtimes/google/ipc/testutil_test.go
index 2768b0c..b6b962e 100644
--- a/runtimes/google/ipc/testutil_test.go
+++ b/runtimes/google/ipc/testutil_test.go
@@ -49,5 +49,13 @@
 	return id
 }
 
+func newCaveat(v security.CaveatValidator) []security.Caveat {
+	cav, err := security.NewCaveat(v)
+	if err != nil {
+		panic(err)
+	}
+	return []security.Caveat{cav}
+}
+
 var _ ipc.ClientOpt = vc.FixedLocalID(newID("irrelevant"))
 var _ ipc.ServerOpt = vc.FixedLocalID(newID("irrelevant"))
diff --git a/runtimes/google/security/identity_chain.go b/runtimes/google/security/identity_chain.go
index 5c24f7c..076b715 100644
--- a/runtimes/google/security/identity_chain.go
+++ b/runtimes/google/security/identity_chain.go
@@ -12,6 +12,7 @@
 	"time"
 
 	"veyron/runtimes/google/security/keys"
+	vsecurity "veyron/security"
 	"veyron/security/caveat"
 	"veyron/security/signing"
 
@@ -31,6 +32,10 @@
 	mistrustedIDProviderPrefix = "mistrusted/"
 )
 
+func errAuthorize(err error) error {
+	return fmt.Errorf("not authorized because: %v", err)
+}
+
 // chainPublicID implements security.PublicID.
 type chainPublicID struct {
 	certificates []wire.Certificate
@@ -92,18 +97,27 @@
 // PublicID and hence has integrity.
 func (id *chainPublicID) Authorize(context security.Context) (security.PublicID, error) {
 	for _, c := range id.certificates {
-		if err := c.ValidateCaveats(context); err != nil {
-			return nil, fmt.Errorf("not authorized because %v", err)
+		for _, cav := range c.Caveats {
+			v, err := vsecurity.CaveatValidators(cav.Bytes)
+			if err != nil {
+				return nil, errAuthorize(err)
+			}
+			if err := v[0].Validate(context); err != nil {
+				return nil, errAuthorize(err)
+			}
 		}
 	}
 	return id, nil
 }
 
-func (id *chainPublicID) ThirdPartyCaveats() (thirdPartyCaveats []security.ServiceCaveat) {
+func (id *chainPublicID) ThirdPartyCaveats() []security.ThirdPartyCaveat {
+	var tpCaveats []security.ThirdPartyCaveat
 	for _, c := range id.certificates {
-		thirdPartyCaveats = append(thirdPartyCaveats, wire.DecodeThirdPartyCaveats(c.Caveats)...)
+		for _, cav := range c.Caveats {
+			tpCaveats = append(tpCaveats, vsecurity.ThirdPartyCaveats(cav.Bytes)...)
+		}
 	}
-	return
+	return tpCaveats
 }
 
 // chainPrivateID implements security.PrivateID
@@ -145,26 +159,35 @@
 // Bless returns a new PublicID by extending the ceritificate chain of the PrivateID's
 // PublicID with a new certificate that has the provided blessingName, caveats, and an
 // additional expiry caveat for the given duration.
-func (id *chainPrivateID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.ServiceCaveat) (security.PublicID, error) {
+func (id *chainPrivateID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.Caveat) (security.PublicID, error) {
 	// The integrity of the PublicID blessee is assumed to have been verified
 	// (typically by a Vom decode).
 	if err := wire.ValidateBlessingName(blessingName); err != nil {
 		return nil, err
 	}
+
 	cert := wire.Certificate{Name: blessingName}
 	if err := cert.PublicKey.Encode(blessee.PublicKey()); err != nil {
 		return nil, err
 	}
+
 	now := time.Now()
-	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 {
+	expiryCaveat, err := security.NewCaveat(&caveat.Expiry{IssueTime: now, ExpiryTime: now.Add(duration)})
+	if err != nil {
 		return nil, err
 	}
+	caveats = append(caveats, expiryCaveat)
+
+	cert.Caveats = make([]wire.Caveat, len(caveats))
+	for i, c := range caveats {
+		cert.Caveats[i] = wire.Caveat{Bytes: vsecurity.CaveatBytes(c)[0]}
+	}
+
 	vomPubID, err := id.publicID.VomEncode()
 	if err != nil {
 		return nil, err
 	}
+
 	if err := cert.Sign(id, vomPubID); err != nil {
 		return nil, err
 	}
@@ -204,7 +227,7 @@
 	}
 }
 
-func (id *chainPrivateID) MintDischarge(cav security.ThirdPartyCaveat, ctx security.Context, duration time.Duration, dischargeCaveats []security.ServiceCaveat) (security.ThirdPartyDischarge, error) {
+func (id *chainPrivateID) MintDischarge(cav security.ThirdPartyCaveat, ctx security.Context, duration time.Duration, dischargeCaveats []security.Caveat) (security.Discharge, error) {
 	return caveat.NewPublicKeyDischarge(id, cav, ctx, duration, dischargeCaveats)
 }
 
diff --git a/runtimes/google/security/identity_set.go b/runtimes/google/security/identity_set.go
index 5ff2f4e..8cb9de6 100644
--- a/runtimes/google/security/identity_set.go
+++ b/runtimes/google/security/identity_set.go
@@ -71,20 +71,17 @@
 	return NewSetPublicID(authids...)
 }
 
-func (s *setPublicID) ThirdPartyCaveats() []security.ServiceCaveat {
-	set := make(map[security.ThirdPartyCaveatID]security.ServiceCaveat)
+func (s *setPublicID) ThirdPartyCaveats() []security.ThirdPartyCaveat {
+	set := make(map[string]security.ThirdPartyCaveat)
 	for _, id := range *s {
-		for _, c := range id.ThirdPartyCaveats() {
-			if tp, ok := c.Caveat.(security.ThirdPartyCaveat); ok {
-				set[tp.ID()] = c
-			}
-			// else { This should not be possible! }
+		for _, tp := range id.ThirdPartyCaveats() {
+			set[tp.ID()] = tp
 		}
 	}
 	if len(set) == 0 {
 		return nil
 	}
-	ret := make([]security.ServiceCaveat, 0, len(set))
+	ret := make([]security.ThirdPartyCaveat, 0, len(set))
 	for _, c := range set {
 		ret = append(ret, c)
 	}
@@ -159,7 +156,7 @@
 
 func (s setPrivateID) PublicKey() security.PublicKey { return s[0].PublicKey() }
 
-func (s setPrivateID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.ServiceCaveat) (security.PublicID, error) {
+func (s setPrivateID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.Caveat) (security.PublicID, error) {
 	pubs := make([]security.PublicID, len(s))
 	for ix, id := range s {
 		var err error
@@ -188,7 +185,7 @@
 	}
 }
 
-func (s setPrivateID) MintDischarge(cav security.ThirdPartyCaveat, ctx security.Context, duration time.Duration, dischargeCaveats []security.ServiceCaveat) (security.ThirdPartyDischarge, error) {
+func (s setPrivateID) MintDischarge(cav security.ThirdPartyCaveat, ctx security.Context, duration time.Duration, dischargeCaveats []security.Caveat) (security.Discharge, error) {
 	for _, id := range s {
 		if d, err := id.MintDischarge(cav, ctx, duration, dischargeCaveats); err == nil {
 			return d, nil
diff --git a/runtimes/google/security/identity_test.go b/runtimes/google/security/identity_test.go
index 1f34ca0..c6c1779 100644
--- a/runtimes/google/security/identity_test.go
+++ b/runtimes/google/security/identity_test.go
@@ -10,9 +10,11 @@
 	"testing"
 	"time"
 
+	"veyron/lib/testutil/blackbox"
 	"veyron/security/caveat"
 	"veyron2/security"
 	"veyron2/security/wire"
+	"veyron2/vlog"
 	"veyron2/vom"
 )
 
@@ -294,29 +296,73 @@
 	}
 }
 
+type unregisteredCaveat struct {
+	// TODO(ataly, ashankar): The int is embedded in order to
+	// distinguish the signature of this type from other Caveat types
+	// and therefore preventing VOM from decoding values of this type
+	// into another type. This is still not foolproof, we need to figure
+	// out a better way of preventing the accidental decoding into another
+	// type.
+	UniqueField int
+}
+
+func (unregisteredCaveat) Validate(security.Context) error {
+	return nil
+}
+
+func encodeUnregisteredCaveat([]string) {
+	cav, err := security.NewCaveat(unregisteredCaveat{1})
+	if err != nil {
+		vlog.Fatalf("security.NewCaveat failed: %s", err)
+	}
+	var buf bytes.Buffer
+	if err := vom.NewEncoder(&buf).Encode(cav); err != nil {
+		vlog.Fatalf("could not VOM-encode caveat: %s", err)
+	}
+	fmt.Println(string(buf.Bytes()))
+	blackbox.WaitForEOFOnStdin()
+}
+
+func TestHelperProcess(t *testing.T) {
+	blackbox.HelperProcess(t)
+}
+
 func TestAuthorizeWithCaveats(t *testing.T) {
 	var (
 		// alice
 		pcAlice = newChain("alice")
 		cAlice  = pcAlice.PublicID().(*chainPublicID)
 
-		// veyron/alice/tv
-		cVeyronAliceTV = bless(newChain("tv").PublicID(),
-			derive(bless(cAlice, veyronChain, "alice", nil), pcAlice),
-			"tv", nil).(*chainPublicID)
-
 		// Some random server called bob
 		bob = newChain("bob").PublicID()
 
 		// Caveats
 		// Can only call "Play" at the Google service
-		cavOnlyPlayAtGoogle = methodRestrictionCaveat("google", S{"Play"})
+		cavOnlyPlay = methodRestrictionCaveat(S{"Play"})
 		// Can only talk to the "Google" service
 		cavOnlyGoogle = peerIdentityCaveat("google")
-		// Can only call the PublicProfile method on veyron/alice/...
-		cavOnlyPublicProfile = methodRestrictionCaveat("veyron/alice/...", S{"PublicProfile"})
 	)
 
+	// We create a Caveat from the CaveatValidator "unregisteredCaveat".
+	// Since "unregisteredCaveat" is not registered with VOM, decoding
+	// this caveat as part of a PublicID should fail.
+	//
+	// The Caveat is created within a child process as VOM automaitcally
+	// registers all values encoded within the same process.
+	child := blackbox.HelperCommand(t, "encodeUnregisteredCaveat")
+	child.Cmd.Start()
+	defer child.Cleanup()
+	encodedCaveat, err := child.ReadLineFromChild()
+	if err != nil {
+		t.Fatalf("ReadLineFromChild failed: %v", err)
+	}
+	child.CloseStdin()
+
+	var cavUnregistered security.Caveat
+	if err := vom.NewDecoder(bytes.NewReader([]byte(encodedCaveat))).Decode(&cavUnregistered); err != nil {
+		t.Fatalf("Failed to decode bytes obtained from ReadLineFromChild: %v", err)
+	}
+
 	type rpc struct {
 		server security.PublicID
 		method string
@@ -330,47 +376,55 @@
 	}{
 		// client has a chain identity
 		{
-			client: bless(cAlice, veyronChain, "alice", cavOnlyPlayAtGoogle),
+			client: bless(cAlice, veyronChain, "alice", cavOnlyPlay),
 			tests: []rpc{
-				{server: bob, method: "Hello", authNames: S{"veyron/alice"}},
-				{server: bob, authNames: S{"veyron/alice"}},
-				{server: googleChain.PublicID(), method: "Hello", authErr: `caveat.MethodRestriction{"Play"} forbids invocation of method Hello`},
+				{server: bob, method: "Play", authNames: S{"veyron/alice"}},
+				{server: bob, method: "Hello", authErr: `caveat.MethodRestriction{"Play"} forbids invocation of method Hello`},
 				{server: googleChain.PublicID(), method: "Play", authNames: S{"veyron/alice"}},
-				{server: googleChain.PublicID(), authNames: S{"veyron/alice"}},
+				{server: googleChain.PublicID(), method: "Hello", authErr: `caveat.MethodRestriction{"Play"} forbids invocation of method Hello`},
 			},
 		},
 		{
 			client: bless(cAlice, veyronChain, "alice", cavOnlyGoogle),
 			tests: []rpc{
-				{server: bob, method: "Hello", authErr: `caveat.PeerIdentity{"google"} forbids RPCing with peer`},
+				{server: bob, method: "Hello", authErr: `caveat.PeerBlessings{"google"} forbids RPCing with peer`},
 				{server: googleChain.PublicID(), method: "Hello", authNames: S{"veyron/alice"}},
 				{server: googleChain.PublicID(), method: "Play", authNames: S{"veyron/alice"}},
 			},
 		},
 		{
-			client: bless(cAlice, veyronChain, "alice", append(cavOnlyGoogle, cavOnlyPlayAtGoogle...)),
+			client: bless(cAlice, veyronChain, "alice", []security.Caveat{cavUnregistered}),
 			tests: []rpc{
-				{server: bob, method: "Hello", authErr: `caveat.PeerIdentity{"google"} forbids RPCing with peer`},
+				{server: bob, method: "Play", authErr: "caveat bytes could not be VOM-decoded"},
+				{server: bob, method: "Hello", authErr: "caveat bytes could not be VOM-decoded"},
+				{server: googleChain.PublicID(), method: "Play", authErr: "caveat bytes could not be VOM-decoded"},
+				{server: googleChain.PublicID(), method: "Hello", authErr: "caveat bytes could not be VOM-decoded"},
+			},
+		},
+		{
+			client: bless(cAlice, veyronChain, "alice", append(cavOnlyGoogle, cavOnlyPlay...)),
+			tests: []rpc{
+				{server: bob, method: "Hello", authErr: `caveat.PeerBlessings{"google"} forbids RPCing with peer`},
+				{server: bob, method: "Play", authErr: `caveat.PeerBlessings{"google"} forbids RPCing with peer`},
 				{server: googleChain.PublicID(), method: "Hello", authErr: `caveat.MethodRestriction{"Play"} forbids invocation of method Hello`},
 				{server: googleChain.PublicID(), method: "Play", authNames: S{"veyron/alice"}},
 			},
 		},
 		{
-			client: bless(cAlice, veyronChain, "alice", cavOnlyPublicProfile),
+			client: bless(cAlice, veyronChain, "alice", append(cavOnlyGoogle, cavUnregistered)),
 			tests: []rpc{
-				{server: cVeyronAliceTV, method: "PrivateProfile", authErr: `caveat.MethodRestriction{"PublicProfile"} forbids invocation of method PrivateProfile`},
-				{server: cVeyronAliceTV, method: "PublicProfile", authNames: S{"veyron/alice"}},
+				{server: googleChain.PublicID(), method: "Play", authErr: "caveat bytes could not be VOM-decoded"},
+				{server: googleChain.PublicID(), method: "Hello", authErr: "caveat bytes could not be VOM-decoded"},
 			},
 		},
 		// client has multiple blessings
 		{
-			client: newSetPublicID(bless(cAlice, veyronChain, "valice", append(cavOnlyPlayAtGoogle, cavOnlyPublicProfile...)), bless(cAlice, googleChain, "galice", cavOnlyGoogle)),
+			client: newSetPublicID(bless(cAlice, veyronChain, "valice", append(cavOnlyPlay, cavUnregistered)), bless(cAlice, googleChain, "galice", cavOnlyGoogle)),
 			tests: []rpc{
-				{server: bob, method: "Hello", authNames: S{"veyron/valice"}},
-				{server: googleChain.PublicID(), method: "Play", authNames: S{"veyron/valice", "google/galice"}},
-				{server: googleChain.PublicID(), method: "Buy", authNames: S{"google/galice"}},
-				{server: cVeyronAliceTV, method: "PublicProfile", authNames: S{"veyron/valice"}},
-				{server: cVeyronAliceTV, method: "PrivateProfile", authErr: "none of the blessings in the set are authorized"},
+				{server: bob, method: "Hello", authErr: "none of the blessings in the set are authorized"},
+				{server: bob, method: "Play", authErr: "none of the blessings in the set are authorized"},
+				{server: googleChain.PublicID(), method: "Hello", authNames: S{"google/galice"}},
+				{server: googleChain.PublicID(), method: "Play", authNames: S{"google/galice"}},
 			},
 		},
 	}
@@ -382,15 +436,18 @@
 		}
 		for _, test := range d.tests {
 			if (len(test.authNames) == 0) == (len(test.authErr) == 0) {
-				t.Fatalf("Bad testdata. Exactly one of authNames and authErr must be non-empty: %+q/%+v", d.client, test)
+				t.Errorf("Bad testdata. Exactly one of authNames and authErr must be non-empty: %+q/%+v", d.client, test)
+				continue
 			}
 			ctx := NewContext(ContextArgs{LocalID: test.server, RemoteID: d.client, Method: test.method})
 			authID, err := d.client.Authorize(ctx)
 			if !matchesErrorPattern(err, test.authErr) {
 				t.Errorf("%q.Authorize(%v) returned error: %v, want to match: %q", d.client, ctx, err, test.authErr)
+				continue
 			}
 			if err := verifyAuthorizedID(d.client, authID, test.authNames); err != nil {
 				t.Errorf("%q.Authorize(%v) returned identity: %v want identity with names: %q [%v]", d.client, ctx, authID, test.authNames, err)
+				continue
 			}
 		}
 	}
@@ -416,9 +473,9 @@
 
 func TestThirdPartyCaveatMinting(t *testing.T) {
 	minter := newChain("minter")
-	cav, err := caveat.NewPublicKeyCaveat(proximityCaveat{}, minter.PublicID(), "location", security.ThirdPartyRequirements{})
+	cav, err := caveat.NewPublicKeyCaveat(newCaveat(proximityCaveat{})[0], minter.PublicID().PublicKey(), "location", security.ThirdPartyRequirements{})
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("security.NewPublicKeyCaveat failed: %s", err)
 	}
 
 	discharge, err := minter.MintDischarge(cav, NewContext(ContextArgs{}), time.Hour, nil)
@@ -432,7 +489,7 @@
 	}
 
 	ctxValidateMinting := NewContext(ContextArgs{
-		Discharges: security.CaveatDischargeMap{discharge.CaveatID(): discharge},
+		Discharges: dischargeMap{discharge.ID(): discharge},
 		Debug:      "ctxValidateMinting",
 	})
 	if err = cav.Validate(ctxValidateMinting); err != nil {
@@ -447,12 +504,12 @@
 	mkgoogle := func(id security.PrivateID, name string) security.PrivateID {
 		return derive(bless(id.PublicID(), googleChain, name, nil), id)
 	}
-	mkcaveat := func(id security.PrivateID) []security.ServiceCaveat {
-		c, err := caveat.NewPublicKeyCaveat(alwaysValidCaveat{}, id.PublicID(), fmt.Sprintf("%v location", id.PublicID()), security.ThirdPartyRequirements{})
+	mkTPCaveat := func(id security.PrivateID) security.ThirdPartyCaveat {
+		c, err := caveat.NewPublicKeyCaveat(newCaveat(alwaysValidCaveat{})[0], id.PublicID().PublicKey(), fmt.Sprintf("%v location", id.PublicID()), security.ThirdPartyRequirements{})
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("NewPublicKeyCaveat with PublicKey of: %v failed: %s", id, err)
 		}
-		return []security.ServiceCaveat{caveat.UniversalCaveat(c)}
+		return c
 	}
 	var (
 		alice = newChain("alice")
@@ -460,12 +517,12 @@
 		carol = newChain("carol").PublicID()
 
 		// aliceProximityCaveat is a caveat whose discharge can only be minted by alice.
-		aliceProximityCaveat = mkcaveat(alice)
-		bobProximityCaveat   = mkcaveat(bob)
+		aliceProximityCaveat = mkTPCaveat(alice)
+		bobProximityCaveat   = mkTPCaveat(bob)
 	)
 
-	mintDischarge := func(id security.PrivateID, duration time.Duration, caveats []security.ServiceCaveat) security.ThirdPartyDischarge {
-		d, err := id.MintDischarge(aliceProximityCaveat[0].Caveat.(security.ThirdPartyCaveat), nil, duration, caveats)
+	mintDischarge := func(id security.PrivateID, duration time.Duration, caveats []security.Caveat) security.Discharge {
+		d, err := id.MintDischarge(aliceProximityCaveat.(security.ThirdPartyCaveat), nil, duration, caveats)
 		if err != nil {
 			t.Fatalf("%q.MintDischarge failed: %v", id, err)
 		}
@@ -481,27 +538,27 @@
 		// Contexts
 		ctxEmpty = NewContext(ContextArgs{Debug: "ctxEmpty"})
 		ctxAlice = NewContext(ContextArgs{
-			Discharges: security.CaveatDischargeMap{dAlice.CaveatID(): dAlice},
+			Discharges: dischargeMap{dAlice.ID(): dAlice},
 			Debug:      "ctxAlice",
 		})
 		// Context containing the discharge dGoogle but the server is not a Google server, so
 		// the service caveat is not satisfied
 		ctxGoogleAtOther = NewContext(ContextArgs{
-			Discharges: security.CaveatDischargeMap{dGoogle.CaveatID(): dGoogle},
+			Discharges: dischargeMap{dGoogle.ID(): dGoogle},
 			Debug:      "ctxGoogleAtOther",
 		})
 		// Context containing the discharge dGoogle at a google server.
 		ctxGoogleAtGoogle = NewContext(ContextArgs{
-			Discharges: security.CaveatDischargeMap{dGoogle.CaveatID(): dGoogle},
+			Discharges: dischargeMap{dGoogle.ID(): dGoogle},
 			LocalID:    googleChain.PublicID(),
 			Debug:      "ctxGoogleAtGoogle",
 		})
 		ctxExpired = NewContext(ContextArgs{
-			Discharges: security.CaveatDischargeMap{dExpired.CaveatID(): dExpired},
+			Discharges: dischargeMap{dExpired.ID(): dExpired},
 			Debug:      "ctxExpired",
 		})
 		ctxInvalid = NewContext(ContextArgs{
-			Discharges: security.CaveatDischargeMap{dInvalid.CaveatID(): dInvalid},
+			Discharges: dischargeMap{dInvalid.ID(): dInvalid},
 			Debug:      "ctxInvalid",
 		})
 
@@ -520,20 +577,20 @@
 	}{
 		// carol blessed by bob with the third-party caveat should be authorized when the context contains a valid discharge
 		{
-			id:        bless(carol, mkveyron(bob, "bob"), "friend", aliceProximityCaveat),
+			id:        bless(carol, mkveyron(bob, "bob"), "friend", newCaveat(aliceProximityCaveat)),
 			authNames: S{"veyron/bob/friend"},
 		},
 		// veyron/vbob/vfriend with bobProximityCaveat and google/gbob/gfriend with aliceProximityCaveat
 		// Only google/gbob/gfriend should be authorized since the discharge for the former is missing
 		{
 			id: newSetPublicID(
-				bless(carol, mkveyron(bob, "vbob"), "vfriend", bobProximityCaveat),
-				bless(carol, mkgoogle(bob, "gbob"), "gfriend", aliceProximityCaveat)),
+				bless(carol, mkveyron(bob, "vbob"), "vfriend", newCaveat(bobProximityCaveat)),
+				bless(carol, mkgoogle(bob, "gbob"), "gfriend", newCaveat(aliceProximityCaveat))),
 			authNames: S{"google/gbob/gfriend"},
 		},
 		// veyron/vbob/friend#google/gbob/friend both have the same caveat and both are satisfied
 		{
-			id:        bless(carol, newSetPrivateID(mkveyron(bob, "vbob"), mkgoogle(bob, "gbob")), "friend", aliceProximityCaveat),
+			id:        bless(carol, newSetPrivateID(mkveyron(bob, "vbob"), mkgoogle(bob, "gbob")), "friend", newCaveat(aliceProximityCaveat)),
 			authNames: S{"veyron/vbob/friend", "google/gbob/friend"},
 		},
 	}
@@ -559,33 +616,39 @@
 	}
 }
 
-type SortedThirdPartyCaveats []security.ServiceCaveat
+type SortedThirdPartyCaveats []security.ThirdPartyCaveat
 
 func (s SortedThirdPartyCaveats) Len() int { return len(s) }
 func (s SortedThirdPartyCaveats) Less(i, j int) bool {
-	return s[i].Caveat.(security.ThirdPartyCaveat).ID() < s[j].Caveat.(security.ThirdPartyCaveat).ID()
+	return s[i].ID() < s[j].ID()
 }
 func (s SortedThirdPartyCaveats) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 
 func TestThirdPartyCaveatAccessors(t *testing.T) {
 	mkTPCaveat := func(id security.PublicID) security.ThirdPartyCaveat {
-		tpCav, err := caveat.NewPublicKeyCaveat(alwaysValidCaveat{}, id, "someLocation", security.ThirdPartyRequirements{})
+		tpCav, err := caveat.NewPublicKeyCaveat(newCaveat(alwaysValidCaveat{})[0], id.PublicKey(), "someLocation", security.ThirdPartyRequirements{})
 		if err != nil {
-			t.Fatalf("NewPublicKeyCaveat(%q, ...) failed: %v", id, err)
+			t.Fatalf("NewPublicKeyCaveat with PublicKey of: %v failed: %s", id, err)
 		}
 		return tpCav
 	}
-	mintDischarge := func(caveat security.ThirdPartyCaveat, id security.PrivateID, caveats []security.ServiceCaveat) security.ThirdPartyDischarge {
+	mintDischarge := func(caveat security.ThirdPartyCaveat, id security.PrivateID, caveats []security.Caveat) security.Discharge {
 		d, err := id.MintDischarge(caveat, nil, time.Minute, caveats)
 		if err != nil {
 			t.Fatalf("%q.MintDischarge failed: %v", id, err)
 		}
 		return d
 	}
-
-	sortTPCaveats := func(c []security.ServiceCaveat) []security.ServiceCaveat {
-		sort.Stable(SortedThirdPartyCaveats(c))
-		return c
+	sortTPCaveats := func(caveats []security.ThirdPartyCaveat) []security.ThirdPartyCaveat {
+		sort.Stable(SortedThirdPartyCaveats(caveats))
+		return caveats
+	}
+	validators := func(caveats []security.ThirdPartyCaveat) []security.CaveatValidator {
+		vals := make([]security.CaveatValidator, len(caveats))
+		for i, cav := range caveats {
+			vals[i] = cav.(security.CaveatValidator)
+		}
+		return vals
 	}
 
 	var (
@@ -597,20 +660,20 @@
 		sBob        = newSetPrivateID(cBob, cBobBuilder).(setPrivateID)
 
 		// Caveats
-		tpCavService   = security.ServiceCaveat{Service: "someService", Caveat: mkTPCaveat(alice.PublicID())}
-		tpCavUniversal = caveat.UniversalCaveat(mkTPCaveat(alice.PublicID()))
-		cav            = methodRestrictionCaveat("someService", nil)[0]
+		tpCavAlice = mkTPCaveat(alice.PublicID())
+		tpCavBob   = mkTPCaveat(alice.PublicID())
+		cav        = caveat.MethodRestriction(nil)
 	)
 
 	caveats := []struct {
-		firstparty []security.ServiceCaveat
-		thirdparty []security.ServiceCaveat
+		firstparty []security.CaveatValidator
+		thirdparty []security.ThirdPartyCaveat
 	}{
 		{firstparty: nil, thirdparty: nil},
-		{firstparty: []security.ServiceCaveat{cav}},
-		{thirdparty: []security.ServiceCaveat{tpCavService}},
-		{thirdparty: []security.ServiceCaveat{tpCavService, tpCavUniversal}},
-		{firstparty: []security.ServiceCaveat{cav}, thirdparty: []security.ServiceCaveat{tpCavService, tpCavUniversal}},
+		{firstparty: []security.CaveatValidator{cav}},
+		{thirdparty: []security.ThirdPartyCaveat{tpCavAlice}},
+		{thirdparty: []security.ThirdPartyCaveat{tpCavAlice, tpCavBob}},
+		{firstparty: []security.CaveatValidator{cav}, thirdparty: []security.ThirdPartyCaveat{tpCavAlice, tpCavBob}},
 	}
 	testdata := []struct {
 		privID security.PrivateID
@@ -623,14 +686,14 @@
 	}
 	for _, d := range testdata {
 		for _, c := range caveats {
-			all := append(c.firstparty, c.thirdparty...)
+			all := append(newCaveat(c.firstparty...), newCaveat(validators(c.thirdparty)...)...)
 			// Test ThirdPartyCaveat accessors on security.PublicIDs.
 			id := bless(d.pubID, d.privID, "irrelevant", all)
 			want := sortTPCaveats(c.thirdparty)
 			if got := sortTPCaveats(id.ThirdPartyCaveats()); !reflect.DeepEqual(got, want) {
 				t.Errorf("%q(%T) got ThirdPartyCaveats() = %+v, want %+v", id, id, got, want)
 			}
-			// Test ThirdPartyCaveat accessors on security.ThirdPartyCaveatDischarges.
+			// Test ThirdPartyCaveat accessors on security.ThirdPartyCaveat discharges.
 			dis := mintDischarge(mkTPCaveat(alice.PublicID()), d.privID, all)
 			if got := sortTPCaveats(dis.ThirdPartyCaveats()); !reflect.DeepEqual(got, want) {
 				t.Errorf("%q got ThirdPartyCaveats() = %+v, want %+v", dis, got, want)
@@ -780,6 +843,8 @@
 }
 
 func init() {
+	blackbox.CommandTable["encodeUnregisteredCaveat"] = encodeUnregisteredCaveat
+
 	vom.Register(alwaysValidCaveat{})
 	vom.Register(proximityCaveat{})
 }
diff --git a/runtimes/google/security/util.go b/runtimes/google/security/util.go
index b4fb38d..8391ab3 100644
--- a/runtimes/google/security/util.go
+++ b/runtimes/google/security/util.go
@@ -34,7 +34,7 @@
 	LocalID, RemoteID security.PublicID
 	// Discharges is the set of third-party caveat discharges for the identity at the remote end
 	// of the request.
-	Discharges security.CaveatDischargeMap
+	Discharges map[string]security.Discharge
 	// Debug describes the context for debugging purposes.
 	Debug string
 	// The following fields must be set only for contexts created at the server receiving the IPC.
@@ -86,21 +86,21 @@
 		buf.WriteString(fmt.Sprintf(" Label:%v", c.Label()))
 	}
 	if len(c.ContextArgs.Discharges) > 0 {
-		buf.WriteString(fmt.Sprintf(" #Discharges:%d", len(c.Discharges)))
+		buf.WriteString(fmt.Sprintf(" #Discharges:%d", len(c.Discharges())))
 	}
 	buf.WriteString(" }")
 	return buf.String()
 }
 
-func (c *context) Method() string                                { return c.ContextArgs.Method }
-func (c *context) Name() string                                  { return c.ContextArgs.Name }
-func (c *context) Suffix() string                                { return c.ContextArgs.Suffix }
-func (c *context) Label() security.Label                         { return c.ContextArgs.Label }
-func (c *context) CaveatDischarges() security.CaveatDischargeMap { return c.ContextArgs.Discharges }
-func (c *context) LocalID() security.PublicID                    { return c.ContextArgs.LocalID }
-func (c *context) RemoteID() security.PublicID                   { return c.ContextArgs.RemoteID }
-func (c *context) LocalEndpoint() naming.Endpoint                { return c.ContextArgs.LocalEndpoint }
-func (c *context) RemoteEndpoint() naming.Endpoint               { return c.ContextArgs.RemoteEndpoint }
+func (c *context) Method() string                            { return c.ContextArgs.Method }
+func (c *context) Name() string                              { return c.ContextArgs.Name }
+func (c *context) Suffix() string                            { return c.ContextArgs.Suffix }
+func (c *context) Label() security.Label                     { return c.ContextArgs.Label }
+func (c *context) Discharges() map[string]security.Discharge { return c.ContextArgs.Discharges }
+func (c *context) LocalID() security.PublicID                { return c.ContextArgs.LocalID }
+func (c *context) RemoteID() security.PublicID               { return c.ContextArgs.RemoteID }
+func (c *context) LocalEndpoint() naming.Endpoint            { return c.ContextArgs.LocalEndpoint }
+func (c *context) RemoteEndpoint() naming.Endpoint           { return c.ContextArgs.RemoteEndpoint }
 
 // NewContext returns a new security.Context for the provided method, name,
 // suffix, discharges, label and identities of the local and remote principals
diff --git a/runtimes/google/security/util_test.go b/runtimes/google/security/util_test.go
index 7cfb9db..9bdfbdb 100644
--- a/runtimes/google/security/util_test.go
+++ b/runtimes/google/security/util_test.go
@@ -22,6 +22,8 @@
 	googleChain = newChain("google").(*chainPrivateID)
 )
 
+type dischargeMap map[string]security.Discharge
+
 func matchesErrorPattern(err error, pattern string) bool {
 	if (len(pattern) == 0) != (err == nil) {
 		return false
@@ -73,7 +75,7 @@
 	return id
 }
 
-func bless(blessee security.PublicID, blessor security.PrivateID, name string, caveats []security.ServiceCaveat) security.PublicID {
+func bless(blessee security.PublicID, blessor security.PrivateID, name string, caveats []security.Caveat) security.PublicID {
 	blessed, err := blessor.Bless(blessee, name, 5*time.Minute, caveats)
 	if err != nil {
 		panic(err)
@@ -109,14 +111,23 @@
 	return nil
 }
 
-func methodRestrictionCaveat(service security.BlessingPattern, methods []string) []security.ServiceCaveat {
-	return []security.ServiceCaveat{
-		{Service: service, Caveat: caveat.MethodRestriction(methods)},
+func newCaveat(validators ...security.CaveatValidator) []security.Caveat {
+	cavs := make([]security.Caveat, len(validators))
+	var err error
+	for i, v := range validators {
+		if cavs[i], err = security.NewCaveat(v); err != nil {
+			panic(err)
+		}
 	}
+	return cavs
 }
 
-func peerIdentityCaveat(p security.BlessingPattern) []security.ServiceCaveat {
-	return []security.ServiceCaveat{caveat.UniversalCaveat(caveat.PeerIdentity{p})}
+func methodRestrictionCaveat(methods []string) []security.Caveat {
+	return newCaveat(caveat.MethodRestriction(methods))
+}
+
+func peerIdentityCaveat(p security.BlessingPattern) []security.Caveat {
+	return newCaveat(caveat.PeerBlessings{p})
 }
 
 func init() {
diff --git a/security/acl_authorizer_test.go b/security/acl_authorizer_test.go
index 1d04e89..17573c3 100644
--- a/security/acl_authorizer_test.go
+++ b/security/acl_authorizer_test.go
@@ -16,20 +16,20 @@
 // context implements Context.
 type context struct {
 	localID, remoteID    security.PublicID
-	discharges           security.CaveatDischargeMap
+	discharges           map[string]security.Discharge
 	method, name, suffix string
 	label                security.Label
 }
 
-func (c *context) Method() string                                { return c.method }
-func (c *context) Name() string                                  { return c.name }
-func (c *context) Suffix() string                                { return c.suffix }
-func (c *context) Label() security.Label                         { return c.label }
-func (c *context) CaveatDischarges() security.CaveatDischargeMap { return c.discharges }
-func (c *context) LocalID() security.PublicID                    { return c.localID }
-func (c *context) RemoteID() security.PublicID                   { return c.remoteID }
-func (c *context) LocalEndpoint() naming.Endpoint                { return nil }
-func (c *context) RemoteEndpoint() naming.Endpoint               { return nil }
+func (c *context) Method() string                            { return c.method }
+func (c *context) Name() string                              { return c.name }
+func (c *context) Suffix() string                            { return c.suffix }
+func (c *context) Label() security.Label                     { return c.label }
+func (c *context) Discharges() map[string]security.Discharge { return c.discharges }
+func (c *context) LocalID() security.PublicID                { return c.localID }
+func (c *context) RemoteID() security.PublicID               { return c.remoteID }
+func (c *context) LocalEndpoint() naming.Endpoint            { return nil }
+func (c *context) RemoteEndpoint() naming.Endpoint           { return nil }
 
 func saveACLToTempFile(acl security.ACL) string {
 	f, err := ioutil.TempFile("", "saved_acl")
diff --git a/security/audit/id.go b/security/audit/id.go
index 779cc40..a56700a 100644
--- a/security/audit/id.go
+++ b/security/audit/id.go
@@ -37,7 +37,7 @@
 	return id.id.PublicID()
 }
 
-func (id *auditingID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.ServiceCaveat) (security.PublicID, error) {
+func (id *auditingID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.Caveat) (security.PublicID, error) {
 	blessed, err := id.id.Bless(blessee, blessingName, duration, caveats)
 	if err = id.audit(err, "Bless", args{blessee, blessingName, duration, caveats}, blessed); err != nil {
 		return nil, err
@@ -57,7 +57,7 @@
 	return NewPrivateID(derived, id.auditor), nil
 }
 
-func (id *auditingID) MintDischarge(caveat security.ThirdPartyCaveat, context security.Context, duration time.Duration, caveats []security.ServiceCaveat) (security.ThirdPartyDischarge, error) {
+func (id *auditingID) MintDischarge(caveat security.ThirdPartyCaveat, context security.Context, duration time.Duration, caveats []security.Caveat) (security.Discharge, error) {
 	d, err := id.id.MintDischarge(caveat, context, duration, caveats)
 	if err = id.audit(err, "MintDischarge", args{caveat, context, duration, caveats}, nil); err != nil {
 		return nil, err
diff --git a/security/audit/id_test.go b/security/audit/id_test.go
index e8f67e9..a0f9304 100644
--- a/security/audit/id_test.go
+++ b/security/audit/id_test.go
@@ -22,7 +22,7 @@
 		publicID         = security.FakePublicID("publicid")
 		str              string
 		duration         time.Duration
-		caveats          []security.ServiceCaveat
+		caveats          []security.Caveat
 		thirdPartyCaveat thirdPartyCaveat
 		context          context
 
@@ -190,7 +190,7 @@
 	}
 	return id.NextResult.(security.PublicID)
 }
-func (id *mockID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.ServiceCaveat) (security.PublicID, error) {
+func (id *mockID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.Caveat) (security.PublicID, error) {
 	defer id.reset()
 	result, _ := id.NextResult.(security.PublicID)
 	return result, id.NextError
@@ -200,9 +200,9 @@
 	result, _ := id.NextResult.(security.PrivateID)
 	return result, id.NextError
 }
-func (id *mockID) MintDischarge(caveat security.ThirdPartyCaveat, context security.Context, duration time.Duration, caveats []security.ServiceCaveat) (security.ThirdPartyDischarge, error) {
+func (id *mockID) MintDischarge(caveat security.ThirdPartyCaveat, context security.Context, duration time.Duration, caveats []security.Caveat) (security.Discharge, error) {
 	defer id.reset()
-	result, _ := id.NextResult.(security.ThirdPartyDischarge)
+	result, _ := id.NextResult.(security.Discharge)
 	return result, id.NextError
 }
 
@@ -240,7 +240,7 @@
 type thirdPartyCaveat struct{}
 
 func (thirdPartyCaveat) Validate(security.Context) error { return nil }
-func (thirdPartyCaveat) ID() security.ThirdPartyCaveatID { return "thirdPartyCaveatID" }
+func (thirdPartyCaveat) ID() string                      { return "thirdPartyCaveatID" }
 func (thirdPartyCaveat) Location() string                { return "thirdPartyCaveatLocation" }
 func (thirdPartyCaveat) Requirements() security.ThirdPartyRequirements {
 	return security.ThirdPartyRequirements{}
@@ -249,21 +249,21 @@
 // context implements security.Context
 type context struct{}
 
-func (context) Method() string                                { return "method" }
-func (context) Name() string                                  { return "name" }
-func (context) Suffix() string                                { return "suffix" }
-func (context) Label() security.Label                         { return security.ReadLabel }
-func (context) CaveatDischarges() security.CaveatDischargeMap { return nil }
-func (context) LocalID() security.PublicID                    { return nil }
-func (context) RemoteID() security.PublicID                   { return nil }
-func (context) LocalEndpoint() naming.Endpoint                { return nil }
-func (context) RemoteEndpoint() naming.Endpoint               { return nil }
+func (context) Method() string                            { return "method" }
+func (context) Name() string                              { return "name" }
+func (context) Suffix() string                            { return "suffix" }
+func (context) Label() security.Label                     { return security.ReadLabel }
+func (context) Discharges() map[string]security.Discharge { return nil }
+func (context) LocalID() security.PublicID                { return nil }
+func (context) RemoteID() security.PublicID               { return nil }
+func (context) LocalEndpoint() naming.Endpoint            { return nil }
+func (context) RemoteEndpoint() naming.Endpoint           { return nil }
 
-// discharge implements the security.ThirdPartyDischarge interface
+// discharge implements the security.Discharge interface
 type discharge struct{}
 
-func (*discharge) CaveatID() security.ThirdPartyCaveatID       { return "thirdPartyCaveatID" }
-func (*discharge) ThirdPartyCaveats() []security.ServiceCaveat { return nil }
+func (*discharge) ID() string                                     { return "thirdPartyCaveatID" }
+func (*discharge) ThirdPartyCaveats() []security.ThirdPartyCaveat { return nil }
 
 func call(receiver interface{}, method string, args V) (results []interface{}, err interface{}) {
 	defer func() {
diff --git a/security/caveat/caveat.go b/security/caveat/caveat.go
index a008381..47b136e 100644
--- a/security/caveat/caveat.go
+++ b/security/caveat/caveat.go
@@ -9,75 +9,72 @@
 	"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.
+// Expiry is a security.CaveatValidator that restricts the validity period of
+// credentials bearing a security.Caveat constructed from this validator.
 type Expiry struct {
+	// TODO(ataly,ashankar): Get rid of IssueTime from this caveat.
 	IssueTime  time.Time
 	ExpiryTime time.Time
 }
 
-func (c *Expiry) Validate(context security.Context) error {
+func (v *Expiry) Validate(context security.Context) error {
 	now := time.Now()
-	if now.Before(c.IssueTime) || now.After(c.ExpiryTime) {
-		return fmt.Errorf("%#v forbids credential from being used at this time(%v)", c, now)
+	if now.Before(v.IssueTime) || now.After(v.ExpiryTime) {
+		return fmt.Errorf("%#v forbids credential from being used at this time(%v)", v, now)
 	}
 	return nil
 }
 
-// MethodRestriction is a security.Caveat that restricts the set of
-// methods that can be invoked by a credential bearing the caveat.
+// MethodRestriction is a security.CaveatValidator that restricts the set of
+// methods that are authorized via credentials bearing a security.Caveat
+// constructed from this validator.
 // An empty set indicates that no methods can be invoked.
 type MethodRestriction []string
 
-func (c MethodRestriction) Validate(ctx security.Context) error {
+func (v MethodRestriction) Validate(ctx security.Context) error {
 	// If the context has an empty Method then the caveat validates.
 	if ctx.Method() == "" {
 		return nil
 	}
-	for _, m := range c {
+	for _, m := range v {
 		if m == ctx.Method() {
 			return nil
 		}
 	}
-	return fmt.Errorf("%#v forbids invocation of method %s", c, ctx.Method())
+	return fmt.Errorf("%#v forbids invocation of method %s", v, ctx.Method())
 }
 
-// PeerIdentity is a security.Caveat that restricts the bearer of a credential
-// with this caveat from making or receiving RPCs to a limited set of peers -
-// those whose identities match one of the provided security.BlessingPatterns.
+// PeerBlessings is a security.CaveatValidator that restricts a credential
+// bearing a security.Caveat constructed from this validator to be used for
+// communicating with a limited set of peers - those who have blessings matching
+// one of the provided security.BlessingPatterns.
 // An empty set indicates that no peers can be communicated with.
-type PeerIdentity []security.BlessingPattern
+type PeerBlessings []security.BlessingPattern
 
-// Validate checks that the identity of the peer is present on the set of services
-// identified by the BlessingPatterns on the caveat.
-func (c PeerIdentity) Validate(ctx security.Context) error {
-	for _, p := range c {
+func (v PeerBlessings) Validate(ctx security.Context) error {
+	for _, p := range v {
 		if ctx.LocalID() != nil && p.MatchedBy(ctx.LocalID().Names()...) {
 			return nil
 		}
 	}
-	return fmt.Errorf("%#v forbids RPCing with peer %s", c, ctx.LocalID())
+	return fmt.Errorf("%#v forbids RPCing with peer %s", v, ctx.LocalID())
 }
 
-// NetworkType is a security.Caveat that restricts communication with the
-// remote process to a particular network ("tcp", "udp", "bluetooth" etc.)
+// NetworkType is a security.CaveatValidator that restricts a credential bearing
+// a security.Caveat constructed from this validator to be used only for communicating over
+// a particular network ("tcp", "udp", "bluetooth" etc.)
 type NetworkType string
 
-func (cav NetworkType) Validate(ctx security.Context) error {
-	if ctx.RemoteEndpoint().Addr().Network() == string(cav) {
+func (v NetworkType) Validate(ctx security.Context) error {
+	if ctx.RemoteEndpoint().Addr().Network() == string(v) {
 		return nil
 	}
-	return fmt.Errorf("required network type %q, got %q", cav, ctx.RemoteEndpoint().Addr().Network())
+	return fmt.Errorf("required network type %q, got %q", v, ctx.RemoteEndpoint().Addr().Network())
 }
 
 func init() {
 	vom.Register(Expiry{})
 	vom.Register(MethodRestriction(nil))
-	vom.Register(PeerIdentity(nil))
+	vom.Register(PeerBlessings(nil))
 	vom.Register(NetworkType(""))
 }
diff --git a/security/caveat/caveat_test.go b/security/caveat/caveat_test.go
index b4f44f8..301491a 100644
--- a/security/caveat/caveat_test.go
+++ b/security/caveat/caveat_test.go
@@ -24,15 +24,15 @@
 	method                        string
 }
 
-func (c *context) Method() string                                { return c.method }
-func (c *context) Name() string                                  { return "some_name" }
-func (c *context) Suffix() string                                { return "some_suffix" }
-func (c *context) Label() security.Label                         { return security.AdminLabel }
-func (c *context) CaveatDischarges() security.CaveatDischargeMap { return nil }
-func (c *context) LocalID() security.PublicID                    { return c.local }
-func (c *context) RemoteID() security.PublicID                   { return c.remote }
-func (c *context) LocalEndpoint() naming.Endpoint                { return &c.localEndpoint }
-func (c *context) RemoteEndpoint() naming.Endpoint               { return &c.remoteEndpoint }
+func (c *context) Method() string                            { return c.method }
+func (c *context) Name() string                              { return "some_name" }
+func (c *context) Suffix() string                            { return "some_suffix" }
+func (c *context) Label() security.Label                     { return security.AdminLabel }
+func (c *context) Discharges() map[string]security.Discharge { return nil }
+func (c *context) LocalID() security.PublicID                { return c.local }
+func (c *context) RemoteID() security.PublicID               { return c.remote }
+func (c *context) LocalEndpoint() naming.Endpoint            { return &c.localEndpoint }
+func (c *context) RemoteEndpoint() naming.Endpoint           { return &c.remoteEndpoint }
 
 func TestCaveats(t *testing.T) {
 	var (
@@ -41,7 +41,7 @@
 	)
 	now := time.Now()
 	tests := []struct {
-		c  security.Caveat
+		c  security.CaveatValidator
 		ok bool
 	}{
 		{&caveat.Expiry{IssueTime: now, ExpiryTime: now.Add(time.Hour)}, true},
@@ -51,10 +51,10 @@
 		{caveat.NetworkType("tcp"), true},
 		{caveat.MethodRestriction{"Pause", "Play"}, true},
 		{caveat.MethodRestriction{"List"}, false},
-		{caveat.PeerIdentity(nil), false},
-		{caveat.PeerIdentity{"fake/alice"}, true},
-		{caveat.PeerIdentity{"fake/carol"}, false},
-		{caveat.PeerIdentity{"fake/alice", "fake/carol"}, true},
+		{caveat.PeerBlessings(nil), false},
+		{caveat.PeerBlessings{"fake/alice"}, true},
+		{caveat.PeerBlessings{"fake/carol"}, false},
+		{caveat.PeerBlessings{"fake/alice", "fake/carol"}, true},
 	}
 	ctx := &context{local: alice, remote: bob, method: "Play", remoteEndpoint: endpoint{addr: &net.TCPAddr{}}}
 	for _, test := range tests {
diff --git a/security/caveat/public_key_caveat.go b/security/caveat/public_key_caveat.go
index 30cbf74..5b4884b 100644
--- a/security/caveat/public_key_caveat.go
+++ b/security/caveat/public_key_caveat.go
@@ -1,13 +1,15 @@
 package caveat
 
 import (
-	"bytes"
+	"crypto/ecdsa"
 	"crypto/rand"
 	"crypto/sha256"
 	"encoding/binary"
 	"fmt"
 	"time"
 
+	vsecurity "veyron/security"
+
 	"veyron2/security"
 	"veyron2/security/wire"
 	"veyron2/vom"
@@ -22,30 +24,22 @@
 // Can we use 4bytes instead?.
 const nonceLength = 16
 
-// errPublicKeyCaveat returns an error indicating that the provided caveat has
-// an invalid or missing discharge.
-func errPublicKeyCaveat(c *publicKeyCaveat, err error) error {
-	return fmt.Errorf("%v for publicKeyCaveat{nonce:%v location:%q}", err, c.RandNonce, c.Location())
-}
-
 // publicKeyCaveat implements security.ThirdPartyCaveat. It specifies a restriction,
-// a validation key and the location of the third-party responsible for
-// discharging the caveat. A discharge for this caveat is a signed assertion whose
+// a validation key and the location (object name) of the third-party responsible
+// for discharging the caveat. A discharge for this caveat is a signed assertion whose
 // signature can be verified using the validation key.
 type publicKeyCaveat struct {
 	// RandNonce specifies a cryptographically random nonce (of fixed length) that
 	// uniquely identifies the caveat.
 	RandNonce []uint8
 	// DischargeMintingCaveat specifies the caveat that has to be validated
-	// before minting a discharge for a publicKeyCaveat. A byte slice containing
-	// VOM-encoded security.Caveat is used to enable a publicKeyCaveat to be
-	// validated by devices that cannot decode the discharge minting caveats.
+	// before minting a discharge for a publicKeyCaveat.
 	DischargeMintingCaveat []byte
 	// ValidationKey specifies the public key of the discharging-party.
 	ValidationKey wire.PublicKey
 	// ThirdPartyLocation specifies the object name of the discharging-party.
 	ThirdPartyLocation string
-	// Information wanted in order to issue a discharge.
+	// ThirdPartyRequirements specify the information wanted in order to issue a discharge.
 	ThirdPartyRequirements security.ThirdPartyRequirements
 }
 
@@ -54,11 +48,10 @@
 //
 // TODO(ataly, ashankar): A 256bit hash is probably much stronger that what we need
 // here. Can we truncate the hash to 96bits?
-func (c *publicKeyCaveat) ID() security.ThirdPartyCaveatID {
-	return security.ThirdPartyCaveatID(id(c.RandNonce, c.DischargeMintingCaveat))
+func (c *publicKeyCaveat) ID() string {
+	return id(c.RandNonce, c.DischargeMintingCaveat)
 }
 
-// Location returns the third-party location embedded in the caveat.
 func (c *publicKeyCaveat) Location() string {
 	return c.ThirdPartyLocation
 }
@@ -71,67 +64,67 @@
 	return c.ThirdPartyRequirements
 }
 
-// Validate verifies whether the caveat validates for the provided context.
 func (c *publicKeyCaveat) Validate(ctx security.Context) error {
 	// Check whether the context has a dicharge matching the caveat's ID.
-	dis, ok := ctx.CaveatDischarges()[c.ID()]
+	dis, ok := ctx.Discharges()[c.ID()]
 	if !ok {
-		return errPublicKeyCaveat(c, fmt.Errorf("missing discharge"))
+		return fmt.Errorf("missing discharge")
 	}
 
 	pkDischarge, ok := dis.(*publicKeyDischarge)
 	if !ok {
-		return errPublicKeyCaveat(c, fmt.Errorf("caveat of type %T cannot be validated with discharge of type %T", c, dis))
+		return fmt.Errorf("caveat of type %T cannot be validated with discharge of type %T", c, dis)
 	}
 
 	// Validate all caveats present on the discharge.
-	for _, cav := range pkDischarge.Caveats {
-		if err := cav.Validate(ctx); err != nil {
-			return errPublicKeyCaveat(c, err)
+	validators, err := vsecurity.CaveatValidators(pkDischarge.Caveats...)
+	if err != nil {
+		return err
+	}
+	for _, v := range validators {
+		if err := v.Validate(ctx); err != nil {
+			return err
 		}
 	}
 
 	// Check the discharge signature with the validation key from the caveat.
 	key, err := c.ValidationKey.Decode()
 	if err != nil {
-		return errPublicKeyCaveat(c, err)
+		return err
 	}
 	if !pkDischarge.Signature.Verify(key, pkDischarge.contentHash()) {
-		return errPublicKeyCaveat(c, fmt.Errorf("discharge %v has invalid signature", dis))
+		return fmt.Errorf("discharge %v has invalid signature", dis)
 	}
 	return nil
 }
 
-// publicKeyDischarge implements security.ThirdPartyDischarge. It specifies a
-// discharge for a publicKeyCaveat, and includes a signature that can be verified
-// with the validation key of the caveat. Additionally, the discharge may include
-// service caveats which must all be valid in order for the discharge to be
-// considered valid.
+// publicKeyDischarge implements security.Discharge. It specifies a discharge
+// for a publicKeyCaveat, and includes a signature that can be verified with
+// the validation key of the publicKeyCaveat. Additionally, the discharge may
+// also include caveats which must all validate in order for the discharge to
+// be considered valid.
 type publicKeyDischarge struct {
-	// ThirdPartyCaveatID is used to match a Discharge with the Caveat it is for.
-	ThirdPartyCaveatID security.ThirdPartyCaveatID
+	// CaveatID is used to match this Discharge to the the ThirdPartyCaveat it is for.
+	CaveatID string
 
 	// Caveats under which this Discharge is valid.
-	Caveats []wire.Caveat
+	Caveats [][]byte
 
-	// Signature on the contents of the discharge obtained using the private key
-	// corresponding to the validaton key in the caveat.
+	// Signature on the contents of the discharge that can be verified using the
+	// validaton key in the publicKeycaveat this discharge is for.
 	Signature security.Signature
 }
 
-// CaveatID returns a unique identity for the discharge based on the random nonce and
-// restriction embedded in the discharge.
-func (d *publicKeyDischarge) CaveatID() security.ThirdPartyCaveatID {
-	return d.ThirdPartyCaveatID
+func (d *publicKeyDischarge) ID() string {
+	return d.CaveatID
 }
 
-func (d *publicKeyDischarge) ThirdPartyCaveats() []security.ServiceCaveat {
-	return wire.DecodeThirdPartyCaveats(d.Caveats)
+func (d *publicKeyDischarge) ThirdPartyCaveats() []security.ThirdPartyCaveat {
+	return vsecurity.ThirdPartyCaveats(d.Caveats...)
 }
 
-// sign uses the provided identity to sign the contents of the discharge.
-func (d *publicKeyDischarge) sign(discharger security.PrivateID) (err error) {
-	d.Signature, err = discharger.Sign(d.contentHash())
+func (d *publicKeyDischarge) sign(signer security.Signer) (err error) {
+	d.Signature, err = signer.Sign(d.contentHash())
 	return
 }
 
@@ -139,72 +132,74 @@
 	h := sha256.New()
 	tmp := make([]byte, binary.MaxVarintLen64)
 
-	wire.WriteBytes(h, tmp, []byte(d.ThirdPartyCaveatID))
+	wire.WriteString(h, tmp, d.CaveatID)
 	for _, cav := range d.Caveats {
-		wire.WriteString(h, tmp, string(cav.Service))
-		wire.WriteBytes(h, tmp, cav.Bytes)
+		wire.WriteBytes(h, tmp, cav)
 	}
 	return h.Sum(nil)
 }
 
-// NewPublicKeyCaveat returns a new third-party caveat from the provided restriction,
-// third-party identity, and third-party location.
-func NewPublicKeyCaveat(dischargeMintingCaveat security.Caveat, thirdParty security.PublicID, location string, requirements security.ThirdPartyRequirements) (security.ThirdPartyCaveat, error) {
+// NewPublicKeyCaveat returns a security.ThirdPartyCaveat which requires a
+// discharge from a principal identified by the public key 'key' and present
+// at the object name 'location'. This discharging principal is expected to
+// validate 'caveat' before issuing a discharge.
+func NewPublicKeyCaveat(caveat security.Caveat, key *ecdsa.PublicKey, location string, requirements security.ThirdPartyRequirements) (security.ThirdPartyCaveat, error) {
 	nonce := make([]uint8, nonceLength)
 	if _, err := rand.Read(nonce); err != nil {
 		return nil, err
 	}
 
 	var validationKey wire.PublicKey
-	if err := validationKey.Encode(thirdParty.PublicKey()); err != nil {
+	if err := validationKey.Encode(key); err != nil {
 		return nil, err
 	}
 
-	var mintingCaveatEncoded bytes.Buffer
-	vom.NewEncoder(&mintingCaveatEncoded).Encode(dischargeMintingCaveat)
 	return &publicKeyCaveat{
 		RandNonce:              nonce,
-		DischargeMintingCaveat: mintingCaveatEncoded.Bytes(),
+		DischargeMintingCaveat: caveat.Bytes(),
 		ValidationKey:          validationKey,
 		ThirdPartyLocation:     location,
 		ThirdPartyRequirements: requirements,
 	}, nil
 }
 
-// NewPublicKeyDischarge returns a new discharge for the provided caveat
-// after verifying that the caveats for minting a discharge are met.
+// NewPublicKeyDischarge returns a new discharge for the provided 'tp'
+// after validating any restrictions specified in it under context 'ctx'.
 //
-// The CaveatID of the discharge is the same as the ID of the caveat, and
-// the discharge includes the provided service caveats along with a universal
-// expiry caveat for the provided duration. The discharge also includes a
-// signature over its contents obtained from the provided private key.
-func NewPublicKeyDischarge(discharger security.PrivateID, caveat security.ThirdPartyCaveat, ctx security.Context, duration time.Duration, caveats []security.ServiceCaveat) (security.ThirdPartyDischarge, error) {
-	cav, ok := caveat.(*publicKeyCaveat)
+// The ID of the discharge is the same as the ID of 'caveat', and the discharge
+// will be usable for the provided 'duration' only if:
+// (1) 'caveats' are met when using the discharge.
+// (2) 'tp' was obtained from NewPublicKeyCaveat using a key that is the same as
+// the provided signer's PublicKey.
+func NewPublicKeyDischarge(signer security.Signer, tp security.ThirdPartyCaveat, ctx security.Context, duration time.Duration, caveats []security.Caveat) (security.Discharge, error) {
+	pkCaveat, ok := tp.(*publicKeyCaveat)
 	if !ok {
-		return nil, fmt.Errorf("cannot mint discharges for %T", caveat)
+		return nil, fmt.Errorf("cannot mint discharges for %T", tp)
 	}
-	var mintingCaveat security.Caveat
-	mcBuf := bytes.NewReader(cav.DischargeMintingCaveat)
-	if err := vom.NewDecoder(mcBuf).Decode(&mintingCaveat); err != nil {
-		return nil, fmt.Errorf("failed to decode DischargeMintingCaveat: %s", err)
-	}
-	if err := mintingCaveat.Validate(ctx); err != nil {
-		return nil, fmt.Errorf("failed to validate DischargeMintingCaveat: %s", err)
-	}
-	now := time.Now()
-	expiryCaveat := &Expiry{IssueTime: now, ExpiryTime: now.Add(duration)}
-	caveats = append(caveats, UniversalCaveat(expiryCaveat))
-	encodedCaveats, err := wire.EncodeCaveats(caveats)
+
+	v, err := vsecurity.CaveatValidators(pkCaveat.DischargeMintingCaveat)
 	if err != nil {
-		return nil, fmt.Errorf("failed to encode caveats in discharge: %v", err)
+		return nil, err
 	}
+	if err := v[0].Validate(ctx); err != nil {
+		return nil, err
+	}
+
+	now := time.Now()
+	expiryCaveat, err := security.NewCaveat(&Expiry{IssueTime: now, ExpiryTime: now.Add(duration)})
+	if err != nil {
+		return nil, err
+	}
+
+	caveats = append(caveats, expiryCaveat)
 	discharge := &publicKeyDischarge{
-		ThirdPartyCaveatID: caveat.ID(),
-		Caveats:            encodedCaveats,
+		CaveatID: tp.ID(),
+		Caveats:  vsecurity.CaveatBytes(caveats...),
 	}
-	// TODO(ashankar,ataly): Should discharger necessarily be the same as ctx.LocalID()?
+
+	// TODO(ashankar,ataly): Should signer necessarily be the same as ctx.LocalID()?
 	// If so, need the PrivateID object corresponding to ctx.LocalID.
-	if err := discharge.sign(discharger); err != nil {
+	if err := discharge.sign(signer); err != nil {
 		return nil, err
 	}
 	return discharge, nil
diff --git a/security/util.go b/security/util.go
index b709c31..31987a0 100644
--- a/security/util.go
+++ b/security/util.go
@@ -1,8 +1,10 @@
 package security
 
 import (
+	"bytes"
 	"encoding/base64"
 	"encoding/json"
+	"fmt"
 	"io"
 
 	"veyron2/security"
@@ -55,3 +57,46 @@
 func SaveACL(w io.Writer, acl security.ACL) error {
 	return json.NewEncoder(w).Encode(acl)
 }
+
+// CaveatBytes returns a slice containing the Bytes of the provided 'caveats'.
+func CaveatBytes(caveats ...security.Caveat) [][]byte {
+	b := make([][]byte, len(caveats))
+	for i, c := range caveats {
+		b[i] = c.Bytes()
+	}
+	return b
+}
+
+// CaveatValidators returns the set of security.CaveatValidators
+// obtained by decoding the provided caveat bytes.
+//
+// It is an error if any of the provided caveat bytes cannot
+// be decoded into a security.CaveatValidator.
+func CaveatValidators(caveats ...[]byte) ([]security.CaveatValidator, error) {
+	if len(caveats) == 0 {
+		return nil, nil
+	}
+	validators := make([]security.CaveatValidator, len(caveats))
+	for i, c := range caveats {
+		var v security.CaveatValidator
+		if err := vom.NewDecoder(bytes.NewReader(c)).Decode(&v); err != nil {
+			return nil, fmt.Errorf("caveat bytes could not be VOM-decoded: %s", err)
+		}
+		validators[i] = v
+	}
+	return validators, nil
+}
+
+// ThirdPartyCaveats returns the set of security.ThirdPartyCaveats
+// that could be successfully decoded from the provided caveat bytes.
+func ThirdPartyCaveats(caveats ...[]byte) []security.ThirdPartyCaveat {
+	var tpCaveats []security.ThirdPartyCaveat
+	for _, c := range caveats {
+		var t security.ThirdPartyCaveat
+		if err := vom.NewDecoder(bytes.NewReader(c)).Decode(&t); err != nil {
+			continue
+		}
+		tpCaveats = append(tpCaveats, t)
+	}
+	return tpCaveats
+}
diff --git a/security/util_test.go b/security/util_test.go
index d535039..2cf2da4 100644
--- a/security/util_test.go
+++ b/security/util_test.go
@@ -2,10 +2,12 @@
 
 import (
 	"bytes"
+	"fmt"
 	"reflect"
 	"testing"
 
 	"veyron2/security"
+	"veyron2/vom"
 )
 
 func TestLoadSaveIdentity(t *testing.T) {
@@ -49,3 +51,76 @@
 		t.Fatalf("Got ACL %v, but want %v", loadedACL, acl)
 	}
 }
+
+// fpCaveat implements security.CaveatValidator.
+type fpCaveat struct{}
+
+func (fpCaveat) Validate(security.Context) error { return nil }
+
+// tpCaveat implements security.ThirdPartyCaveat.
+type tpCaveat struct{}
+
+func (tpCaveat) Validate(security.Context) (err error)             { return }
+func (tpCaveat) ID() (id string)                                   { return }
+func (tpCaveat) Location() (loc string)                            { return }
+func (tpCaveat) Requirements() (r security.ThirdPartyRequirements) { return }
+
+func TestCaveatUtil(t *testing.T) {
+	type b [][]byte
+	type v []security.CaveatValidator
+	type tp []security.ThirdPartyCaveat
+
+	newCaveatBytes := func(v security.CaveatValidator) []byte {
+		cav, err := security.NewCaveat(v)
+		if err != nil {
+			t.Fatalf("NewCaveat failed: %s", err)
+		}
+		return cav.Bytes()
+	}
+	var (
+		fpCavBytes = newCaveatBytes(fpCaveat{})
+		tpCavBytes = newCaveatBytes(tpCaveat{})
+		invalid    = []byte("fake")
+	)
+	testdata := []struct {
+		caveats    [][]byte
+		validators []security.CaveatValidator
+		tpCaveats  []security.ThirdPartyCaveat
+	}{
+		{nil, nil, nil},
+		{b{fpCavBytes}, v{fpCaveat{}}, nil},
+		{b{tpCavBytes}, v{tpCaveat{}}, tp{tpCaveat{}}},
+		{b{fpCavBytes, tpCavBytes}, v{fpCaveat{}, tpCaveat{}}, tp{tpCaveat{}}},
+	}
+	for i, d := range testdata {
+		// Test CaveatValidators.
+		got, err := CaveatValidators(d.caveats...)
+		if err != nil {
+			t.Errorf("CaveatValidators(%v) failed: %s", d.caveats, err)
+			continue
+		}
+		if !reflect.DeepEqual(got, d.validators) {
+			fmt.Println("TEST ", i)
+			t.Errorf("CaveatValidators(%v): got: %#v, want: %#v", d.caveats, got, d.validators)
+			continue
+		}
+		if _, err := CaveatValidators(append(d.caveats, invalid)...); err == nil {
+			t.Errorf("CaveatValidators(%v) succeeded unexpectedly", d.caveats)
+			continue
+		}
+		// Test ThirdPartyCaveats.
+		if got := ThirdPartyCaveats(d.caveats...); !reflect.DeepEqual(got, d.tpCaveats) {
+			t.Errorf("ThirdPartyCaveats(%v): got: %#v, want: %#v", d.caveats, got, d.tpCaveats)
+			continue
+		}
+		if got := ThirdPartyCaveats(append(d.caveats, invalid)...); !reflect.DeepEqual(got, d.tpCaveats) {
+			t.Errorf("ThirdPartyCaveats(%v): got: %#v, want: %#v", d.caveats, got, d.tpCaveats)
+			continue
+		}
+	}
+}
+
+func init() {
+	vom.Register(&fpCaveat{})
+	vom.Register(&tpCaveat{})
+}
diff --git a/services/identity/googleoauth/handler.go b/services/identity/googleoauth/handler.go
index 77292c0..915db37 100644
--- a/services/identity/googleoauth/handler.go
+++ b/services/identity/googleoauth/handler.go
@@ -231,7 +231,7 @@
 		return
 	}
 
-	caveatID := security.ThirdPartyCaveatID(string(decodedCaveatID))
+	caveatID := string(decodedCaveatID)
 
 	if err := h.revocationManager.Revoke(caveatID); err != nil {
 		vlog.Infof("Revocation failed: %s", err)
diff --git a/services/identity/revocation/bless.go b/services/identity/revocation/bless.go
index b90a6b0..bfacb4b 100644
--- a/services/identity/revocation/bless.go
+++ b/services/identity/revocation/bless.go
@@ -4,8 +4,8 @@
 	"fmt"
 	"time"
 
+	vsecurity "veyron/security"
 	"veyron/security/audit"
-	"veyron/security/caveat"
 
 	"veyron2/security"
 )
@@ -13,8 +13,12 @@
 // Bless creates a blessing on behalf of the identity server.
 func Bless(server security.PrivateID, blessee security.PublicID, email string, duration time.Duration, revocationCaveat security.ThirdPartyCaveat) (security.PublicID, error) {
 	if revocationCaveat != nil {
+		caveat, err := security.NewCaveat(revocationCaveat)
+		if err != nil {
+			return nil, err
+		}
 		// TODO(suharshs): Extend the duration for blessings with provided revocaionCaveats
-		return server.Bless(blessee, email, duration, []security.ServiceCaveat{caveat.UniversalCaveat(revocationCaveat)})
+		return server.Bless(blessee, email, duration, []security.Caveat{caveat})
 	}
 	// return a blessing with a more limited duration, since there is no revocation caveat
 	return server.Bless(blessee, email, duration, nil)
@@ -40,9 +44,13 @@
 		blessEntry.End = blessEntry.Start.Add(time.Duration(duration))
 	}
 	blessEntry.Blessed, _ = entry.Results[0].(security.PublicID)
-	caveats, _ := entry.Arguments[3].([]security.ServiceCaveat)
+	caveats, _ := entry.Arguments[3].([]security.Caveat)
 	if len(caveats) > 0 {
-		blessEntry.RevocationCaveat, _ = caveats[0].Caveat.(security.ThirdPartyCaveat)
+		revocationCaveat, err := vsecurity.CaveatValidators(caveats[0].Bytes())
+		if err != nil {
+			return blessEntry, err
+		}
+		blessEntry.RevocationCaveat, _ = revocationCaveat[0].(security.ThirdPartyCaveat)
 	}
 	return blessEntry, nil
 }
diff --git a/services/identity/revocation/revocation_manager.go b/services/identity/revocation/revocation_manager.go
index 139012a..c9cdada 100644
--- a/services/identity/revocation/revocation_manager.go
+++ b/services/identity/revocation/revocation_manager.go
@@ -31,8 +31,11 @@
 	if _, err := rand.Read(revocation[:]); err != nil {
 		return nil, err
 	}
-	restriction := revocationCaveat(revocation)
-	cav, err := caveat.NewPublicKeyCaveat(restriction, dischargerID, dischargerLocation, security.ThirdPartyRequirements{})
+	restriction, err := security.NewCaveat(revocationCaveat(revocation))
+	if err != nil {
+		return nil, err
+	}
+	cav, err := caveat.NewPublicKeyCaveat(restriction, dischargerID.PublicKey(), dischargerLocation, security.ThirdPartyRequirements{})
 	if err != nil {
 		return nil, err
 	}
@@ -43,7 +46,7 @@
 }
 
 // Revoke disables discharges from being issued for the provided third-party caveat.
-func (r *RevocationManager) Revoke(caveatID security.ThirdPartyCaveatID) error {
+func (r *RevocationManager) Revoke(caveatID string) error {
 	token, err := r.caveatMap.Get(hex.EncodeToString([]byte(caveatID)))
 	if err != nil {
 		return err
@@ -53,7 +56,7 @@
 
 // GetRevocationTimestamp returns the timestamp at which a caveat was revoked.
 // If the caveat wasn't revoked returns nil
-func (r *RevocationManager) GetRevocationTime(caveatID security.ThirdPartyCaveatID) *time.Time {
+func (r *RevocationManager) GetRevocationTime(caveatID string) *time.Time {
 	token, err := r.caveatMap.Get(hex.EncodeToString([]byte(caveatID)))
 	if err != nil {
 		return nil
diff --git a/services/security/discharger.vdl b/services/security/discharger.vdl
index 95202d1..07139fd 100644
--- a/services/security/discharger.vdl
+++ b/services/security/discharger.vdl
@@ -8,7 +8,7 @@
   // party caveat and seeks to get a discharge that proves the fulfillment of
   // this caveat.
   //
-  // Caveat and Discharge are of type ThirdPartyCaveat and ThirdPartyDischarge
+  // Caveat and Discharge are of type ThirdPartyCaveat and Discharge
   // respectively. (not enforced here because vdl does not know these types)
   // TODO(ataly,ashankar): Figure out a VDL representation for ThirdPartyCaveat
   // and Discharge and use those here?
diff --git a/services/security/discharger.vdl.go b/services/security/discharger.vdl.go
index 1b4bc4a..de2de44 100644
--- a/services/security/discharger.vdl.go
+++ b/services/security/discharger.vdl.go
@@ -28,7 +28,7 @@
 	// party caveat and seeks to get a discharge that proves the fulfillment of
 	// this caveat.
 	//
-	// Caveat and Discharge are of type ThirdPartyCaveat and ThirdPartyDischarge
+	// Caveat and Discharge are of type ThirdPartyCaveat and Discharge
 	// respectively. (not enforced here because vdl does not know these types)
 	// TODO(ataly,ashankar): Figure out a VDL representation for ThirdPartyCaveat
 	// and Discharge and use those here?
@@ -46,7 +46,7 @@
 	// party caveat and seeks to get a discharge that proves the fulfillment of
 	// this caveat.
 	//
-	// Caveat and Discharge are of type ThirdPartyCaveat and ThirdPartyDischarge
+	// Caveat and Discharge are of type ThirdPartyCaveat and Discharge
 	// respectively. (not enforced here because vdl does not know these types)
 	// TODO(ataly,ashankar): Figure out a VDL representation for ThirdPartyCaveat
 	// and Discharge and use those here?
diff --git a/services/security/discharger/revoker.go b/services/security/discharger/revoker.go
index 6e6cba8..0f49f44 100644
--- a/services/security/discharger/revoker.go
+++ b/services/security/discharger/revoker.go
@@ -69,8 +69,11 @@
 	if _, err := rand.Read(revocation[:]); err != nil {
 		return revocation, nil, err
 	}
-	restriction := revocationCaveat(sha256.Sum256(revocation[:]))
-	cav, err := caveat.NewPublicKeyCaveat(restriction, dischargerID, dischargerLocation, security.ThirdPartyRequirements{})
+	restriction, err := security.NewCaveat(revocationCaveat(sha256.Sum256(revocation[:])))
+	if err != nil {
+		return revocation, nil, err
+	}
+	cav, err := caveat.NewPublicKeyCaveat(restriction, dischargerID.PublicKey(), dischargerLocation, security.ThirdPartyRequirements{})
 	return revocation, cav, err
 }
 
diff --git a/services/store/memstore/testing/util.go b/services/store/memstore/testing/util.go
index 37dece7..be31dc9 100644
--- a/services/store/memstore/testing/util.go
+++ b/services/store/memstore/testing/util.go
@@ -34,18 +34,18 @@
 	}
 }
 
-func (*FakeServerContext) Server() ipc.Server                            { return nil }
-func (*FakeServerContext) Method() string                                { return "" }
-func (*FakeServerContext) Name() string                                  { return "" }
-func (*FakeServerContext) Suffix() string                                { return "" }
-func (*FakeServerContext) Label() (l security.Label)                     { return }
-func (*FakeServerContext) CaveatDischarges() security.CaveatDischargeMap { return nil }
-func (ctx *FakeServerContext) LocalID() security.PublicID                { return ctx.id }
-func (ctx *FakeServerContext) RemoteID() security.PublicID               { return ctx.id }
-func (*FakeServerContext) Blessing() security.PublicID                   { return nil }
-func (*FakeServerContext) LocalEndpoint() naming.Endpoint                { return nil }
-func (*FakeServerContext) RemoteEndpoint() naming.Endpoint               { return nil }
-func (ctx *FakeServerContext) Cancel()                                   { ctx.cancel() }
+func (*FakeServerContext) Server() ipc.Server                        { return nil }
+func (*FakeServerContext) Method() string                            { return "" }
+func (*FakeServerContext) Name() string                              { return "" }
+func (*FakeServerContext) Suffix() string                            { return "" }
+func (*FakeServerContext) Label() (l security.Label)                 { return }
+func (*FakeServerContext) Discharges() map[string]security.Discharge { return nil }
+func (ctx *FakeServerContext) LocalID() security.PublicID            { return ctx.id }
+func (ctx *FakeServerContext) RemoteID() security.PublicID           { return ctx.id }
+func (*FakeServerContext) Blessing() security.PublicID               { return nil }
+func (*FakeServerContext) LocalEndpoint() naming.Endpoint            { return nil }
+func (*FakeServerContext) RemoteEndpoint() naming.Endpoint           { return nil }
+func (ctx *FakeServerContext) Cancel()                               { ctx.cancel() }
 
 // Utilities for PutMutations.
 
diff --git a/services/wsprd/app/app.go b/services/wsprd/app/app.go
index 022a0b5..7385834 100644
--- a/services/wsprd/app/app.go
+++ b/services/wsprd/app/app.go
@@ -58,15 +58,14 @@
 	inType vom.Type
 }
 
-type jsonServiceCaveat struct {
-	Type    string `json:"_type"`
-	Service security.BlessingPattern
-	Data    json.RawMessage
+type jsonCaveatValidator struct {
+	Type string `json:"_type"`
+	Data json.RawMessage
 }
 
 type blessingRequest struct {
 	Handle     int64
-	Caveats    []jsonServiceCaveat
+	Caveats    []jsonCaveatValidator
 	DurationMs int64
 	Name       string
 }
@@ -578,18 +577,17 @@
 }
 
 // Convert the json wire format of a caveat into the right go object
-func decodeCaveat(c jsonServiceCaveat) (security.ServiceCaveat, error) {
-	var ret security.ServiceCaveat
-	ret.Service = c.Service
+func decodeCaveat(c jsonCaveatValidator) (security.CaveatValidator, error) {
+	var ret security.CaveatValidator
 	switch c.Type {
 	case "MethodCaveat":
-		ret.Caveat = &caveat.MethodRestriction{}
-	case "PeerIdentityCaveat":
-		ret.Caveat = &caveat.PeerIdentity{}
+		ret = &caveat.MethodRestriction{}
+	case "PeerBlessingsCaveat":
+		ret = &caveat.PeerBlessings{}
 	default:
 		return ret, verror.BadArgf("unknown caveat type %s", c.Type)
 	}
-	return ret, json.Unmarshal(c.Data, &ret.Caveat)
+	return ret, json.Unmarshal(c.Data, &ret)
 }
 
 func (c *Controller) getPublicIDHandle(handle int64) (*PublicIDHandle, error) {
@@ -601,13 +599,17 @@
 }
 
 func (c *Controller) bless(request blessingRequest) (*PublicIDHandle, error) {
-	var caveats []security.ServiceCaveat
+	var caveats []security.Caveat
 	for _, c := range request.Caveats {
-		newCaveat, err := decodeCaveat(c)
+		v, err := decodeCaveat(c)
 		if err != nil {
 			return nil, verror.BadArgf("failed to parse caveat: %v", err)
 		}
-		caveats = append(caveats, newCaveat)
+		c, err := security.NewCaveat(v)
+		if err != nil {
+			return nil, verror.BadArgf("failed to convert caveat to security.Caveat: %v", err)
+		}
+		caveats = append(caveats, c)
 	}
 	duration := time.Duration(request.DurationMs) * time.Millisecond
 
diff --git a/services/wsprd/app/app_test.go b/services/wsprd/app/app_test.go
index f0e654d..dc38e00 100644
--- a/services/wsprd/app/app_test.go
+++ b/services/wsprd/app/app_test.go
@@ -687,26 +687,20 @@
 func TestDeserializeCaveat(t *testing.T) {
 	testCases := []struct {
 		json          string
-		expectedValue security.ServiceCaveat
+		expectedValue security.CaveatValidator
 	}{
 		{
-			json: `{"_type":"MethodCaveat","service":"...","data":["Get","MultiGet"]}`,
-			expectedValue: security.ServiceCaveat{
-				Service: security.AllPrincipals,
-				Caveat:  &caveat.MethodRestriction{"Get", "MultiGet"},
-			},
+			json:          `{"_type":"MethodCaveat","service":"...","data":["Get","MultiGet"]}`,
+			expectedValue: &caveat.MethodRestriction{"Get", "MultiGet"},
 		},
 		{
-			json: `{"_type":"PeerIdentityCaveat","service":"...","data":["veyron/batman","veyron/brucewayne"]}`,
-			expectedValue: security.ServiceCaveat{
-				Service: security.AllPrincipals,
-				Caveat:  &caveat.PeerIdentity{"veyron/batman", "veyron/brucewayne"},
-			},
+			json:          `{"_type":"PeerBlessingsCaveat","service":"...","data":["veyron/batman","veyron/brucewayne"]}`,
+			expectedValue: &caveat.PeerBlessings{"veyron/batman", "veyron/brucewayne"},
 		},
 	}
 
 	for _, c := range testCases {
-		var s jsonServiceCaveat
+		var s jsonCaveatValidator
 		if err := json.Unmarshal([]byte(c.json), &s); err != nil {
 			t.Errorf("Failed to deserialize object: %v", err)
 			return
@@ -770,7 +764,7 @@
 
 func (*mockSecurityContext) Label() security.Label { return 0 }
 
-func (*mockSecurityContext) CaveatDischarges() security.CaveatDischargeMap { return nil }
+func (*mockSecurityContext) Discharges() map[string]security.Discharge { return nil }
 
 func (*mockSecurityContext) RemoteID() security.PublicID { return nil }
 
@@ -885,7 +879,7 @@
 			"durationMs": 10000,
 			"caveats": []map[string]interface{}{
 				map[string]interface{}{
-					"_type":   "PeerIdentityCaveat",
+					"_type":   "PeerBlessingsCaveat",
 					"service": security.AllPrincipals,
 					"data":    []string{securityName("test/alice")},
 				},
@@ -908,7 +902,7 @@
 			"durationMs": 10000,
 			"caveats": []map[string]interface{}{
 				map[string]interface{}{
-					"_type":   "PeerIdentityCaveat",
+					"_type":   "PeerBlessingsCaveat",
 					"service": security.AllPrincipals,
 					"data":    []string{securityName("test/alice")},
 				},
diff --git a/services/wsprd/identity/identity.go b/services/wsprd/identity/identity.go
index b9a9c7b..b7b0f32 100644
--- a/services/wsprd/identity/identity.go
+++ b/services/wsprd/identity/identity.go
@@ -31,7 +31,7 @@
 type permissions struct {
 	// The account name that is given to an app.
 	Account string
-	Caveats []security.ServiceCaveat
+	Caveats []security.Caveat
 }
 
 // persistentState is the state of the manager that will be persisted to disk.
@@ -161,7 +161,7 @@
 }
 
 // AddOrigin adds an origin to the manager linked to a the given account.
-func (i *IDManager) AddOrigin(origin string, account string, caveats []security.ServiceCaveat) error {
+func (i *IDManager) AddOrigin(origin string, account string, caveats []security.Caveat) error {
 	i.mu.Lock()
 	defer i.mu.Unlock()
 	if _, found := i.state.Accounts[account]; !found {
@@ -184,7 +184,7 @@
 	return nil
 }
 
-func (i *IDManager) generateBlessedID(origin string, account string, caveats []security.ServiceCaveat) (security.PrivateID, error) {
+func (i *IDManager) generateBlessedID(origin string, account string, caveats []security.Caveat) (security.PrivateID, error) {
 	blessor := i.state.Accounts[account]
 	if blessor == nil {
 		return nil, verror.NotFoundf("unknown account %s", account)