Merge "mounttable: fix Resolve access"
diff --git a/profiles/internal/ipc/full_test.go b/profiles/internal/ipc/full_test.go
index a6573ff..06ed262 100644
--- a/profiles/internal/ipc/full_test.go
+++ b/profiles/internal/ipc/full_test.go
@@ -1118,6 +1118,97 @@
 	}
 }
 
+// maliciousBlessingStore implements security.BlessingStore. It is a
+// BlessingStore that marks the last blessing that was set on it as
+// shareable with any peer. It does not care about the public key that
+// blessing being set is bound to.
+type maliciousBlessingStore struct {
+	b security.Blessings
+}
+
+func (s *maliciousBlessingStore) Set(b security.Blessings, _ security.BlessingPattern) (security.Blessings, error) {
+	s.b = b
+	return security.Blessings{}, nil
+}
+func (s *maliciousBlessingStore) ForPeer(...string) security.Blessings {
+	return s.b
+}
+func (*maliciousBlessingStore) SetDefault(b security.Blessings) error {
+	return nil
+}
+func (*maliciousBlessingStore) Default() security.Blessings {
+	return security.Blessings{}
+}
+func (*maliciousBlessingStore) PublicKey() security.PublicKey {
+	return nil
+}
+func (*maliciousBlessingStore) DebugString() string {
+	return ""
+}
+func (*maliciousBlessingStore) PeerBlessings() map[security.BlessingPattern]security.Blessings {
+	return nil
+}
+
+// maliciousPrincipal implements security.Principal. It is a wrapper over
+// a security.Principal that intercepts  all invocations on the
+// principal's BlessingStore and serves them via a maliciousBlessingStore.
+type maliciousPrincipal struct {
+	security.Principal
+	b maliciousBlessingStore
+}
+
+func (p *maliciousPrincipal) BlessingStore() security.BlessingStore {
+	return &p.b
+}
+
+func TestRPCClientBlessingsPublicKey(t *testing.T) {
+	var (
+		pprovider, pserver = tsecurity.NewPrincipal("root"), tsecurity.NewPrincipal("server")
+		pclient            = &maliciousPrincipal{Principal: tsecurity.NewPrincipal("client")}
+
+		bserver = bless(pprovider, pserver, "server")
+		bclient = bless(pprovider, pclient, "client")
+		bvictim = bless(pprovider, tsecurity.NewPrincipal("victim"), "victim")
+
+		b = createBundle(t, pclient, pserver, &testServer{})
+	)
+	defer b.cleanup(t)
+
+	// Make the client and server trust blessings from pprovider.
+	pclient.AddToRoots(pprovider.BlessingStore().Default())
+	pserver.AddToRoots(pprovider.BlessingStore().Default())
+
+	// Make the server present bserver to all clients.
+	pserver.BlessingStore().SetDefault(bserver)
+	tests := []struct {
+		blessings security.Blessings
+		errID     verror.IDAction
+		err       string
+	}{
+		{blessings: bclient},
+		// server disallows clients from authenticating with blessings not bound to
+		// the client principal's public key
+		{blessings: bvictim, errID: verror.ErrNoAccess, err: "bound to a different public key"},
+		// or authenticating with the server's blessings
+		{blessings: bserver, errID: verror.ErrNoAccess, err: "bound to a different public key"},
+	}
+	for i, test := range tests {
+		name := fmt.Sprintf("%d: Client RPCing with blessings %v", i, test.blessings)
+
+		pclient.BlessingStore().Set(test.blessings, "root")
+
+		call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "Closure", nil)
+		if err != nil {
+			t.Errorf("%v: StartCall failed: %v", name, err)
+			continue
+		}
+		if err := call.Finish(); !matchesErrorPattern(err, test.errID, test.err) {
+			t.Errorf("%v: Finish returned error %v", name, err)
+			continue
+		}
+	}
+}
+
 func TestDischargePurgeFromCache(t *testing.T) {
 	var (
 		pserver     = tsecurity.NewPrincipal("server")
diff --git a/profiles/internal/ipc/server.go b/profiles/internal/ipc/server.go
index b4e52ee..9439086 100644
--- a/profiles/internal/ipc/server.go
+++ b/profiles/internal/ipc/server.go
@@ -1139,6 +1139,12 @@
 }
 
 func (fs *flowServer) initSecurity(req *ipc.Request) error {
+	// LocalPrincipal is nil which means we are operating under
+	// VCSecurityNone.
+	if fs.flow.LocalPrincipal() == nil {
+		return nil
+	}
+
 	// If additional credentials are provided, make them available in the context
 	// Detect unusable blessings now, rather then discovering they are unusable on
 	// first use.
@@ -1147,10 +1153,11 @@
 	// the server's identity as the blessing. Figure out what we want to do about
 	// this - should servers be able to assume that a blessing is something that
 	// does not have the authorizations that the server's own identity has?
-	if b := req.GrantedBlessings; b.PublicKey() != nil && !reflect.DeepEqual(b.PublicKey(), fs.flow.LocalPrincipal().PublicKey()) {
-		return verror.New(verror.ErrNoAccess, fs.T, fmt.Sprintf("blessing granted not bound to this server(%v vs %v)", b.PublicKey(), fs.flow.LocalPrincipal().PublicKey()))
+	if got, want := req.GrantedBlessings.PublicKey(), fs.flow.LocalPrincipal().PublicKey(); got != nil && !reflect.DeepEqual(got, want) {
+		return verror.New(verror.ErrNoAccess, fs.T, fmt.Sprintf("blessing granted not bound to this server(%v vs %v)", got, want))
 	}
 	fs.grantedBlessings = req.GrantedBlessings
+
 	var err error
 	if fs.clientBlessings, err = serverDecodeBlessings(fs.flow.VCDataCache(), req.Blessings, fs.server.stats); err != nil {
 		// When the server can't access the blessings cache, the client is not following
@@ -1160,6 +1167,11 @@
 		fs.server.streamMgr.ShutdownEndpoint(fs.RemoteEndpoint())
 		return verror.New(verror.ErrBadProtocol, fs.T, newErrBadBlessingsCache(fs.T, err))
 	}
+	// Verify that the blessings sent by the client in the request have the same public
+	// key as those sent by the client during VC establishment.
+	if got, want := fs.clientBlessings.PublicKey(), fs.flow.RemoteBlessings().PublicKey(); got != nil && !reflect.DeepEqual(got, want) {
+		return verror.New(verror.ErrNoAccess, fs.T, fmt.Sprintf("blessings sent with the request are bound to a different public key (%v) from the blessing used during VC establishment (%v)", got, want))
+	}
 	fs.ackBlessings = true
 
 	for _, d := range req.Discharges {