Bug 1309284 - WebAuthn JS API [part 3]: Support origin relax algorithm r=keeler draft
authorJ.C. Jones <jjones@mozilla.com>
Mon, 09 Jan 2017 13:55:59 -0700
changeset 457782 1d1cbdabfa79097be5ad14a5e4ecb887883453e4
parent 457781 52151480b4b2b600a598c06678b28f6be581e5e6
child 457783 72cd4970c78254ec43612f1c1ffbbbcb6116c39b
push id40890
push userjjones@mozilla.com
push dateMon, 09 Jan 2017 22:16:19 +0000
reviewerskeeler
bugs1309284, 1329764
milestone53.0a1
Bug 1309284 - WebAuthn JS API [part 3]: Support origin relax algorithm r=keeler The WebAuthn specification calls for running the HTML5.1 algorithm that occurs when you modify document.domain from JS, and use that algorithm's output for the "Relying Party ID" through the rest of the WebAuthn algorithm. This code paves the way for that to be added in Bug 1329764, once the spec issues upstream are resolved. MozReview-Commit-ID: DNNcr3Gh1Be
dom/u2f/WebAuthentication.cpp
dom/u2f/WebAuthentication.h
--- a/dom/u2f/WebAuthentication.cpp
+++ b/dom/u2f/WebAuthentication.cpp
@@ -636,16 +636,31 @@ WebAuthentication::U2FAuthGetAssertion(c
     return;
   }
 
   // 4.1.2.9 Reject promise with a DOMException whose name is "NotAllowedError",
   // and terminate this algorithm.
   aRequest->SetFailure(NS_ERROR_DOM_NOT_ALLOWED_ERR);
 }
 
+nsresult
+WebAuthentication::RelaxSameOrigin(const nsAString& aInputRpId,
+                                   /* out */ nsACString& aRelaxedRpId)
+{
+  MOZ_ASSERT(mParent);
+  nsCOMPtr<nsIDocument> document = mParent->GetDoc();
+  if (!document || !document->IsHTMLDocument()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // TODO: Bug 1329764: Invoke the Relax Algorithm, once properly defined
+  aRelaxedRpId.Assign(NS_ConvertUTF16toUTF8(aInputRpId));
+  return NS_OK;
+}
+
 already_AddRefed<Promise>
 WebAuthentication::MakeCredential(JSContext* aCx, const Account& aAccount,
                   const Sequence<ScopedCredentialParameters>& aCryptoParameters,
                   const ArrayBufferViewOrArrayBuffer& aChallenge,
                   const ScopedCredentialOptions& aOptions)
 {
   MOZ_ASSERT(mParent);
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
@@ -697,19 +712,20 @@ WebAuthentication::MakeCredential(JSCont
     // 4.1.1.3.b If rpId is specified, then invoke the procedure used for
     // relaxing the same-origin restriction by setting the document.domain
     // attribute, using rpId as the given value but without changing the current
     // document’s domain. If no errors are thrown, set rpId to the value of host
     // as computed by this procedure, and rpIdHash to the SHA-256 hash of rpId.
     // Otherwise, reject promise with a DOMException whose name is
     // "SecurityError", and terminate this algorithm.
 
-    // TODO: relax the same-origin restriction
-
-    rpId.Assign(NS_ConvertUTF16toUTF8(aOptions.mRpId.Value()));
+    if (NS_FAILED(RelaxSameOrigin(aOptions.mRpId.Value(), rpId))) {
+      promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
+      return promise.forget();
+    }
   }
 
   CryptoBuffer rpIdHash;
   if (!rpIdHash.SetLength(SHA256_LENGTH, fallible)) {
     promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
     return promise.forget();
   }
 
@@ -896,19 +912,20 @@ WebAuthentication::GetAssertion(const Ar
     // 4.1.2.3.b If rpId is specified, then invoke the procedure used for
     // relaxing the same-origin restriction by setting the document.domain
     // attribute, using rpId as the given value but without changing the current
     // document’s domain. If no errors are thrown, set rpId to the value of host
     // as computed by this procedure, and rpIdHash to the SHA-256 hash of rpId.
     // Otherwise, reject promise with a DOMException whose name is
     // "SecurityError", and terminate this algorithm.
 
-    // TODO: relax the same-origin restriction
-
-    rpId.Assign(NS_ConvertUTF16toUTF8(aOptions.mRpId.Value()));
+    if (NS_FAILED(RelaxSameOrigin(aOptions.mRpId.Value(), rpId))) {
+      promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
+      return promise.forget();
+    }
   }
 
   CryptoBuffer rpIdHash;
   if (!rpIdHash.SetLength(SHA256_LENGTH, fallible)) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     return promise.forget();
   }
 
--- a/dom/u2f/WebAuthentication.h
+++ b/dom/u2f/WebAuthentication.h
@@ -93,16 +93,19 @@ private:
              const WebAuthnExtensions& aExtensions);
   void
   U2FAuthGetAssertion(const RefPtr<AssertionRequest>& aRequest,
                    const Authenticator& aToken, CryptoBuffer& aRpIdHash,
                    const nsACString& aClientData, CryptoBuffer& aClientDataHash,
                    nsTArray<CryptoBuffer>& aAllowList,
                    const WebAuthnExtensions& aExtensions);
 
+  nsresult
+  RelaxSameOrigin(const nsAString& aInputRpId, nsACString& aRelaxedRpId);
+
   nsCOMPtr<nsPIDOMWindowInner> mParent;
   nsString mOrigin;
   Sequence<Authenticator> mAuthenticators;
   bool mInitialized;
 };
 
 } // namespace dom
 } // namespace mozilla