API consumer question: How do we recover Credential?

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