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 codes calls that method in the current nsHTMLDocument.
MozReview-Commit-ID: GN1E4U8sIsn
--- a/dom/u2f/WebAuthentication.cpp
+++ b/dom/u2f/WebAuthentication.cpp
@@ -5,16 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/WebAuthentication.h"
#include "mozilla/dom/WebAuthnAssertion.h"
#include "mozilla/dom/WebAuthnAttestation.h"
#include "mozilla/dom/Promise.h"
#include "nsICryptoHash.h"
+#include "nsHTMLDocument.h"
#include "pkix/Input.h"
#include "pkixutil.h"
namespace mozilla {
namespace dom {
extern mozilla::LazyLogModule gWebauthLog; // defined in U2F.cpp
@@ -634,16 +635,38 @@ 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;
+ }
+
+ RefPtr<nsHTMLDocument> htmlDoc = document->AsHTMLDocument();
+
+ ErrorResult rv;
+ nsCOMPtr<nsIURI> relaxedUri = htmlDoc->RelaxSameOriginForDomain(aInputRpId,
+ rv);
+ if (rv.Failed()) {
+ return rv.StealNSResult();
+ }
+
+ return relaxedUri->GetAsciiHost(aRelaxedRpId);
+}
+
already_AddRefed<Promise>
WebAuthentication::MakeCredential(JSContext* aCx, const Account& aAccount,
const Sequence<ScopedCredentialParameters>& aCryptoParameters,
const ArrayBufferViewOrArrayBuffer& aChallenge,
const ScopedCredentialOptions& aOptions)
{
MOZ_ASSERT(mParent);
nsPIDOMWindowInner* window = GetParentObject();
@@ -695,19 +718,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 +920,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
--- a/dom/u2f/moz.build
+++ b/dom/u2f/moz.build
@@ -30,14 +30,16 @@ UNIFIED_SOURCES += [
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/dom/base',
'/dom/crypto',
+ '/dom/html',
+ '/layout/style',
'/security/manager/ssl',
'/security/pkix/include',
'/security/pkix/lib',
]
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']