Merge "veyron2: Panic if the user tries to use the runtime when it is not set."
diff --git a/runtimes/google/ipc/blessings_cache.go b/runtimes/google/ipc/blessings_cache.go
index effa8e8..aadbbfc 100644
--- a/runtimes/google/ipc/blessings_cache.go
+++ b/runtimes/google/ipc/blessings_cache.go
@@ -1,6 +1,7 @@
 package ipc
 
 import (
+	"crypto/sha256"
 	"fmt"
 	"reflect"
 	"sync"
@@ -12,7 +13,7 @@
 
 // clientEncodeBlessings gets or inserts the blessings into the cache.
 func clientEncodeBlessings(cache stream.VCDataCache, blessings security.Blessings) ipc.BlessingsRequest {
-	blessingsCacheAny := cache.GetOrInsert(clientBlessingsKey{}, newClientBlessingsCache)
+	blessingsCacheAny := cache.GetOrInsert(clientBlessingsCacheKey{}, newClientBlessingsCache)
 	blessingsCache := blessingsCacheAny.(*clientBlessingsCache)
 	return blessingsCache.getOrInsert(blessings)
 }
@@ -20,7 +21,7 @@
 // clientAckBlessings verifies that the server has updated its cache to include blessings.
 // This means that subsequent rpcs from the client with blessings can send only a cache key.
 func clientAckBlessings(cache stream.VCDataCache, blessings security.Blessings) {
-	blessingsCacheAny := cache.GetOrInsert(clientBlessingsKey{}, newClientBlessingsCache)
+	blessingsCacheAny := cache.GetOrInsert(clientBlessingsCacheKey{}, newClientBlessingsCache)
 	blessingsCache := blessingsCacheAny.(*clientBlessingsCache)
 	blessingsCache.acknowledge(blessings)
 }
@@ -28,77 +29,94 @@
 // serverDecodeBlessings insert the key and blessings into the cache or get the blessings if only
 // key is provided in req.
 func serverDecodeBlessings(cache stream.VCDataCache, req ipc.BlessingsRequest, stats *ipcStats) (security.Blessings, error) {
-	blessingsCacheAny := cache.GetOrInsert(serverBlessingsKey{}, newServerBlessingsCache)
+	blessingsCacheAny := cache.GetOrInsert(serverBlessingsCacheKey{}, newServerBlessingsCache)
 	blessingsCache := blessingsCacheAny.(*serverBlessingsCache)
 	return blessingsCache.getOrInsert(req, stats)
 }
 
 // IMPLEMENTATION DETAILS BELOW
 
-// clientBlessingsCache is a thread-safe map from blessings to cache key.
+// clientBlessingsCache is a thread-safe map from blessings to cache id.
 type clientBlessingsCache struct {
 	sync.RWMutex
-	m   map[security.Blessings]clientCacheValue
-	key uint64
+	m     map[[sha256.Size]byte]clientCacheValue
+	curId uint64
 }
 
 type clientCacheValue struct {
-	key uint64
-	// ack is set to true once the server has confirmed receipt of the cache key.
-	// Clients that insert into the cache when ack is false must send both the key
+	id uint64
+	// ack is set to true once the server has confirmed receipt of the cache id.
+	// Clients that insert into the cache when ack is false must send both the id
 	// and the blessings.
 	ack bool
 }
 
-// clientBlessingsKey is the key used to retrieve the clientBlessingsCache from the VCDataCache.
-type clientBlessingsKey struct{}
+// clientBlessingsCacheKey is the key used to retrieve the clientBlessingsCache from the VCDataCache.
+type clientBlessingsCacheKey struct{}
 
 func newClientBlessingsCache() interface{} {
-	return &clientBlessingsCache{m: make(map[security.Blessings]clientCacheValue)}
+	return &clientBlessingsCache{m: make(map[[sha256.Size]byte]clientCacheValue)}
+}
+
+func getBlessingsHashKey(blessings security.Blessings) (key [sha256.Size]byte) {
+	h := sha256.New()
+	for _, chain := range security.MarshalBlessings(blessings).CertificateChains {
+		if len(chain) == 0 {
+			continue
+		}
+		cert := chain[len(chain)-1]
+		s := sha256.Sum256(cert.Signature.R)
+		h.Write(s[:])
+		s = sha256.Sum256(cert.Signature.S)
+		h.Write(s[:])
+	}
+	copy(key[:], h.Sum(nil))
+	return
 }
 
 func (c *clientBlessingsCache) getOrInsert(blessings security.Blessings) ipc.BlessingsRequest {
+	key := getBlessingsHashKey(blessings)
 	c.RLock()
-	val, exists := c.m[blessings]
+	val, exists := c.m[key]
 	c.RUnlock()
 	if exists {
 		return c.makeBlessingsRequest(val, blessings)
 	}
-	// if the val doesn't exist we must create a new key, update the cache, and send the key and blessings.
+	// If the val doesn't exist we must create a new id, update the cache, and send the id and blessings.
 	c.Lock()
-	defer c.Unlock()
-	// we must check that the val wasn't inserted in the time we changed locks.
-	val, exists = c.m[blessings]
-	if exists {
-		return c.makeBlessingsRequest(val, blessings)
+	// We must check that the val wasn't inserted in the time we changed locks.
+	val, exists = c.m[key]
+	if !exists {
+		val = clientCacheValue{id: c.nextIdLocked()}
+		c.m[key] = val
 	}
-	newVal := clientCacheValue{key: c.nextKeyLocked()}
-	c.m[blessings] = newVal
-	return c.makeBlessingsRequest(newVal, blessings)
+	c.Unlock()
+	return c.makeBlessingsRequest(val, blessings)
 }
 
 func (c *clientBlessingsCache) acknowledge(blessings security.Blessings) {
+	key := getBlessingsHashKey(blessings)
 	c.Lock()
-	val := c.m[blessings]
+	val := c.m[key]
 	val.ack = true
-	c.m[blessings] = val
+	c.m[key] = val
 	c.Unlock()
 }
 
 func (c *clientBlessingsCache) makeBlessingsRequest(val clientCacheValue, blessings security.Blessings) ipc.BlessingsRequest {
 	if val.ack {
 		// when the value is acknowledged, only send the key, since the server has confirmed that it knows the key.
-		return ipc.BlessingsRequest{Key: val.key}
+		return ipc.BlessingsRequest{Key: val.id}
 	}
 	// otherwise we still need to send both key and blessings, but we must ensure that we send the same key.
 	wireBlessings := security.MarshalBlessings(blessings)
-	return ipc.BlessingsRequest{val.key, &wireBlessings}
+	return ipc.BlessingsRequest{val.id, &wireBlessings}
 }
 
-// nextKeyLocked creates a new key for inserting blessings. It must be called after acquiring a writer lock.
-func (c *clientBlessingsCache) nextKeyLocked() uint64 {
-	c.key++
-	return c.key
+// nextIdLocked creates a new id for inserting blessings. It must be called after acquiring a writer lock.
+func (c *clientBlessingsCache) nextIdLocked() uint64 {
+	c.curId++
+	return c.curId
 }
 
 // serverBlessingsCache is a thread-safe map from cache key to blessings.
@@ -107,8 +125,8 @@
 	m map[uint64]security.Blessings
 }
 
-// serverBlessingsKey is the key used to retrieve the serverBlessingsCache from the VCDataCache.
-type serverBlessingsKey struct{}
+// serverBlessingsCacheKey is the key used to retrieve the serverBlessingsCache from the VCDataCache.
+type serverBlessingsCacheKey struct{}
 
 func newServerBlessingsCache() interface{} {
 	return &serverBlessingsCache{m: make(map[uint64]security.Blessings)}
@@ -131,6 +149,8 @@
 		stats.recordBlessingCache(true)
 		return cached, nil
 	}
+	// Always count the slow path as a cache miss since we do not get the benefit of sending only the cache key.
+	stats.recordBlessingCache(false)
 	// Slowpath, might need to update the cache, or check that the received blessings are
 	// the same as what's in the cache.
 	recv, err := security.NewBlessings(*req.Blessings)
@@ -144,10 +164,8 @@
 		if !reflect.DeepEqual(cached, recv) {
 			return nil, fmt.Errorf("client sent invalid Blessings")
 		}
-		stats.recordBlessingCache(true)
 		return cached, nil
 	}
 	c.m[req.Key] = recv
-	stats.recordBlessingCache(false)
 	return recv, nil
 }
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 6ef039b..a472e68 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -736,8 +736,8 @@
 	// Encode the Blessings information for the client to authorize the flow.
 	var blessingsRequest ipc.BlessingsRequest
 	if fc.flow.LocalPrincipal() != nil {
-		localBlessings := fc.flow.LocalPrincipal().BlessingStore().ForPeer(fc.server...)
-		blessingsRequest = clientEncodeBlessings(fc.flow.VCDataCache(), localBlessings)
+		fc.blessings = fc.flow.LocalPrincipal().BlessingStore().ForPeer(fc.server...)
+		blessingsRequest = clientEncodeBlessings(fc.flow.VCDataCache(), fc.blessings)
 	}
 	// TODO(suharshs, ataly): Make security.Discharge a vdl type.
 	anyDischarges := make([]vdlutil.Any, len(fc.discharges))
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 432242e..e9b7066 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -1118,7 +1118,9 @@
 		fs.server.streamMgr.ShutdownEndpoint(fs.RemoteEndpoint())
 		return old_verror.BadProtocolf("ipc: blessings cache failed: %v", err)
 	}
-	fs.ackBlessings = true
+	if fs.clientBlessings != nil {
+		fs.ackBlessings = true
+	}
 
 	// TODO(suharshs, ataly): Make security.Discharge a vdl type.
 	for i, d := range req.Discharges {
diff --git a/security/agent/client.go b/security/agent/client.go
index af30ec3..0c2912a 100644
--- a/security/agent/client.go
+++ b/security/agent/client.go
@@ -268,7 +268,7 @@
 	if err != nil {
 		return err
 	}
-	return b.caller.call("BlessingRootsAdd", results(), marshalledKey, blessing)
+	return b.caller.call("BlessingRootsRecognized", results(), marshalledKey, blessing)
 }
 
 func (b *blessingRoots) DebugString() (s string) {
diff --git a/security/agent/test.sh b/security/agent/test.sh
index 2e574a6..f4aaeba 100755
--- a/security/agent/test.sh
+++ b/security/agent/test.sh
@@ -9,6 +9,7 @@
 build() {
   AGENTD_BIN="$(shell_test::build_go_binary 'v.io/core/veyron/security/agent/agentd')"
   PINGPONG_BIN="$(shell_test::build_go_binary 'v.io/core/veyron/security/agent/pingpong')"
+  TESTPRINCIPAL_BIN="$(shell_test::build_go_binary 'v.io/core/veyron/security/agent/test_principal')"
   VRUN="$(shell_test::build_go_binary 'v.io/core/veyron/tools/vrun')"
 }
 
@@ -21,20 +22,33 @@
 
   shell_test::setup_server_test || shell_test::fail "line ${LINENO} failed to setup server test"
   export VEYRON_CREDENTIALS="$(shell::tmp_dir)"
+  # Test all methods of the principal interface.
+  # (Errors are printed to STDERR)
+  echo -n "agentd: test_principal..."
+  "${AGENTD_BIN}" "${TESTPRINCIPAL_BIN}" >/dev/null || shell_test::fail "line ${LINENO}"
+  echo "OK"
+
+  # Use a different credentials directory for future tests
+  # since test_principal "pollutes" it.
+  export VEYRON_CREDENTIALS="$(shell::tmp_dir)"
 
   # Test running a single app.
+  echo -n "agentd: single app..."
   shell_test::start_server "${PINGPONG_BIN}" --server
   "${AGENTD_BIN}" --v=4 "${PINGPONG_BIN}" || shell_test::fail "line ${LINENO}: failed to run pingpong"
   local -r CREDENTIALS_UNDER_AGENT=$("${AGENTD_BIN}" bash -c 'echo ${VEYRON_CREDENTIALS}')
   if [[ "${CREDENTIALS_UNDER_AGENT}" != "" ]]; then
     shell_test::fail "line ${LINENO}: VEYRON_CREDENTIALS should not be set when running under the agent(${CREDENTIALS_UNDER_AGENT})"
   fi
+  echo "OK"
 
   # Test running multiple apps connecting to the same agent.
   # Make sure the testchild.sh script get the same shell_test_BIN_DIR as the main script.
+  echo -n "agentd: multiple apps..."
   export shell_test_BIN_DIR="${shell_test_BIN_DIR}"
   RESULT=$(shell::check_result "${AGENTD_BIN}" bash "$(go list -f {{.Dir}} v.io/core/veyron/security/agent)/testchild.sh")
   shell_test::assert_eq "${RESULT}" "0" "${LINENO}"
+  echo "OK"
 
   # Verify the restart feature.
   local -r COUNTER_FILE="${WORKDIR}/counter"
@@ -49,22 +63,28 @@
 EOF
   )
   # Have the agent restart the child while its exit code is 0.
+  echo -n "agentd: restart child while its exit code is 0..."
   echo "0" > "${COUNTER_FILE}"
   RESULT=$(shell::check_result "${AGENTD_BIN}" --additional_principals="$(shell::tmp_dir)" --restart_exit_code="0" bash -c "${SCRIPT}")
   shell_test::assert_eq "${RESULT}" "1" "${LINENO}"
   [[ $(<"${COUNTER_FILE}") -eq 5 ]] || shell_test::fail "Failed"
+  echo "OK"
 
   # Have the agent restart the child while its exit code is !0.
+  echo -n "agentd: restart child while its exit code != 0..."
   echo "0" > "${COUNTER_FILE}"
   RESULT=$(shell::check_result "${AGENTD_BIN}" --additional_principals="$(shell::tmp_dir)" --restart_exit_code="!0" bash -c "${SCRIPT}")
   shell_test::assert_eq "${RESULT}" "0" "${LINENO}"
   [[ $(<"${COUNTER_FILE}") -eq 1 ]] || shell_test::fail "Failed"
+  echo "OK"
 
   # Have the agent restart the child while its exit code is != 1.
+  echo -n "agentd: restart child while its exit code != 1..."
   echo "0" > "${COUNTER_FILE}"
   RESULT=$(shell::check_result "${AGENTD_BIN}" --additional_principals="$(shell::tmp_dir)" --restart_exit_code="!1" bash -c "${SCRIPT}")
   shell_test::assert_eq "${RESULT}" "1" "${LINENO}"
   [[ $(<"${COUNTER_FILE}") -eq 5 ]] || shell_test::fail "Failed"
+  echo "OK"
 
   shell_test::pass
 }
diff --git a/security/agent/test_principal/main.go b/security/agent/test_principal/main.go
new file mode 100644
index 0000000..b8dc549
--- /dev/null
+++ b/security/agent/test_principal/main.go
@@ -0,0 +1,112 @@
+package main
+
+import (
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"fmt"
+	"os"
+	"reflect"
+	"runtime"
+
+	_ "v.io/core/veyron/profiles"
+	"v.io/core/veyron2"
+	"v.io/core/veyron2/security"
+)
+
+func newKey() security.PublicKey {
+	k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		panic(err)
+	}
+	return security.NewECDSAPublicKey(&k.PublicKey)
+}
+
+func main() {
+	ctx, shutdown := veyron2.Init()
+	defer shutdown()
+	p := veyron2.GetPrincipal(ctx)
+
+	var errors []string
+	defer func() {
+		if len(errors) == 0 {
+			return
+		}
+		// Print out all errors and exit with failure.
+		for _, e := range errors {
+			fmt.Fprintln(os.Stderr, e)
+		}
+		os.Exit(1)
+	}()
+	errorf := func(format string, args ...interface{}) {
+		_, file, line, _ := runtime.Caller(1)
+		errors = append(errors, fmt.Sprintf("%v:%d: %v", file, line, fmt.Sprintf(format, args...)))
+	}
+
+	// BlessSelf
+	b, err := p.BlessSelf("batman")
+	if err != nil {
+		errorf("BlessSelf: %v", err)
+	}
+	// Bless
+	if _, err := p.Bless(newKey(), b, "delegate", security.UnconstrainedUse()); err != nil {
+		errorf("Bless: %v", err)
+	}
+	// Sign & PublicKey
+	signature, err := p.Sign([]byte("bugs bunny"))
+	if err != nil {
+		errorf("Sign: %v", err)
+	}
+	if !signature.Verify(p.PublicKey(), []byte("bugs bunny")) {
+		errorf("signature.Verify: %v", err)
+	}
+	// MintDischarge
+	cav, err := security.MethodCaveat("method")
+	if err != nil {
+		errorf("security.MethodCaveat: %v", err)
+	}
+	tpcav, err := security.NewPublicKeyCaveat(p.PublicKey(), "location", security.ThirdPartyRequirements{}, cav)
+	if err != nil {
+		errorf("security.NewPublicKeyCaveat: %v", err)
+	}
+	if _, err := p.MintDischarge(tpcav, cav); err != nil {
+		errorf("MintDischarge: %v", err)
+	}
+	// BlessingRoots
+	if err := p.Roots().Recognized(p.PublicKey(), "batman"); err == nil {
+		errorf("Roots().Recognized returned nil")
+	}
+	if err := p.AddToRoots(b); err != nil {
+		errorf("AddToRoots: %v", err)
+	}
+	if err := p.Roots().Recognized(p.PublicKey(), "batman"); err != nil {
+		errorf("Roots().Recognized: %v", err)
+	}
+	// BlessingStore: Defaults
+	if err := p.BlessingStore().SetDefault(nil); err != nil {
+		errorf("BlessingStore().SetDefault: %v", err)
+	}
+	if def := p.BlessingStore().Default(); def != nil {
+		errorf("BlessingStore().Default returned %v, want nil", def)
+	}
+	if err := p.BlessingStore().SetDefault(b); err != nil {
+		errorf("BlessingStore().SetDefault: %v", err)
+	}
+	if def := p.BlessingStore().Default(); !reflect.DeepEqual(def, b) {
+		errorf("BlessingStore().Default returned [%v], want [%v]", def, b)
+	}
+	// BlessingStore: Set & ForPeer
+	// First, clear out the self-generated default of the blessing store.
+	if _, err := p.BlessingStore().Set(nil, security.AllPrincipals); err != nil {
+		errorf("BlessingStore().Set(nil, %q): %v", security.AllPrincipals, err)
+	}
+	if forpeer := p.BlessingStore().ForPeer("superman/friend"); forpeer != nil {
+		errorf("BlessingStore().ForPeer unexpectedly returned %v", forpeer)
+	}
+	if old, err := p.BlessingStore().Set(b, "superman/..."); old != nil || err != nil {
+		errorf("BlessingStore().Set returned (%v, %v)", old, err)
+	}
+	if forpeer := p.BlessingStore().ForPeer("superman/friend"); !reflect.DeepEqual(forpeer, b) {
+		errorf("BlessingStore().ForPeer returned %v and not %v", forpeer, b)
+	}
+}
diff --git a/security/blessingstore.go b/security/blessingstore.go
index 46636d4..74ed21c 100644
--- a/security/blessingstore.go
+++ b/security/blessingstore.go
@@ -116,7 +116,7 @@
 func (bs *blessingStore) SetDefault(blessings security.Blessings) error {
 	bs.mu.Lock()
 	defer bs.mu.Unlock()
-	if !reflect.DeepEqual(blessings.PublicKey(), bs.publicKey) {
+	if blessings != nil && !reflect.DeepEqual(blessings.PublicKey(), bs.publicKey) {
 		return errStoreAddMismatch
 	}
 	oldDefault := bs.state.Default
diff --git a/security/blessingstore_test.go b/security/blessingstore_test.go
index a3e59d6..d328da4 100644
--- a/security/blessingstore_test.go
+++ b/security/blessingstore_test.go
@@ -51,6 +51,13 @@
 	if got := s.Default(); !reflect.DeepEqual(got, currentDefault) {
 		return fmt.Errorf("Default(): got: %v, want: %v", got, currentDefault)
 	}
+	// SetDefault(nil)
+	if err := s.SetDefault(nil); err != nil {
+		return fmt.Errorf("SetDefault(nil): %v", err)
+	}
+	if got := s.Default(); got != nil {
+		return fmt.Errorf("Default returned %v, want nil", got)
+	}
 	if err := s.SetDefault(t.def); err != nil {
 		return fmt.Errorf("SetDefault(%v): %v", t.def, err)
 	}