bug 1332681 - part 2/4 - authentication.getAssertion: return a PublicKeyCredential instead of a WebAuthnAssertion r=jcj,qdot
authorDavid Keeler <dkeeler@mozilla.com>
Mon, 22 May 2017 13:03:58 -0700
changeset 411407 5d05100ea93645c57fcdb196c323afe159151135
parent 411406 675f396003827bd1075128c6620dd38386a2b64f
child 411408 3c0d57fec9e5bb5c6eb71389d62129d7f8a2baa8
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjcj, qdot
bugs1332681
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1332681 - part 2/4 - authentication.getAssertion: return a PublicKeyCredential instead of a WebAuthnAssertion r=jcj,qdot MozReview-Commit-ID: 72p9lvhQISe
dom/webauthn/AuthenticatorAssertionResponse.cpp
dom/webauthn/AuthenticatorAssertionResponse.h
dom/webauthn/WebAuthnAssertion.cpp
dom/webauthn/WebAuthnAssertion.h
dom/webauthn/WebAuthnManager.cpp
dom/webauthn/moz.build
dom/webauthn/tests/test_webauthn_loopback.html
dom/webidl/WebAuthentication.webidl
rename from dom/webauthn/WebAuthnAssertion.cpp
rename to dom/webauthn/AuthenticatorAssertionResponse.cpp
--- a/dom/webauthn/WebAuthnAssertion.cpp
+++ b/dom/webauthn/AuthenticatorAssertionResponse.cpp
@@ -1,98 +1,66 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/WebAuthenticationBinding.h"
-#include "mozilla/dom/WebAuthnAssertion.h"
+#include "mozilla/dom/AuthenticatorAssertionResponse.h"
 
 namespace mozilla {
 namespace dom {
 
-// Only needed for refcounted objects.
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebAuthnAssertion, mParent)
-NS_IMPL_CYCLE_COLLECTING_ADDREF(WebAuthnAssertion)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(WebAuthnAssertion)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebAuthnAssertion)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
+NS_IMPL_ADDREF_INHERITED(AuthenticatorAssertionResponse, AuthenticatorResponse)
+NS_IMPL_RELEASE_INHERITED(AuthenticatorAssertionResponse, AuthenticatorResponse)
 
-WebAuthnAssertion::WebAuthnAssertion(nsPIDOMWindowInner* aParent)
-  : mParent(aParent)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AuthenticatorAssertionResponse)
+NS_INTERFACE_MAP_END_INHERITING(AuthenticatorResponse)
+
+AuthenticatorAssertionResponse::AuthenticatorAssertionResponse(nsPIDOMWindowInner* aParent)
+  : AuthenticatorResponse(aParent)
 {}
 
-WebAuthnAssertion::~WebAuthnAssertion()
+AuthenticatorAssertionResponse::~AuthenticatorAssertionResponse()
 {}
 
 JSObject*
-WebAuthnAssertion::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+AuthenticatorAssertionResponse::WrapObject(JSContext* aCx,
+                                           JS::Handle<JSObject*> aGivenProto)
 {
-  return WebAuthnAssertionBinding::Wrap(aCx, this, aGivenProto);
-}
-
-already_AddRefed<ScopedCredential>
-WebAuthnAssertion::Credential() const
-{
-  RefPtr<ScopedCredential> temp(mCredential);
-  return temp.forget();
+  return AuthenticatorAssertionResponseBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
-WebAuthnAssertion::GetClientData(JSContext* aCx,
-                                 JS::MutableHandle<JSObject*> aRetVal) const
-{
-  aRetVal.set(mClientData.ToUint8Array(aCx));
-}
-
-void
-WebAuthnAssertion::GetAuthenticatorData(JSContext* aCx,
-                                        JS::MutableHandle<JSObject*> aRetVal) const
+AuthenticatorAssertionResponse::GetAuthenticatorData(JSContext* aCx,
+                                                     JS::MutableHandle<JSObject*> aRetVal) const
 {
   aRetVal.set(mAuthenticatorData.ToUint8Array(aCx));
 }
 
+nsresult
+AuthenticatorAssertionResponse::SetAuthenticatorData(CryptoBuffer& aBuffer)
+{
+  if (NS_WARN_IF(!mAuthenticatorData.Assign(aBuffer))) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  return NS_OK;
+}
+
 void
-WebAuthnAssertion::GetSignature(JSContext* aCx,
-                                JS::MutableHandle<JSObject*> aRetVal) const
+AuthenticatorAssertionResponse::GetSignature(JSContext* aCx,
+                                             JS::MutableHandle<JSObject*> aRetVal) const
 {
   aRetVal.set(mSignature.ToUint8Array(aCx));
 }
 
 nsresult
-WebAuthnAssertion::SetCredential(RefPtr<ScopedCredential> aCredential)
-{
-  mCredential = aCredential;
-  return NS_OK;
-}
-
-nsresult
-WebAuthnAssertion::SetClientData(CryptoBuffer& aBuffer)
+AuthenticatorAssertionResponse::SetSignature(CryptoBuffer& aBuffer)
 {
-  if (!mClientData.Assign(aBuffer)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  return NS_OK;
-}
-
-nsresult
-WebAuthnAssertion::SetAuthenticatorData(CryptoBuffer& aBuffer)
-{
-  if (!mAuthenticatorData.Assign(aBuffer)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  return NS_OK;
-}
-
-nsresult
-WebAuthnAssertion::SetSignature(CryptoBuffer& aBuffer)
-{
-  if (!mSignature.Assign(aBuffer)) {
+  if (NS_WARN_IF(!mSignature.Assign(aBuffer))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 } // namespace dom
 } // namespace mozilla
rename from dom/webauthn/WebAuthnAssertion.h
rename to dom/webauthn/AuthenticatorAssertionResponse.h
--- a/dom/webauthn/WebAuthnAssertion.h
+++ b/dom/webauthn/AuthenticatorAssertionResponse.h
@@ -1,86 +1,56 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_dom_WebAuthnAssertion_h
-#define mozilla_dom_WebAuthnAssertion_h
+#ifndef mozilla_dom_AuthenticatorAssertionResponse_h
+#define mozilla_dom_AuthenticatorAssertionResponse_h
 
 #include "js/TypeDecls.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
+#include "mozilla/dom/AuthenticatorResponse.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/CryptoBuffer.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla {
 namespace dom {
 
-class ScopedCredential;
-
-} // namespace dom
-} // namespace mozilla
-
-namespace mozilla {
-namespace dom {
-
-class WebAuthnAssertion final : public nsISupports
-                              , public nsWrapperCache
+class AuthenticatorAssertionResponse final : public AuthenticatorResponse
 {
 public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebAuthnAssertion)
+  NS_DECL_ISUPPORTS_INHERITED
 
-public:
-  explicit WebAuthnAssertion(nsPIDOMWindowInner* aParent);
+  explicit AuthenticatorAssertionResponse(nsPIDOMWindowInner* aParent);
 
 protected:
-  ~WebAuthnAssertion();
+  ~AuthenticatorAssertionResponse() override;
 
 public:
-  nsPIDOMWindowInner*
-  GetParentObject() const
-  {
-    return mParent;
-  }
-
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  already_AddRefed<ScopedCredential>
-  Credential() const;
-
   void
-  GetClientData(JSContext* cx, JS::MutableHandle<JSObject*> aRetVal) const;
-
-  void
-  GetAuthenticatorData(JSContext* cx, JS::MutableHandle<JSObject*> aRetVal) const;
-
-  void
-  GetSignature(JSContext* cx, JS::MutableHandle<JSObject*> aRetVal) const;
-
-  nsresult
-  SetCredential(RefPtr<ScopedCredential> aCredential);
-
-  nsresult
-  SetClientData(CryptoBuffer& aBuffer);
+  GetAuthenticatorData(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal) const;
 
   nsresult
   SetAuthenticatorData(CryptoBuffer& aBuffer);
 
+  void
+  GetSignature(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal) const;
+
   nsresult
   SetSignature(CryptoBuffer& aBuffer);
 
 private:
-  nsCOMPtr<nsPIDOMWindowInner> mParent;
-  RefPtr<ScopedCredential> mCredential;
   CryptoBuffer mAuthenticatorData;
-  CryptoBuffer mClientData;
   CryptoBuffer mSignature;
 };
 
 } // namespace dom
 } // namespace mozilla
 
-#endif // mozilla_dom_WebAuthnAssertion_h
+#endif // mozilla_dom_AuthenticatorAssertionResponse_h
--- a/dom/webauthn/WebAuthnManager.cpp
+++ b/dom/webauthn/WebAuthnManager.cpp
@@ -727,31 +727,31 @@ WebAuthnManager::FinishGetAssertion(nsTA
   CryptoBuffer credentialBuf;
   if (!credentialBuf.Assign(aCredentialId)) {
     Cancel(rv);
     return;
   }
 
   // If any authenticator returns success:
 
-  // Create a new WebAuthnAssertion object named value and populate its fields
+  // Create a new PublicKeyCredential object named value and populate its fields
   // with the values returned from the authenticator as well as the
   // clientDataJSON computed earlier.
-
-  RefPtr<ScopedCredential> credential = new ScopedCredential(mCurrentParent);
-  credential->SetType(ScopedCredentialType::ScopedCred);
-  credential->SetId(credentialBuf);
-
-  RefPtr<WebAuthnAssertion> assertion = new WebAuthnAssertion(mCurrentParent);
-  assertion->SetCredential(credential);
-  assertion->SetClientData(clientDataBuf);
+  RefPtr<AuthenticatorAssertionResponse> assertion =
+    new AuthenticatorAssertionResponse(mCurrentParent);
+  assertion->SetClientDataJSON(clientDataBuf);
   assertion->SetAuthenticatorData(authenticatorDataBuf);
   assertion->SetSignature(signatureData);
 
-  mTransactionPromise->MaybeResolve(assertion);
+  RefPtr<PublicKeyCredential> credential =
+    new PublicKeyCredential(mCurrentParent);
+  credential->SetRawId(credentialBuf);
+  credential->SetResponse(assertion);
+
+  mTransactionPromise->MaybeResolve(credential);
   MaybeClearTransaction();
 }
 
 void
 WebAuthnManager::Cancel(const nsresult& aError)
 {
   if (mChild) {
     mChild->SendRequestCancel();
--- a/dom/webauthn/moz.build
+++ b/dom/webauthn/moz.build
@@ -7,43 +7,43 @@
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
 
 IPDL_SOURCES += [
     'PWebAuthnTransaction.ipdl'
 ]
 
 EXPORTS.mozilla.dom += [
+    'AuthenticatorAssertionResponse.h',
     'AuthenticatorAttestationResponse.h',
     'AuthenticatorResponse.h',
     'NSSU2FTokenRemote.h',
     'PublicKeyCredential.h',
     'ScopedCredential.h',
     'U2FSoftTokenManager.h',
     'U2FTokenManager.h',
     'U2FTokenTransport.h',
     'WebAuthentication.h',
-    'WebAuthnAssertion.h',
     'WebAuthnManager.h',
     'WebAuthnRequest.h',
     'WebAuthnTransactionChild.h',
     'WebAuthnTransactionParent.h',
     'WebAuthnUtil.h'
 ]
 
 UNIFIED_SOURCES += [
+    'AuthenticatorAssertionResponse.cpp',
     'AuthenticatorAttestationResponse.cpp',
     'AuthenticatorResponse.cpp',
     'NSSU2FTokenRemote.cpp',
     'PublicKeyCredential.cpp',
     'ScopedCredential.cpp',
     'U2FSoftTokenManager.cpp',
     'U2FTokenManager.cpp',
     'WebAuthentication.cpp',
-    'WebAuthnAssertion.cpp',
     'WebAuthnManager.cpp',
     'WebAuthnTransactionChild.cpp',
     'WebAuthnTransactionParent.cpp',
     'WebAuthnUtil.cpp'
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/dom/webauthn/tests/test_webauthn_loopback.html
+++ b/dom/webauthn/tests/test_webauthn_loopback.html
@@ -58,47 +58,46 @@ function() {
     return decodeU2FRegistration(aCredInfo.response.attestationObject)
     .then(function(u2fObj) {
       aCredInfo.u2fReg = u2fObj;
       return aCredInfo;
     });
   }
 
   function checkAssertionAndSigValid(aPublicKey, aAssertion) {
-    /* WebAuthnAssertion
-    - Credential
-    -- ID: ID of Credential from AllowList that succeeded
-    -- Type: "ScopedCred"
-    - ClientData: serialized JSON
-    - AuthenticatorData: RP ID Hash || U2F Sign() Response
-    - Signature: U2F Sign() Response */
+    /* PublicKeyCredential : Credential
+       - rawId: ID of Credential from AllowList that succeeded
+       - response : AuthenticatorAssertionResponse : AuthenticatorResponse
+         - clientDataJSON: serialized JSON
+         - authenticatorData: RP ID Hash || U2F Sign() Response
+         - signature: U2F Sign() Response
+    */
 
-    is(aAssertion.credential.type, "ScopedCred", "Type is correct");
-    ok(aAssertion.credential.id.length > 0, "Key ID exists");
+    ok(aAssertion.rawId.length > 0, "Key ID exists");
 
-    ok(aAssertion.authenticatorData.length > 0, "Authenticator data exists");
-    let clientData = JSON.parse(buffer2string(aAssertion.clientData));
+    ok(aAssertion.response.authenticatorData.length > 0, "Authenticator data exists");
+    let clientData = JSON.parse(buffer2string(aAssertion.response.clientDataJSON));
     is(clientData.challenge, bytesToBase64UrlSafe(gAssertionChallenge), "Challenge is correct");
     is(clientData.origin, window.location.origin, "Origin is correct");
     is(clientData.hashAlg, "S256", "Hash algorithm is correct");
 
     // Parse the signature data
-    if (aAssertion.signature[0] != 0x01) {
+    if (aAssertion.response.signature[0] != 0x01) {
       throw "User presence byte not set";
     }
-    let presenceAndCounter = aAssertion.signature.slice(0,5);
-    let signatureValue = aAssertion.signature.slice(5);
+    let presenceAndCounter = aAssertion.response.signature.slice(0,5);
+    let signatureValue = aAssertion.response.signature.slice(5);
 
-    let rpIdHash = aAssertion.authenticatorData.slice(0,32);
+    let rpIdHash = aAssertion.response.authenticatorData.slice(0,32);
 
     // Assemble the signed data and verify the signature
-    return deriveAppAndChallengeParam(clientData.origin, aAssertion.clientData)
+    return deriveAppAndChallengeParam(clientData.origin, aAssertion.response.clientDataJSON)
     .then(function(aParams) {
       console.log(aParams.appParam, rpIdHash, presenceAndCounter, aParams.challengeParam);
-      console.log("ClientData buffer: ", hexEncode(aAssertion.clientData));
+      console.log("ClientData buffer: ", hexEncode(aAssertion.response.clientDataJSON));
       console.log("ClientDataHash: ", hexEncode(aParams.challengeParam));
       return assembleSignedData(aParams.appParam, presenceAndCounter, aParams.challengeParam);
     })
     .then(function(aSignedData) {
       console.log(aPublicKey, aSignedData, signatureValue);
       return verifySignature(aPublicKey, aSignedData, signatureValue);
     })
   }
--- a/dom/webidl/WebAuthentication.webidl
+++ b/dom/webidl/WebAuthentication.webidl
@@ -45,19 +45,17 @@ dictionary ScopedCredentialParameters {
 dictionary ScopedCredentialOptions {
     unsigned long                        timeoutSeconds;
     USVString                            rpId;
     sequence<ScopedCredentialDescriptor> excludeList;
     WebAuthnExtensions                   extensions;
 };
 
 [SecureContext, Pref="security.webauth.webauthn"]
-interface WebAuthnAssertion {
-    readonly attribute ScopedCredential credential;
-    readonly attribute ArrayBuffer      clientData;
+interface AuthenticatorAssertionResponse : AuthenticatorResponse {
     readonly attribute ArrayBuffer      authenticatorData;
     readonly attribute ArrayBuffer      signature;
 };
 
 dictionary AssertionOptions {
     unsigned long                        timeoutSeconds;
     USVString                            rpId;
     sequence<ScopedCredentialDescriptor> allowList;
@@ -105,13 +103,13 @@ enum WebAuthnTransport {
 interface WebAuthentication {
     Promise<PublicKeyCredential> makeCredential (
         Account                                 accountInformation,
         sequence<ScopedCredentialParameters>    cryptoParameters,
         BufferSource                            attestationChallenge,
         optional ScopedCredentialOptions        options
     );
 
-    Promise<WebAuthnAssertion> getAssertion (
+    Promise<PublicKeyCredential> getAssertion (
         BufferSource               assertionChallenge,
         optional AssertionOptions  options
     );
 };