- From: J.C. Jones <jc@mozilla.com>
- Date: Wed, 13 Jul 2016 16:19:43 -0700
- To: W3C WebAuthn WG <public-webauthn@w3.org>
- Message-ID: <CAObDDPBixA15=D6spG5BWg7PcpULXwJxuwC0v_gpAR3AY+Z+ng@mail.gmail.com>
I'm working my head through using WebAuthn for a U2F-like use case and hit a snag: What are the right ways to serialize and deserialize the Credentials which come from makeCredential(), so we have them handy for getAssertion()? The Credential interface in WebIDL consists of two read-only attributes; I don't believe it's possible to deserialize something to match that interface using JSON.parse(), but I could be wrong. Let me walk through a sketch of this, just for everyone's reference. Note: the JS is imperfect, and I didn't do all the necessary incantations for IndexedDB -- it's just a sketch. :) (It's online / colorized here: https://jsfiddle.net/ad3ssofo/5/ ) First, we need to make a new credential: /* Called when a new authenticator is being added to the account */ function addAuthenticator(account, params, challenge) { let wauthn = navigator.authentication; wauthn.makeCredential(account, params, challenge) .then(function(scopedCred) { /* Send the Scoped Cred info to the RP */ transmitCredToRP(scopedCred); /* Cache in IndexedDB */ let dbReq = window.indexedDB.open("appDB", 1); dbReq.onsuccess = function() { let db = DBOpenRequest.result; let objectStore = db.createObjectStore("credStore"); objectStore.put(scopedCred.credential, "credential"); } }); } ...which calls the stub: /* Send the scoped credential data to the RP */ function transmitCredToRP(scopedCred) { let serialized = JSON.stringify(scopedCred); /* send(serialized); */ } All's well, so far, I guess. There's no reason a Scoped Credential can't be serialized to JSON. When we go to generate the assertion though: /* Called when an authenticator is being asked to prove possession */ function authenticate(serializedCredential) { let wauthn = navigator.authentication; let whitelist = []; /* Decode a Credential from a serialized form from the RP */ whitelist.push(deserializeCredential(serializedCredential)); /* Maybe could also come via IndexedDB? */ let dbReq = window.indexedDB.open("appDB", 1); dbReq.onsuccess = function() { let db = DBOpenRequest.result; let objectStore = db.createObjectStore("credStore"); whitelist.push(objectStore.get("credential")) } /* Whitelist is optional, but if it's not provided, how would a U2F-type authenticator obtain its' private key? */ wauthn.getAssertion(challenge, whitelist) .then(function(assertion) { /* Transmit the assertion object to the RP */ transmitAssertionToRP(assertion) }); } ...which uses the stubs: /* Send the assertion data to the RP */ function transmitAssertionToRP(assertion) { let serialized = JSON.stringify(assertion); /* send(serialized); */ } /* Deserialize a Credential object from the RP for re-use */ function deserializeCredential(serializedCredential) { /* DOES THIS WORK? Or do we need a constructor? */ let credentialObj = JSON.parse(serializedCredential); return credentialObj; } So the problems I'm hitting here are: 1. How do we want people to serialize/deserialize Credential objects? 2. For getAssertion(), whitelist is optional. But without it, how would U2F-style authenticators get their wrapped private key to do work? Where's my thinking flawed? Thanks, J.C.
Received on Wednesday, 13 July 2016 23:20:31 UTC