js: Use full blessings objects in Javascript

MultiPart: 1/2
Change-Id: I4bced36c5b38f61c5e13d0ca4e09cd6f550a1d80
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
index 8ff3aad..072765b 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
@@ -22,6 +22,7 @@
 
 // Types:
 var _type1 = new vdl.Type();
+var _type10 = new vdl.Type();
 var _type2 = new vdl.Type();
 var _type3 = new vdl.Type();
 var _type4 = new vdl.Type();
@@ -40,6 +41,9 @@
 _type1.kind = vdl.kind.LIST;
 _type1.name = "";
 _type1.elem = _typeRpcCallOption;
+_type10.kind = vdl.kind.LIST;
+_type10.name = "";
+_type10.elem = new security.WireBlessings()._type;
 _type2.kind = vdl.kind.LIST;
 _type2.name = "";
 _type2.elem = new security.BlessingPattern()._type;
@@ -51,20 +55,20 @@
 _type4.elem = _typeRpcServerOption;
 _type5.kind = vdl.kind.LIST;
 _type5.name = "";
-_type5.elem = new security.Caveat()._type;
+_type5.elem = vdl.types.BYTE;
 _type6.kind = vdl.kind.LIST;
 _type6.name = "";
-_type6.elem = vdl.types.STRING;
-_type7.kind = vdl.kind.MAP;
+_type6.elem = new security.Caveat()._type;
+_type7.kind = vdl.kind.LIST;
 _type7.name = "";
-_type7.elem = new principal.BlessingsId()._type;
-_type7.key = new security.BlessingPattern()._type;
-_type8.kind = vdl.kind.LIST;
+_type7.elem = vdl.types.STRING;
+_type8.kind = vdl.kind.MAP;
 _type8.name = "";
-_type8.elem = new signature.Interface()._type;
+_type8.elem = new principal.BlessingsId()._type;
+_type8.key = new security.BlessingPattern()._type;
 _type9.kind = vdl.kind.LIST;
 _type9.name = "";
-_type9.elem = new principal.BlessingsHandle()._type;
+_type9.elem = new signature.Interface()._type;
 _typeGranterHandle.kind = vdl.kind.INT32;
 _typeGranterHandle.name = "v.io/x/ref/services/wspr/internal/app.GranterHandle";
 _typeGranterRequest.kind = vdl.kind.STRUCT;
@@ -72,7 +76,7 @@
 _typeGranterRequest.fields = [{name: "GranterHandle", type: _typeGranterHandle}, {name: "Call", type: new server.SecurityCall()._type}];
 _typeGranterResponse.kind = vdl.kind.STRUCT;
 _typeGranterResponse.name = "v.io/x/ref/services/wspr/internal/app.GranterResponse";
-_typeGranterResponse.fields = [{name: "Blessings", type: new principal.BlessingsHandle()._type}, {name: "Err", type: vdl.types.ERROR}];
+_typeGranterResponse.fields = [{name: "Blessings", type: new security.WireBlessings()._type}, {name: "Err", type: vdl.types.ERROR}];
 _typeRpcCallOption.kind = vdl.kind.UNION;
 _typeRpcCallOption.name = "v.io/x/ref/services/wspr/internal/app.RpcCallOption";
 _typeRpcCallOption.fields = [{name: "AllowedServersPolicy", type: _type2}, {name: "RetryTimeout", type: new time.Duration()._type}, {name: "Granter", type: _typeGranterHandle}];
@@ -86,6 +90,7 @@
 _typeRpcServerOption.name = "v.io/x/ref/services/wspr/internal/app.RpcServerOption";
 _typeRpcServerOption.fields = [{name: "IsLeaf", type: vdl.types.BOOL}, {name: "ServesMountTable", type: vdl.types.BOOL}];
 _type1.freeze();
+_type10.freeze();
 _type2.freeze();
 _type3.freeze();
 _type4.freeze();
@@ -151,17 +156,7 @@
 };
     
       
-Controller.prototype.unlinkBlessings = function(ctx, serverCall, handle) {
-  throw new Error('Method UnlinkBlessings not implemented');
-};
-    
-      
-Controller.prototype.blessingsDebugString = function(ctx, serverCall, handle) {
-  throw new Error('Method BlessingsDebugString not implemented');
-};
-    
-      
-Controller.prototype.bless = function(ctx, serverCall, publicKey, handle, extension, caveat) {
+Controller.prototype.bless = function(ctx, serverCall, publicKey, blessings, extension, caveat) {
   throw new Error('Method Bless not implemented');
 };
     
@@ -171,12 +166,12 @@
 };
     
       
-Controller.prototype.addToRoots = function(ctx, serverCall, handle) {
+Controller.prototype.addToRoots = function(ctx, serverCall, blessings) {
   throw new Error('Method AddToRoots not implemented');
 };
     
       
-Controller.prototype.blessingStoreSet = function(ctx, serverCall, blessingsHandle, pattern) {
+Controller.prototype.blessingStoreSet = function(ctx, serverCall, blessingsblessings, pattern) {
   throw new Error('Method BlessingStoreSet not implemented');
 };
     
@@ -186,7 +181,7 @@
 };
     
       
-Controller.prototype.blessingStoreSetDefault = function(ctx, serverCall, blessingsHandle) {
+Controller.prototype.blessingStoreSetDefault = function(ctx, serverCall, blessingsblessings) {
   throw new Error('Method BlessingStoreSetDefault not implemented');
 };
     
@@ -320,54 +315,17 @@
     
       
     {
-    name: 'UnlinkBlessings',
-    doc: "// UnlinkBlessings removes the given blessings from the blessings store.",
-    inArgs: [{
-      name: 'handle',
-      doc: "",
-      type: new principal.BlessingsHandle()._type
-    },
-    ],
-    outArgs: [],
-    inStream: null,
-    outStream: null,
-    tags: []
-  },
-    
-      
-    {
-    name: 'BlessingsDebugString',
-    doc: "// BlessingsDebugString gets a string useful for debugging blessings.",
-    inArgs: [{
-      name: 'handle',
-      doc: "",
-      type: new principal.BlessingsHandle()._type
-    },
-    ],
-    outArgs: [{
-      name: '',
-      doc: "",
-      type: vdl.types.STRING
-    },
-    ],
-    inStream: null,
-    outStream: null,
-    tags: []
-  },
-    
-      
-    {
     name: 'Bless',
     doc: "// Bless binds extensions of blessings held by this principal to\n// another principal (represented by its public key).",
     inArgs: [{
       name: 'publicKey',
       doc: "",
-      type: vdl.types.STRING
+      type: _type5
     },
     {
-      name: 'handle',
+      name: 'blessings',
       doc: "",
-      type: new principal.BlessingsHandle()._type
+      type: new security.WireBlessings()._type
     },
     {
       name: 'extension',
@@ -377,7 +335,7 @@
     {
       name: 'caveat',
       doc: "",
-      type: _type5
+      type: _type6
     },
     ],
     outArgs: [{
@@ -403,7 +361,7 @@
     {
       name: 'caveats',
       doc: "",
-      type: _type5
+      type: _type6
     },
     ],
     outArgs: [{
@@ -422,9 +380,9 @@
     name: 'AddToRoots',
     doc: "// AddToRoots adds the provided blessing as a root.",
     inArgs: [{
-      name: 'handle',
+      name: 'blessings',
       doc: "",
-      type: new principal.BlessingsHandle()._type
+      type: new security.WireBlessings()._type
     },
     ],
     outArgs: [],
@@ -438,9 +396,9 @@
     name: 'BlessingStoreSet',
     doc: "// BlessingStoreSet puts the specified blessing in the blessing store under the provided pattern.",
     inArgs: [{
-      name: 'blessingsHandle',
+      name: 'blessingsblessings',
       doc: "",
-      type: new principal.BlessingsHandle()._type
+      type: new security.WireBlessings()._type
     },
     {
       name: 'pattern',
@@ -466,7 +424,7 @@
     inArgs: [{
       name: 'peerBlessings',
       doc: "",
-      type: _type6
+      type: _type7
     },
     ],
     outArgs: [{
@@ -485,9 +443,9 @@
     name: 'BlessingStoreSetDefault',
     doc: "// BlessingStoreSetDefault sets the default blessings.",
     inArgs: [{
-      name: 'blessingsHandle',
+      name: 'blessingsblessings',
       doc: "",
-      type: new principal.BlessingsHandle()._type
+      type: new security.WireBlessings()._type
     },
     ],
     outArgs: [],
@@ -520,7 +478,7 @@
     outArgs: [{
       name: '',
       doc: "",
-      type: vdl.types.STRING
+      type: _type5
     },
     ],
     inStream: null,
@@ -536,7 +494,7 @@
     outArgs: [{
       name: '',
       doc: "",
-      type: _type7
+      type: _type8
     },
     ],
     inStream: null,
@@ -578,7 +536,7 @@
     outArgs: [{
       name: '',
       doc: "",
-      type: _type6
+      type: _type7
     },
     ],
     inStream: null,
@@ -599,7 +557,7 @@
     outArgs: [{
       name: '',
       doc: "",
-      type: _type8
+      type: _type9
     },
     ],
     inStream: null,
@@ -614,7 +572,7 @@
     inArgs: [{
       name: 'toJoin',
       doc: "",
-      type: _type9
+      type: _type10
     },
     ],
     outArgs: [{
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js
index f11c056..aefc340 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js
@@ -4,12 +4,12 @@
 
 // This file was auto-generated by the vanadium vdl tool.
 var vdl = require('../../../../../../../../vdl');
-var canonicalize = require('../../../../../../../../vdl/canonicalize');
 
 
 
 
 
+var security = require('./../../../../../../v23/security');
 
 module.exports = {};
 
@@ -19,45 +19,32 @@
 var _typeBlessingsCacheAddMessage = new vdl.Type();
 var _typeBlessingsCacheDeleteMessage = new vdl.Type();
 var _typeBlessingsCacheMessage = new vdl.Type();
-var _typeBlessingsHandle = new vdl.Type();
 var _typeBlessingsId = new vdl.Type();
-var _typeJsBlessings = new vdl.Type();
 _typeBlessingsCacheAddMessage.kind = vdl.kind.STRUCT;
 _typeBlessingsCacheAddMessage.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsCacheAddMessage";
-_typeBlessingsCacheAddMessage.fields = [{name: "CacheId", type: _typeBlessingsId}, {name: "Blessings", type: _typeJsBlessings}];
+_typeBlessingsCacheAddMessage.fields = [{name: "CacheId", type: _typeBlessingsId}, {name: "Blessings", type: new security.WireBlessings()._type}];
 _typeBlessingsCacheDeleteMessage.kind = vdl.kind.STRUCT;
 _typeBlessingsCacheDeleteMessage.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsCacheDeleteMessage";
 _typeBlessingsCacheDeleteMessage.fields = [{name: "CacheId", type: _typeBlessingsId}, {name: "DeleteAfter", type: vdl.types.UINT32}];
 _typeBlessingsCacheMessage.kind = vdl.kind.UNION;
 _typeBlessingsCacheMessage.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsCacheMessage";
 _typeBlessingsCacheMessage.fields = [{name: "Add", type: _typeBlessingsCacheAddMessage}, {name: "Delete", type: _typeBlessingsCacheDeleteMessage}];
-_typeBlessingsHandle.kind = vdl.kind.INT32;
-_typeBlessingsHandle.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsHandle";
 _typeBlessingsId.kind = vdl.kind.UINT32;
 _typeBlessingsId.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsId";
-_typeJsBlessings.kind = vdl.kind.STRUCT;
-_typeJsBlessings.name = "v.io/x/ref/services/wspr/internal/principal.JsBlessings";
-_typeJsBlessings.fields = [{name: "Handle", type: _typeBlessingsHandle}, {name: "PublicKey", type: vdl.types.STRING}];
 _typeBlessingsCacheAddMessage.freeze();
 _typeBlessingsCacheDeleteMessage.freeze();
 _typeBlessingsCacheMessage.freeze();
-_typeBlessingsHandle.freeze();
 _typeBlessingsId.freeze();
-_typeJsBlessings.freeze();
 module.exports.BlessingsCacheAddMessage = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsCacheAddMessage));
 module.exports.BlessingsCacheDeleteMessage = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsCacheDeleteMessage));
 module.exports.BlessingsCacheMessage = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsCacheMessage));
-module.exports.BlessingsHandle = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsHandle));
 module.exports.BlessingsId = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsId));
-module.exports.JsBlessings = (vdl.registry.lookupOrCreateConstructor(_typeJsBlessings));
 
 
 
 
 // Consts:
 
-  module.exports.ZeroHandle = canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeBlessingsHandle))(0, true), _typeBlessingsHandle);
-
 
 
 // Errors:
@@ -67,8 +54,6 @@
 // Services:
 
    
-
-   
  
 
 
diff --git a/src/proxy/stream-handler.js b/src/proxy/stream-handler.js
index a4a04b6..9566da0 100644
--- a/src/proxy/stream-handler.js
+++ b/src/proxy/stream-handler.js
@@ -64,7 +64,7 @@
   return vom.decode(data, false, this._typeDecoder).then(function(data) {
     if (data instanceof BlessingsId) {
       var runtime = runtimeFromContext(handler._ctx);
-      runtime.blessingsManager.blessingsFromId(data)
+      runtime.blessingsCache.blessingsFromId(data)
       .then(function(blessings) {
         blessings.retain();
         handler._stream._queueRead(blessings);
diff --git a/src/proxy/stream.js b/src/proxy/stream.js
index 81fa654..f7be945 100644
--- a/src/proxy/stream.js
+++ b/src/proxy/stream.js
@@ -13,7 +13,6 @@
 var inherits = require('inherits');
 var reduce = require('../vdl/canonicalize').reduce;
 var unwrap = require('../vdl/type-util').unwrap;
-var Blessings = require('../security/blessings');
 var ServerRpcReply =
   require('../gen-vdl/v.io/x/ref/services/wspr/internal/lib').ServerRpcReply;
 var hexVom = require('../lib/hex-vom');
@@ -165,9 +164,6 @@
       this.isClient ? 'inStream' : 'outStream', 'type. Tried to queue', chunk);
     return;
   }
-  if (chunk instanceof Blessings) {
-    chunk = chunk.convertToJsBlessings();
-  }
   var object = {
     id: this.flowId,
     data: hexVom.encode(chunk, this.writeType, this._typeEncoder),
diff --git a/src/rpc/client.js b/src/rpc/client.js
index e816fb5..b618c5c 100644
--- a/src/rpc/client.js
+++ b/src/rpc/client.js
@@ -38,7 +38,6 @@
 var vlog = require('../lib/vlog');
 var SharedContextKeys = require('../runtime/shared-context-keys');
 var vtrace = require('../vtrace');
-var Blessings = require('../security/blessings');
 var ByteArrayMessageWriter = require('../vom/byte-array-message-writer');
 var BlessingsId =
   require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').BlessingsId;
@@ -72,13 +71,7 @@
 function convertOutArg(ctx, arg, type, controller) {
   if (arg instanceof BlessingsId) {
     var runtime = runtimeFromContext(ctx);
-    return runtime.blessingsManager.blessingsFromId(arg)
-    .then(function(blessings) {
-      if (blessings) {
-        blessings.retain();
-      }
-      return blessings;
-    });
+    return runtime.blessingsCache.blessingsFromId(arg);
   }
 
   // There's no protection against bad out args if it's a JSValue.
@@ -322,11 +315,7 @@
   var encoder = new Encoder(writer, this._typeEncoder);
   encoder.encode(header);
   for (var i = 0; i < this._args.length; i++) {
-    var o = this._args[i];
-    if (o instanceof Blessings) {
-      o = o.convertToJsBlessings();
-    }
-    encoder.encode(o);
+    encoder.encode(this._args[i]);
   }
   return byteUtil.bytes2Hex(writer.getBytes());
 };
diff --git a/src/rpc/create-server-call.js b/src/rpc/create-server-call.js
index 616f787..b584027 100644
--- a/src/rpc/create-server-call.js
+++ b/src/rpc/create-server-call.js
@@ -11,7 +11,7 @@
  * before the user is given the object.
  * @private
  */
-function createServerCall(request, blessingsManager) {
+function createServerCall(request, blessingsCache) {
   var serverCall = new ServerCall();
   if (request instanceof ServerCall) {
     serverCall.securityCall = request.securityCall.clone();
@@ -20,12 +20,12 @@
   } else {
     var promises = [];
     promises.push(createSecurityCall(request.call.securityCall,
-      blessingsManager).then(function(securityCall) {
+      blessingsCache).then(function(securityCall) {
       serverCall.securityCall = securityCall;
     }));
     if (request.call.grantedBlessings) {
       promises.push(
-        blessingsManager.blessingsFromId(request.call.grantedBlessings)
+        blessingsCache.blessingsFromId(request.call.grantedBlessings)
         .then(function(grantedBlessings) {
           serverCall.grantedBlessings = grantedBlessings;
         })
diff --git a/src/rpc/granter-router.js b/src/rpc/granter-router.js
index 075d46c..5112e41 100644
--- a/src/rpc/granter-router.js
+++ b/src/rpc/granter-router.js
@@ -25,14 +25,14 @@
  * grant requests.
  * @private
  */
-function GranterRouter(proxy, rootCtx, blessingsManager) {
+function GranterRouter(proxy, rootCtx, blessingsCache) {
   proxy.addIncomingHandler(Incoming.GRANTER_REQUEST, this);
 
   this._proxy = proxy;
   this._rootCtx = rootCtx;
   this.nextGranterId = 0;
   this.activeGranters = {};
-  this._blessingsManager = blessingsManager;
+  this._blessingsCache = blessingsCache;
 }
 
 /**
@@ -66,7 +66,7 @@
         new verror.NoExistError(router._rootCtx, 'unknown granter'));
     }
     delete router.activeGranters[request.granterHandle];
-    return createSecurityCall(request.call, router._blessingsManager);
+    return createSecurityCall(request.call, router._blessingsCache);
   }, function(e) {
     return Promise.reject(
       new verror.NoExistError(router._rootCtx, 'failed to decode message'));
@@ -88,7 +88,7 @@
               });
     return promise;
   }).then(function(outBlessings) {
-    var result = new GranterResponse({blessings: outBlessings[0]._id});
+    var result = new GranterResponse({blessings: outBlessings[0]});
     var data = hexVom.encode(result);
     router._proxy.sendRequest(data, Outgoing.GRANTER_RESPONSE, null,
       messageId);
diff --git a/src/rpc/server-router.js b/src/rpc/server-router.js
index 4fae75a..4c649ae 100644
--- a/src/rpc/server-router.js
+++ b/src/rpc/server-router.js
@@ -54,7 +54,7 @@
  * @private
  */
 var Router = function(
-  proxy, appName, rootCtx, controller, caveatRegistry, blessingsManager) {
+  proxy, appName, rootCtx, controller, caveatRegistry, blessingsCache) {
   this._servers = {};
   this._proxy = proxy;
   this._streamMap = {};
@@ -64,7 +64,7 @@
   this._caveatRegistry = caveatRegistry;
   this._outstandingRequestForId = {};
   this._controller = controller;
-  this._blessingsManager = blessingsManager;
+  this._blessingsCache = blessingsCache;
   this._typeEncoder = proxy.typeEncoder;
   this._typeDecoder = proxy.typeDecoder;
 
@@ -138,7 +138,7 @@
                                 null, messageId);
       return;
     }
-    return createSecurityCall(decodedRequest.call, router._blessingsManager)
+    return createSecurityCall(decodedRequest.call, router._blessingsCache)
     .then(function(call) {
       return server.handleAuthorization(decodedRequest.handle, ctx, call);
     });
@@ -186,7 +186,7 @@
 
 Router.prototype.handleCaveatValidationRequest = function(messageId, request) {
   var router = this;
-  createSecurityCall(request.call, this._blessingsManager)
+  createSecurityCall(request.call, this._blessingsCache)
   .then(function(call) {
     var ctx = router._rootCtx.withValue(SharedContextKeys.LANG_KEY,
       request.context.language);
@@ -339,7 +339,7 @@
     this._outstandingRequestForId[messageId] = 0;
     this.incrementOutstandingRequestForId(messageId);
     var globPattern = typeUtil.unwrap(request.args[0]);
-    return createServerCall(request, this._blessingsManager)
+    return createServerCall(request, this._blessingsCache)
     .then(function(call) {
       self.handleGlobRequest(messageId, call.securityCall.suffix,
                              server, new Glob(globPattern), ctx, call, invoker,
@@ -359,7 +359,7 @@
     }
     var unwrapped = typeUtil.unwrap(arg);
     if (unwrapped instanceof BlessingsId) {
-      return self._blessingsManager.blessingsFromId(unwrapped);
+      return self._blessingsCache.blessingsFromId(unwrapped);
     }
     return Promise.resolve(unwrapped);
   });
@@ -422,7 +422,7 @@
   var args;
   this._unwrapArgs(request.args, methodSig).then(function(unwrapped) {
     args = unwrapped;
-    return createServerCall(request, self._blessingsManager);
+    return createServerCall(request, self._blessingsCache);
   }).then(function(call) {
     var options = {
       methodName: methodName,
@@ -519,13 +519,8 @@
     stream: options.stream
   };
 
-  var rootCtx = this._rootCtx;
   var def = new Deferred();
   function InvocationFinishedCallback(err, results) {
-    // Note: We use the rootCtx here because we want to make this
-    // call to clean up the blessings even if the method invocation
-    // is cancelled.
-    call.securityCall.remoteBlessings.release(rootCtx);
     if (err) {
       return def.reject(err);
     }
@@ -615,7 +610,7 @@
       self.incrementOutstandingRequestForId(messageId);
       var nextInvoker;
       var subCall;
-      createServerCall(call, this._blessingsManager).then(function(servCall) {
+      createServerCall(call, this._blessingsCache).then(function(servCall) {
         subCall = servCall;
         subCall.securityCall.suffix = suffix;
         return server._handleLookup(suffix);
@@ -691,12 +686,6 @@
 
   var traceResponse = vtrace.response(ctx);
 
-  // Convert any Blessings to JsBlessings
-  for (var i = 0; i < results.length; ++i) {
-    if (results[i] instanceof Blessings) {
-      results[i] = results[i].convertToJsBlessings();
-    }
-  }
   // If this is a streaming request, queue up the final response after all
   // the other stream requests are done.
   var stream = this._streamMap[messageId];
diff --git a/src/runtime/index.js b/src/runtime/index.js
index 7c51044..7b7df1f 100644
--- a/src/runtime/index.js
+++ b/src/runtime/index.js
@@ -23,7 +23,7 @@
 var vtrace = require('../vtrace');
 var Controller =
   require('../gen-vdl/v.io/x/ref/services/wspr/internal/app').Controller;
-var BlessingsManager = require('../security/blessings-manager');
+var BlessingsCache = require('../security/blessings-cache');
 var BlessingsRouter = require('../security/blessings-router');
 
 module.exports = {
@@ -119,9 +119,9 @@
   this._name = options.appName;
   this._language = options.language;
   this.caveatRegistry = new CaveatValidatorRegistry();
-  this.blessingsManager = new BlessingsManager(this._controller);
+  this.blessingsCache = new BlessingsCache();
   this._blessingsRouter = new BlessingsRouter(this._getProxyConnection(),
-    this.blessingsManager);
+    this.blessingsCache);
 }
 
 inherits(Runtime, EE);
@@ -255,7 +255,7 @@
       this.getContext(),
       this._controller,
       this.caveatRegistry,
-      this.blessingsManager);
+      this.blessingsCache);
   }
   return this._router;
 };
@@ -270,7 +270,7 @@
     this._granterRouter = new GranterRouter(
       this._getProxyConnection(),
       this.getContext(),
-      this.blessingsManager);
+      this.blessingsCache);
   }
   return this._granterRouter;
 };
diff --git a/src/security/blessings-manager.js b/src/security/blessings-manager.js
deleted file mode 100644
index 723b1d7..0000000
--- a/src/security/blessings-manager.js
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/**
- * @fileoverview Manager of cache blessings. This differs from BlessingsCache
- * because it converts JsBlessings to Blessings objects.
- * TODO(bprosnitz) Remove this after switching to performing WireBlessings to
- * Blessings conversion with native types.
- * @private
- */
-
-var BlessingsCache = require('../security/blessings-cache');
-var Blessings = require('../security/blessings');
-
-
-module.exports = BlessingsManager;
-
-/*
- * TODO(bprosnitz) Replace this with just BlessingsCache after switching
- * to using native type conversion with blessings.
- */
-/*
- * @summary Manager of blessings received from WSPR.
- * @constructor
- * @inner
- */
-function BlessingsManager(controller) {
-  this._blessingsCache = new BlessingsCache();
-  this._controller = controller;
-}
-
-BlessingsManager.prototype.blessingsFromId = function(id) {
-  var controller = this._controller;
-  return this._blessingsCache.blessingsFromId(id).then(function(jsBless) {
-    if (!jsBless) {
-      return null;
-    }
-    return new Blessings(jsBless.handle, jsBless.publicKey, controller);
-  });
-};
-
-BlessingsManager.prototype.addBlessings = function(addMessage) {
-  return this._blessingsCache.addBlessings(addMessage);
-};
-
-BlessingsManager.prototype.deleteBlessings = function(deleteMessage) {
-  return this._blessingsCache.deleteBlessings(deleteMessage);
-};
diff --git a/src/security/blessings-router.js b/src/security/blessings-router.js
index 4254bf9..7436d97 100644
--- a/src/security/blessings-router.js
+++ b/src/security/blessings-router.js
@@ -19,8 +19,8 @@
  * @constructor
  * @private
  */
-function BlessingsRouter(proxy, blessingsManager) {
-  this._blessingsManager = blessingsManager;
+function BlessingsRouter(proxy, blessingsCache) {
+  this._blessingsCache = blessingsCache;
 
   proxy.addIncomingHandler(Incoming.BLESSINGS_CACHE_MESSAGE, this);
 }
@@ -39,9 +39,9 @@
   for (var i = 0; i < messages.length; i++) {
     var message = messages[i];
     if (message.hasOwnProperty('add')) {
-      this._blessingsManager.addBlessings(message.add);
+      this._blessingsCache.addBlessings(message.add);
     } else if (message.hasOwnProperty('delete')) {
-      this._blessingsManager.deleteBlessings(message.delete);
+      this._blessingsCache.deleteBlessings(message.delete);
     } else {
       vlog.logger.error('Unknown blessings cache message: ', message);
     }
diff --git a/src/security/blessings-util.js b/src/security/blessings-util.js
index a0d21c0..9f6ce4d 100644
--- a/src/security/blessings-util.js
+++ b/src/security/blessings-util.js
@@ -40,12 +40,8 @@
    if (args.length > 0 && typeof args[args.length - 1] === 'function') {
      cb = args.pop();
    }
-
    var blessingsList = args;
-   var handleList = blessingsList.map(function(blessings) {
-     return blessings._id;
-   });
 
    var runtime = runtimeFromContext(ctx);
-   return runtime._controller.unionOfBlessings(ctx, handleList, cb);
+   return runtime._controller.unionOfBlessings(ctx, blessingsList, cb);
 }
diff --git a/src/security/blessings.js b/src/security/blessings.js
index 2cb3f51..cdbb3d5 100644
--- a/src/security/blessings.js
+++ b/src/security/blessings.js
@@ -7,9 +7,16 @@
  * @private
  */
 
-var vlog = require('../lib/vlog');
-var JsBlessings =
-  require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').JsBlessings;
+var unwrap = require('../vdl/type-util').unwrap;
+var nativeTypeRegistry = require('../vdl/native-type-registry');
+var vdlSecurity = require('../gen-vdl/v.io/v23/security');
+
+module.exports = Blessings;
+
+var wireBlessingsType = vdlSecurity.WireBlessings.prototype._type;
+nativeTypeRegistry.registerFromNativeValue(Blessings, toWireBlessings,
+  wireBlessingsType);
+nativeTypeRegistry.registerFromWireValue(wireBlessingsType, fromWireBlessings);
 
 /**
  * @summary Blessings encapsulates all cryptographic operations
@@ -20,60 +27,80 @@
  * bound to a principal in a specific call.</p>
  * <p>Blessings objects are meant to be presented to other principals to
  * authenticate and authorize actions.</p>
+ * @property {module:vanadium.security.Certificate[]} chains Certificate chains.
+ * @property {module:vanadium.security.PublicKey} publicKey The public key.
  * @constructor
  * @memberof module:vanadium.security
  * @inner
  */
-function Blessings(id, publicKey, controller) {
-  this._id = id;
-  this._count = 1;
-  this._controller = controller;
-  this.publicKey = publicKey;
+function Blessings(wireblessings) {
+  var unwrappedWireBlessings = unwrap(wireblessings);
+  this.chains = unwrappedWireBlessings.certificateChains;
+  if (this.chains.length === 0) {
+    throw new Error('Refusing to create empty blessings object');
+  }
+  if (this.chains[0].length === 0) {
+    throw new Error('First chain should be non-null');
+  }
+  this.publicKey = this.chains[0][this.chains[0].length - 1].publicKey;
 }
 
 /**
- * Increments the reference count on the Blessings.  When the reference count
- * goes to zero, the Blessings will be removed from the cache in the go code.
- */
-Blessings.prototype.retain = function() {
-  this._count++;
-};
-
-/**
- * Decrements the reference count on the Blessings.  When the reference count
- * goes to zero, the Blessings will be removed from the cache in the go code.
- * @param {module:vanadium.context.Context} ctx A context.
- */
-Blessings.prototype.release = function(ctx) {
-  this._count--;
-  if (this._count === 0) {
-    this._controller.unlinkBlessings(ctx, this._id).catch(function(err) {
-      vlog.logger.warn('Ignoring failure while cleaning up blessings: ' + err);
-    });
-  }
-};
-
-Blessings.prototype.toJSON = function() {
-  return {
-    id: this._id,
-    publicKey: this.publicKey,
-  };
-};
-
-/**
  * Get a string that describes this blessings object.
- * @return {Promise} A promise to a string describing the blessings.
+ * @return {string} A string describing the blessings.
  * @private
  */
-Blessings.prototype._debugString = function(ctx) {
-  return this._controller.blessingsDebugString(ctx, this._id);
+Blessings.prototype.toString = function() {
+  var parts = [];
+  for (var chainidx = 0; chainidx < this.chains.length; chainidx++) {
+    var chainParts = [];
+    var chain = this.chains[chainidx];
+    for (var certidx = 0; certidx < chain.length; certidx++) {
+      var cert = chain[certidx];
+      chainParts.push(cert.extension);
+    }
+    parts.push(chainParts.join(vdlSecurity.ChainSeparator));
+  }
+  return parts.join(' ');
 };
 
-Blessings.prototype.convertToJsBlessings = function() {
-  return new JsBlessings({
-    handle: this._id,
-    publicKey: this.publicKey
-  }, true);
-};
+function toWireBlessings(blessings) {
+  if (!blessings) {
+    // null is used for zero blessings
+    return new vdlSecurity.WireBlessings({
+      certificateChains: []
+    });
+  }
 
-module.exports = Blessings;
+  if (typeof blessings !== 'object') {
+    throw new Error('Expected blessings to be an object');
+  }
+
+  if (blessings.hasOwnProperty('certificateChains')) {
+    // Assume this is a WireBlessings object. It isn't possible to directly
+    // construct WireBlessings due to the way that native types are set up so
+    // this check is used in place of instance of.
+    // TODO(bprosnitz) Fix the way that native type conversion works.
+    return blessings;
+  }
+
+  return new vdlSecurity.WireBlessings({
+    certificateChains: blessings.chains
+  });
+}
+
+function fromWireBlessings(wireblessings) {
+  if (typeof wireblessings !== 'object') {
+    throw new Error('Expected wire blessings to be an object');
+  }
+
+  if (wireblessings instanceof Blessings) {
+    return wireblessings;
+  }
+
+  if (wireblessings.certificateChains.length === 0) {
+    return null;
+  }
+
+  return new Blessings(wireblessings);
+}
diff --git a/src/security/blessingstore.js b/src/security/blessingstore.js
index ec74dd6..687ac02 100644
--- a/src/security/blessingstore.js
+++ b/src/security/blessingstore.js
@@ -81,7 +81,7 @@
      return def.promise;
    }
 
-   return this._controller.blessingStoreSet(ctx, blessings._id, pattern, cb);
+   return this._controller.blessingStoreSet(ctx, blessings, pattern, cb);
  };
 
  /**
@@ -124,8 +124,7 @@
   * @return {Promise} A promise that will be resolved without an output
   * value.
   */
- BlessingStore.prototype.setDefault = function(
-   ctx, blessings, cb) {
+ BlessingStore.prototype.setDefault = function(ctx, blessings, cb) {
    if (blessings === undefined) {
      var def = new Deferred(cb);
      def.reject(new verror.BadArgError(ctx,
@@ -133,7 +132,7 @@
      return def.promise;
    }
 
-   return this._controller.blessingStoreSetDefault(ctx, blessings._id, cb);
+   return this._controller.blessingStoreSetDefault(ctx, blessings, cb);
  };
 
  /**
@@ -149,8 +148,7 @@
   * @return {Promise<module:vanadium.security~Blessings>} A promise that will
   * be resolved with the blessing.
   */
- BlessingStore.prototype.getDefault = function(
-   ctx, cb) {
+ BlessingStore.prototype.getDefault = function(ctx, cb) {
    return this._controller.blessingStoreDefault(ctx, cb);
  };
 
@@ -163,8 +161,7 @@
   * @return {Promise<string>} A promise that will
   * be resolved with the public key as a string.
   */
- BlessingStore.prototype.getPublicKey = function(
-   ctx, cb) {
+ BlessingStore.prototype.getPublicKey = function(ctx, cb) {
    return this._controller.blessingStorePublicKey(ctx, cb);
  };
 
@@ -178,8 +175,7 @@
   * module:vanadium.security~Blessings>>} A promise that will
   * be resolved with the peer blessings.
   */
- BlessingStore.prototype.getPeerBlessings = function(
-   ctx, cb) {
+ BlessingStore.prototype.getPeerBlessings = function(ctx, cb) {
    var def = new Deferred(cb);
    var controller = this._controller;
    controller.blessingStorePeerBlessings(ctx)
@@ -188,7 +184,7 @@
      var promises = [];
      peerBlessings.forEach(function(blessId, pattern) {
        var runtime = runtimeFromContext(ctx);
-       promises.push(runtime.blessingsManager.blessingsFromId(blessId)
+       promises.push(runtime.blessingsCache.blessingsFromId(blessId)
        .then(function(blessingsObj) {
          outPeerBlessings.set(pattern, blessingsObj);
        }));
@@ -210,7 +206,6 @@
   * @return {Promise<string>} A promise that will
   * be resolved with the debug string.
   */
- BlessingStore.prototype.getDebugString = function(
-   ctx, cb) {
+ BlessingStore.prototype.getDebugString = function(ctx, cb) {
    return this._controller.blessingStoreDebugString(ctx, cb);
  };
diff --git a/src/security/create-security-call.js b/src/security/create-security-call.js
index 8cdd467..37b6400 100644
--- a/src/security/create-security-call.js
+++ b/src/security/create-security-call.js
@@ -13,7 +13,7 @@
  * before the user is given the object.
  * @private
  */
-function createSecurityCall(input, blessingsManager) {
+function createSecurityCall(input, blessingsCache) {
   var call = new Call();
   call.method = input.method;
   call.suffix = input.suffix;
@@ -25,11 +25,11 @@
   call.remoteEndpoint = input.remoteEndpoint;
 
   var promises = [];
-  promises.push(blessingsManager.blessingsFromId(input.localBlessings)
+  promises.push(blessingsCache.blessingsFromId(input.localBlessings)
   .then(function(localBlessings) {
     call.localBlessings = localBlessings;
   }));
-  promises.push(blessingsManager.blessingsFromId(input.remoteBlessings)
+  promises.push(blessingsCache.blessingsFromId(input.remoteBlessings)
   .then(function(remoteBlessings) {
     call.remoteBlessings = remoteBlessings;
     return call;
diff --git a/src/security/default-authorizer.js b/src/security/default-authorizer.js
index 6a952b4..fb76a61 100644
--- a/src/security/default-authorizer.js
+++ b/src/security/default-authorizer.js
@@ -14,17 +14,13 @@
     call.localBlessings.publicKey === call.remoteBlessings.publicKey) {
     return cb();
   }
-  var matchesLocal = call.localBlessingStrings.some(function(l) {
-    return blessingMatches(l, call.remoteBlessingStrings);
+  var matches = call.localBlessingStrings.some(function(l) {
+    return call.remoteBlessingStrings.some(function(r) {
+      return blessingMatches(l, r) || blessingMatches(r, l);
+    });
   });
-  if (matchesLocal) {
-    return cb();
-  }
 
-  var matchesRemote = call.remoteBlessingStrings.some(function(l) {
-    return blessingMatches(l, call.localBlessingStrings);
-  });
-  if (matchesRemote) {
+  if (matches) {
     return cb();
   }
   return cb(new vError.NoAccessError(ctx, 'authorization failed'));
diff --git a/src/security/principal.js b/src/security/principal.js
index afc40cc..dfd697c 100644
--- a/src/security/principal.js
+++ b/src/security/principal.js
@@ -80,7 +80,7 @@
 
   var caveats = args.slice(4);
 
-  this._controller.bless(ctx, publicKey, blessings._id, extension, caveats)
+  this._controller.bless(ctx, publicKey, blessings, extension, caveats)
   .then(function(blessings) {
     def.resolve(blessings);
   }).catch(function(err) {
@@ -143,7 +143,7 @@
     return def.promise;
   }
 
-  return this._controller.addToRoots(ctx, blessings._id, cb);
+  return this._controller.addToRoots(ctx, blessings, cb);
 };
 
 module.exports = Principal;
diff --git a/src/vtrace/vtrace.js b/src/vtrace/vtrace.js
index d93e1c1..c9c8227 100644
--- a/src/vtrace/vtrace.js
+++ b/src/vtrace/vtrace.js
@@ -5,6 +5,7 @@
 var uniqueid = require('../lib/uniqueid');
 var context = require('../context');
 var vdl = require('../gen-vdl/v.io/v23/vtrace');
+var vlog = require('../lib/vlog');
 
 var spanKey = context.ContextKey();
 var storeKey = context.ContextKey();
@@ -409,6 +410,10 @@
  * @memberof module:vanadium.vtrace
  */
 function response(ctx) {
+  if (!ctx) {
+    vlog.logger.warn('Cannot perform vtrace without valid context');
+    return;
+  }
   var store = ctx.value(storeKey);
   var span = ctx.value(spanKey);
   return vdl.Response({
diff --git a/test/integration/test-bless.js b/test/integration/test-bless.js
index 1c03b5b..a3f147e 100644
--- a/test/integration/test-bless.js
+++ b/test/integration/test-bless.js
@@ -12,11 +12,8 @@
 
 function validateBlessings(t, blessings) {
   t.ok(blessings instanceof Blessings, 'Blessings have correct type');
-  t.ok(typeof blessings._id === 'number' && blessings._id !== 0,
-    'Blessing has non-zero id');
-  t.ok(typeof blessings.publicKey === 'string' && blessings.publicKey !== '',
-    'Blessing has public key');
-  t.ok(blessings._controller, 'Blessing object has controller attached');
+  t.ok(blessings.chains.length > 0, 'Non-empty chains');
+  t.ok(blessings.publicKey, 'Public key is set');
 }
 
 test('Test bless self without Caveat', function(t) {
@@ -122,12 +119,13 @@
   var service = {
     method: function(ctx, serverCall) {
       t.ok(serverCall.grantedBlessings, 'Expect to get granted blessing');
-      t.equal(serverCall.grantedBlessings._id, expectedBlessing._id,
+      t.deepEqual(serverCall.grantedBlessings, expectedBlessing,
         'Expect to get blessing that was granted.');
       return 'aResponse';
     }
   };
 
+
   serve('testing/clientblessgranter', leafDispatcher(service),
     function(err, res) {
       if (err) {
@@ -173,14 +171,13 @@
 
     runtime.principal.blessSelf(runtime.getContext(), 'blessedname')
     .then(function(blessings) {
-      t.ok(blessings instanceof Blessings, 'Got blessings');
-      t.ok(blessings._id > 0, 'Should get non-zero blessings');
+      validateBlessings(t, blessings);
 
       return runtime.principal.addToRoots(runtime.getContext(), blessings);
     }).then(function() {
       rt.close(t.end);
     }).catch(function(err) {
-      t.error(err, 'either blessSelf or addToRoots errored');
+      t.error(err, 'either blessSelf or addToRoots errored ' + err);
       rt.close(t.end);
     });
   });
@@ -197,9 +194,8 @@
 
     runtime.principal.blessSelf(runtime.getContext(), 'blessedname')
     .then(function(blessings) {
-      return blessings._debugString(runtime.getContext());
-    }).then(function(debugString) {
-      t.ok(debugString === 'blessedname', 'Got blessed name as debug string');
+      t.ok(blessings.chains[0][0].extension === 'blessedname',
+        'Blessing had correct extension');
       rt.close(t.end);
     }).catch(function(err) {
       t.error(err);
diff --git a/test/integration/test-blessings-util.js b/test/integration/test-blessings-util.js
index 0f55cea..9a98e0c 100644
--- a/test/integration/test-blessings-util.js
+++ b/test/integration/test-blessings-util.js
@@ -22,11 +22,10 @@
       });
     })
     .then(function(unionedBlessings) {
-      return unionedBlessings._debugString(runtime.getContext());
-    })
-    .then(function(debugStr) {
-      t.ok(debugStr.indexOf('blessedname1') >= 0, 'first blessing in union');
-      t.ok(debugStr.indexOf('blessedname2') >= 0, 'second blessing in union');
+      t.ok(unionedBlessings.toString().indexOf('blessedname1') >= 0,
+          'first blessing in union');
+      t.ok(unionedBlessings.toString().indexOf('blessedname2') >= 0,
+          'second blessing in union');
       runtime.close(t.end);
     }).catch(function(err) {
       runtime.close();
@@ -62,17 +61,11 @@
             runtime.close(t.end);
             return;
           }
-          unionedBlessings._debugString(runtime.getContext())
-          .then(function(debugStr) {
-            t.ok(debugStr.indexOf('blessedname1') >= 0,
+          t.ok(unionedBlessings.toString().indexOf('blessedname1') >= 0,
               'first blessing in union');
-            t.ok(debugStr.indexOf('blessedname2') >= 0,
+          t.ok(unionedBlessings.toString().indexOf('blessedname2') >= 0,
               'second blessing in union');
             runtime.close(t.end);
-          }).catch(function(err) {
-            t.error(err);
-            runtime.close(t.end);
-          });
         });
       });
     });
diff --git a/test/integration/test-blessingstore.js b/test/integration/test-blessingstore.js
index 2bc1318..31be624 100644
--- a/test/integration/test-blessingstore.js
+++ b/test/integration/test-blessingstore.js
@@ -9,11 +9,8 @@
 
 function validateBlessings(t, blessings) {
   t.ok(blessings instanceof Blessings, 'Blessings have correct type');
-  t.ok(typeof blessings._id === 'number' && blessings._id !== 0,
-    'Blessing has non-zero id');
-  t.ok(typeof blessings.publicKey === 'string' && blessings.publicKey !== '',
-    'Blessing has public key');
-  t.ok(blessings._controller, 'Blessing object has controller attached');
+  t.ok(blessings.chains.length > 0, 'Non-empty chains');
+  t.ok(blessings.publicKey, 'Public key is set');
 }
 
 test('Test blessing store set (promise case)', function(t) {
@@ -33,8 +30,8 @@
       return runtime.principal.blessingStore.set(runtime.getContext(),
         blessSelfResult, 'fake/remote/pattern');
     }).then(function(firstBlessing) {
-      t.equal(firstBlessing._id, blessSelfResult._id,
-        'Should get handle of first blessing back');
+      t.deepEqual(firstBlessing, blessSelfResult,
+        'Should get first blessings back');
       validateBlessings(t, firstBlessing);
       runtime.close(t.end);
     }).catch(function(err) {
@@ -76,8 +73,8 @@
             runtime.close(t.end);
             return;
           }
-          t.equal(firstBlessing._id, blessSelfResult._id,
-            'Should get handle of first blessing back');
+          t.deepEqual(firstBlessing, blessSelfResult,
+            'Should get first blessings back');
           validateBlessings(t, firstBlessing);
           runtime.close(t.end);
         });
@@ -168,8 +165,8 @@
       return runtime.principal.blessingStore.getDefault(runtime.getContext());
     }).then(function(defaultBlessings) {
       validateBlessings(t, defaultBlessings);
-      t.equal(defaultBlessings._id, blessSelfResult._id,
-        'Should get handle of default blessing back');
+      t.deepEqual(defaultBlessings, blessSelfResult,
+        'Should get default blessings back');
 
       // Restore original default blessings
       return runtime.principal.blessingStore.setDefault(
@@ -221,8 +218,8 @@
               return;
             }
             validateBlessings(t, defaultBlessings);
-            t.equal(defaultBlessings._id, blessSelfResult._id,
-              'Should get handle of default blessing back');
+            t.deepEqual(defaultBlessings, blessSelfResult,
+              'Should get default blessings back');
 
             // Restore original default blessings
             runtime.principal.blessingStore.setDefault(runtime.getContext(),
@@ -245,7 +242,8 @@
 
     runtime.principal.blessingStore.getPublicKey(runtime.getContext())
     .then(function(publicKey) {
-      t.ok(typeof publicKey === 'string' && publicKey !== '', 'got public key');
+      t.ok(publicKey instanceof Uint8Array && publicKey.length > 0,
+        'got public key');
       runtime.close(t.end);
     }).catch(function(err) {
       t.error(err, 'error in getPublicKey()');
@@ -267,7 +265,8 @@
         runtime.close(t.end);
         return;
       }
-      t.ok(typeof publicKey === 'string' && publicKey !== '', 'got public key');
+      t.ok(publicKey instanceof Uint8Array && publicKey.length > 0,
+        'got public key');
       runtime.close(t.end);
     });
   });
diff --git a/test/unit/test-blessings-cache.js b/test/unit/test-blessings-cache.js
index 1999e3c..a7b9e0b 100644
--- a/test/unit/test-blessings-cache.js
+++ b/test/unit/test-blessings-cache.js
@@ -6,10 +6,19 @@
 var BlessingsCache = require('../../src/security/blessings-cache');
 var principal =
   require('../../src/gen-vdl/v.io/x/ref/services/wspr/internal/principal');
+var security = require('../../src/gen-vdl/v.io/v23/security');
+var nativeTypeRegistry =
+  require('../../src/vdl/native-type-registry');
 
 test('Blessing cache - add before use', function(t) {
   var blessingsA = {
-    publicKey: 'A'
+    certificateChains: [
+      [
+        new security.Certificate({
+          extension: 'A'
+        })
+      ]
+    ]
   };
   var messages = [
     {
@@ -31,7 +40,13 @@
 
 test('Blessing cache - add after use', function(t) {
   var blessingsA = {
-    publicKey: 'A'
+    certificateChains: [
+      [
+        new security.Certificate({
+          extension: 'A'
+        })
+      ]
+    ]
   };
   var messages = [
     {
@@ -54,7 +69,13 @@
 
 test('Blessing cache - delete after add', function(t) {
   var blessingsA = {
-    publicKey: 'A'
+    certificateChains: [
+      [
+        new security.Certificate({
+          extension: 'A'
+        })
+      ]
+    ]
   };
   var messages = [
     {
@@ -82,7 +103,13 @@
 
 test('Blessing cache - reference counting delete', function(t) {
   var blessingsA = {
-    publicKey: 'A'
+    certificateChains: [
+      [
+        new security.Certificate({
+          extension: 'A'
+        })
+      ]
+    ]
   };
   var messages = [
     {
@@ -120,7 +147,13 @@
 
 test('Blessing cache - add after delete', function(t) {
   var blessingsA = {
-    publicKey: 'A'
+    certificateChains: [
+      [
+        new security.Certificate({
+          extension: 'A'
+        })
+      ]
+    ]
   };
   var messages = [
     {
@@ -153,13 +186,31 @@
 
 test('Blessing cache - multiple entries', function(t) {
   var blessingsA = {
-    publicKey: 'A'
+    certificateChains: [
+      [
+        new security.Certificate({
+          extension: 'A'
+        })
+      ]
+    ]
   };
   var blessingsB = {
-    publicKey: 'B'
+    certificateChains: [
+      [
+        new security.Certificate({
+          extension: 'B'
+        })
+      ]
+    ]
   };
   var blessingsC = {
-    publicKey: 'C'
+    certificateChains: [
+      [
+        new security.Certificate({
+          extension: 'C'
+        })
+      ]
+    ]
   };
   var messages = [
     {
@@ -248,7 +299,13 @@
 
 test('Blessing cache handles typed BlessingsId objects', function(t) {
   var blessingsA = {
-    publicKey: 'A'
+    certificateChains: [
+      [
+        new security.Certificate({
+          extension: 'A'
+        })
+      ]
+    ]
   };
   var messages = [
     {
@@ -325,8 +382,10 @@
   } else if (message.type === 'blessingsFromId') {
     return cache.blessingsFromId(message.cacheId).then(function(blessings) {
       var expected = null;
-      if (message.expected !== null) {
-        expected = new principal.JsBlessings(message.expected);
+      if (message.expected) {
+        expected = nativeTypeRegistry.fromWireValue(
+          security.WireBlessings.prototype._type,
+          message.expected);
       }
       t.deepEqual(blessings, expected,
         'Should get expected blessings on message ' + index);
diff --git a/test/unit/test-blessings.js b/test/unit/test-blessings.js
new file mode 100644
index 0000000..f5e2905
--- /dev/null
+++ b/test/unit/test-blessings.js
@@ -0,0 +1,75 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var test = require('prova');
+var Blessings = require('../../src/security/blessings');
+var vom = require('./../../src/vom');
+var WireBlessings =
+  require('../../src/gen-vdl/v.io/v23/security').WireBlessings;
+
+function makeTestWireBlessings() {
+  return new WireBlessings({
+    certificateChains: [
+      [
+        {
+          extension: 'A',
+          publicKey: new Uint8Array([1, 2, 3])
+        },
+        {
+          extension: 'B',
+          publicKey: new Uint8Array([4, 5, 6])
+        }
+      ],
+      [
+        {
+          extension: 'C',
+          publicKey: new Uint8Array([7, 8, 9])
+        }
+      ]
+    ]
+  });
+}
+
+function makeTestBlessings() {
+  return new Blessings(makeTestWireBlessings());
+}
+
+test('Blessings constructor', function(t) {
+  var blessings = makeTestBlessings();
+  t.deepEquals(blessings.publicKey, new Uint8Array([4, 5, 6]),
+    'Got correct public key');
+  t.deepEquals(blessings.chains, makeTestWireBlessings().certificateChains,
+    'Got correct chains');
+  t.end();
+});
+
+test('Encode and decode of blessings', function(t) {
+  var blessings = makeTestBlessings();
+
+  var encodedBlessings = vom.encode(blessings);
+  vom.decode(encodedBlessings, false, undefined,
+    function(err, decodedBlessings) {
+    t.error(err, 'Error decoding to Blessings');
+    t.deepEquals(decodedBlessings.publicKey, blessings.publicKey,
+      'Got correct public key');
+    t.equals(decodedBlessings.length, blessings.length,
+      'Decoded blessings are the correct length');
+    t.equals(decodedBlessings.chains[0][0].extension,
+      blessings.chains[0][0].extension,
+      'Should get same extension');
+    t.equals(decodedBlessings.chains[1][0].extension,
+      blessings.chains[1][0].extension,
+      'Should get same extension for second chain');
+    t.deepEquals(decodedBlessings.chains[0][1].publicKey,
+      blessings.chains[0][1].publicKey,
+      'Should get same publicKey');
+    t.end();
+  });
+});
+
+test('Blessings toString', function(t) {
+  var blessings = makeTestBlessings();
+  t.equals(blessings.toString(), 'A/B C');
+  t.end();
+});
diff --git a/test/unit/test-permissions-authorizer.js b/test/unit/test-permissions-authorizer.js
index 4000502..c16e32a 100644
--- a/test/unit/test-permissions-authorizer.js
+++ b/test/unit/test-permissions-authorizer.js
@@ -6,13 +6,18 @@
 var test = require('prova');
 var permissionsAuthorizer =
   require('../../src/security/access/permissions-authorizer');
-var Blessings = require('../../src/security/blessings');
 var access = require('../../src/gen-vdl/v.io/v23/security/access');
 var unwrap = require('../../src/vdl/type-util').unwrap;
 var createConstructor = require('../../src/vdl/create-constructor');
 var kind = require('../../src/vdl/kind');
 var Context = require('../../src/context').Context;
 
+function makeFakeBlessings(str) {
+  return {
+    publicKey: str,
+  };
+}
+
 require('es6-shim');
 var rootCtx = new Context();
 var allTags = [
@@ -20,8 +25,8 @@
 test('allow same public key access with no other permissions',
      function(assert) {
   var call = {
-    localBlessings: new Blessings(undefined, 'me', undefined),
-    remoteBlessings: new Blessings(undefined, 'me', undefined)
+    localBlessings: makeFakeBlessings('sameKey'),
+    remoteBlessings: makeFakeBlessings('sameKey')
   };
 
   var auth = permissionsAuthorizer({}, access.Tag);
@@ -168,12 +173,8 @@
       continue;
     }
     var call = {
-      localBlessings: {
-        publicKey: 'me',
-      },
-      remoteBlessings: {
-        publicKey: 'otherkey',
-      },
+      localBlessings: makeFakeBlessings('localBlessingsMe'),
+      remoteBlessings: makeFakeBlessings('remoteBlessingsOther'),
       remoteBlessingStrings: [name],
     };
     var exp = expectations[name];
@@ -200,8 +201,8 @@
   });
   var myAdmin = new MyTag('Admin');
   var call = {
-    localBlessings: new Blessings(undefined, 'me', undefined),
-    remoteBlessings: new Blessings(undefined, 'otherKey', undefined),
+    localBlessings: makeFakeBlessings('localBlessingsMe'),
+    remoteBlessings: 'localBlessingsOther',
     remoteBlessingStrings: ['server/alice', 'server/bob/friend'],
   };
 
@@ -229,8 +230,8 @@
   });
   var myAdmin = new MyTag('Admin');
   var call = {
-    localBlessings: new Blessings(undefined, 'me', undefined),
-    remoteBlessings: new Blessings(undefined, 'otherKey', undefined),
+    localBlessings: makeFakeBlessings('localBlessingsMe'),
+    remoteBlessings: 'localBlessingsOther',
     remoteBlessingStrings: ['server/alice', 'server/bob/friend'],
   };
 
@@ -250,8 +251,8 @@
 
 test('multiple tags of a type - error', function(assert) {
   var call = {
-    localBlessings: new Blessings(undefined, 'me', undefined),
-    remoteBlessings: new Blessings(undefined, 'otherKey', undefined),
+    localBlessings: makeFakeBlessings('localBlessingsMe'),
+    remoteBlessings: 'localBlessingsOther',
     remoteBlessingStrings: ['server/alice', 'server/bob/friend'],
   };