bug 1332681 - part 2/4 - authentication.getAssertion: return a PublicKeyCredential instead of a WebAuthnAssertion r?jcj,qdot draft
authorDavid Keeler <dkeeler@mozilla.com>
Mon, 22 May 2017 13:03:58 -0700
changeset 590355 3c949f2f4523aea3d2cb474ddfa9bbea88eb6571
parent 590354 0f07758ee0f95dd40372c7cee67375619a819e6f
child 590356 7524671e6792ce63d9d290bd42c0a1851d4771b8
push id62720
push userbmo:dkeeler@mozilla.com
push dateWed, 07 Jun 2017 18:21:33 +0000
reviewersjcj, qdot
bugs1332681
milestone55.0a1
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
     );
 };