Skip to content

Commit

Permalink
Bug 1555963 - Add WindowGlobalParent.getSecurityInfo(). r=nika,mconley
Browse files Browse the repository at this point in the history
This adds an API for fetching security info per frame, no matter if we have
a certificate error or a valid certificate.

I tried to make this work in a Fission-compatible way, let me know if this
is the right approach.

Differential Revision: https://phabricator.services.mozilla.com/D34354
  • Loading branch information
Johann Hofmann committed Jun 21, 2019
1 parent b04f2ab commit 0be95c4
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 1 deletion.
5 changes: 4 additions & 1 deletion browser/base/content/test/siteIdentity/browser.ini
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ tags = mcb
support-files =
file_csp_block_all_mixedcontent.html
file_csp_block_all_mixedcontent.js
[browser_deprecatedTLSVersions.js]
[browser_getSecurityInfo.js]
support-files =
dummy_iframe_page.html
[browser_identity_UI.js]
[browser_identityBlock_focus.js]
support-files = ../permissions/permissions.html
Expand Down Expand Up @@ -115,4 +119,3 @@ support-files =
support-files =
file_mixedPassiveContent.html
file_bug1045809_1.html
[browser_deprecatedTLSVersions.js]
57 changes: 57 additions & 0 deletions browser/base/content/test/siteIdentity/browser_getSecurityInfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */

const MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.MOZILLA_PKIX_ERROR_BASE;
const MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT = MOZILLA_PKIX_ERROR_BASE + 14;

const IFRAME_PAGE = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com") + "dummy_iframe_page.html";

// Tests the getSecurityInfo() function exposed on WindowGlobalParent.
add_task(async function test() {
await BrowserTestUtils.withNewTab("about:blank", async function(browser) {
let loaded = BrowserTestUtils.waitForErrorPage(browser);
await BrowserTestUtils.loadURI(browser, "https://self-signed.example.com");
await loaded;

let securityInfo = await browser.browsingContext.currentWindowGlobal.getSecurityInfo();
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
ok(securityInfo, "Found some security info");
ok(securityInfo.failedCertChain, "Has a failed cert chain");
is(securityInfo.errorCode, MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT, "Has the correct error code");
is(securityInfo.serverCert.commonName, "self-signed.example.com", "Has the correct certificate");

loaded = BrowserTestUtils.browserLoaded(browser);
await BrowserTestUtils.loadURI(browser, "http://example.com");
await loaded;

securityInfo = await browser.browsingContext.currentWindowGlobal.getSecurityInfo();
is(securityInfo, null, "Found no security info");

loaded = BrowserTestUtils.browserLoaded(browser);
await BrowserTestUtils.loadURI(browser, "https://example.com");
await loaded;

securityInfo = await browser.browsingContext.currentWindowGlobal.getSecurityInfo();
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
ok(securityInfo, "Found some security info");
ok(securityInfo.succeededCertChain, "Has a succeeded cert chain");
is(securityInfo.errorCode, 0, "Has no error code");
is(securityInfo.serverCert.commonName, "example.com", "Has the correct certificate");

loaded = BrowserTestUtils.browserLoaded(browser);
await BrowserTestUtils.loadURI(browser, IFRAME_PAGE);
await loaded;

// Get the info of the parent, which is HTTP.
securityInfo = await browser.browsingContext.currentWindowGlobal.getSecurityInfo();
is(securityInfo, null, "Found no security info");

// Get the info of the frame, which is HTTPS.
securityInfo = await browser.browsingContext.getChildren()[0].currentWindowGlobal.getSecurityInfo();
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
ok(securityInfo, "Found some security info");
ok(securityInfo.succeededCertChain, "Has a succeeded cert chain");
is(securityInfo.errorCode, 0, "Has no error code");
is(securityInfo.serverCert.commonName, "example.com", "Has the correct certificate");
});
});
10 changes: 10 additions & 0 deletions browser/base/content/test/siteIdentity/dummy_iframe_page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html>
<head>
<title>Dummy iframe test page</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
</head>
<body>
<iframe src="https://example.org"></iframe>
<p>Dummy test page</p>
</body>
</html>
13 changes: 13 additions & 0 deletions dom/chrome-webidl/WindowGlobalActors.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface Principal;
interface URI;
interface nsIDocShell;
interface RemoteTab;
interface nsITransportSecurityInfo;

[Exposed=Window, ChromeOnly]
interface WindowGlobalParent {
Expand Down Expand Up @@ -54,6 +55,18 @@ interface WindowGlobalParent {
Promise<unsigned long long> changeFrameRemoteness(
BrowsingContext? bc, DOMString remoteType,
unsigned long long pendingSwitchId);

/**
* Fetches the securityInfo object for this window. This function will
* look for failed and successful channels to find the security info,
* thus it will work on regular HTTPS pages as well as certificate
* error pages.
*
* This returns a Promise which resolves to an nsITransportSecurity
* object with certificate data or undefined if no security info is available.
*/
[Throws]
Promise<nsITransportSecurityInfo> getSecurityInfo();
};

[Exposed=Window, ChromeOnly]
Expand Down
5 changes: 5 additions & 0 deletions dom/ipc/PWindowGlobal.ipdl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ child:
uint64_t aSwitchId)
returns (nsresult rv, nullable PBrowserBridge bridge);

/**
* Returns the serialized security info associated with this window.
*/
async GetSecurityInfo() returns(nsCString? serializedSecInfo);

both:
async RawMessage(JSWindowActorMessageMeta aMetadata, ClonedMessageData aData);

Expand Down
31 changes: 31 additions & 0 deletions dom/ipc/WindowGlobalChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "nsGlobalWindowInner.h"
#include "nsFrameLoaderOwner.h"
#include "nsQueryObject.h"
#include "nsSerializationHelper.h"

#include "mozilla/dom/JSWindowActorBinding.h"
#include "mozilla/dom/JSWindowActorChild.h"
Expand Down Expand Up @@ -253,6 +254,36 @@ IPCResult WindowGlobalChild::RecvChangeFrameRemoteness(
return IPC_OK();
}

mozilla::ipc::IPCResult WindowGlobalChild::RecvGetSecurityInfo(
GetSecurityInfoResolver&& aResolve) {
Maybe<nsCString> result;

if (nsCOMPtr<Document> doc = mWindowGlobal->GetDoc()) {
nsCOMPtr<nsISupports> secInfo;
nsresult rv = NS_OK;

// First check if there's a failed channel, in case of a certificate
// error.
if (nsIChannel* failedChannel = doc->GetFailedChannel()) {
rv = failedChannel->GetSecurityInfo(getter_AddRefs(secInfo));
} else {
// When there's no failed channel we should have a regular
// security info on the document. In some cases there's no
// security info at all, i.e. on HTTP sites.
secInfo = doc->GetSecurityInfo();
}

if (NS_SUCCEEDED(rv) && secInfo) {
nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(secInfo);
result.emplace();
NS_SerializeToString(secInfoSer, result.ref());
}
}

aResolve(result);
return IPC_OK();
}

IPCResult WindowGlobalChild::RecvRawMessage(
const JSWindowActorMessageMeta& aMeta, const ClonedMessageData& aData) {
StructuredCloneData data;
Expand Down
3 changes: 3 additions & 0 deletions dom/ipc/WindowGlobalChild.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ class WindowGlobalChild final : public WindowGlobalActor,
dom::BrowsingContext* aBc, const nsString& aRemoteType,
uint64_t aPendingSwitchId, ChangeFrameRemotenessResolver&& aResolver);

mozilla::ipc::IPCResult RecvGetSecurityInfo(
GetSecurityInfoResolver&& aResolve);

virtual void ActorDestroy(ActorDestroyReason aWhy) override;

private:
Expand Down
41 changes: 41 additions & 0 deletions dom/ipc/WindowGlobalParent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include "nsGlobalWindowInner.h"
#include "nsQueryObject.h"
#include "nsFrameLoaderOwner.h"
#include "nsSerializationHelper.h"
#include "nsITransportSecurityInfo.h"

#include "mozilla/dom/JSWindowActorBinding.h"
#include "mozilla/dom/JSWindowActorParent.h"
Expand Down Expand Up @@ -319,6 +321,45 @@ already_AddRefed<Promise> WindowGlobalParent::ChangeFrameRemoteness(
return promise.forget();
}

already_AddRefed<Promise> WindowGlobalParent::GetSecurityInfo(
ErrorResult& aRv) {
RefPtr<BrowserParent> browserParent = GetBrowserParent();
if (NS_WARN_IF(!browserParent)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}

nsIGlobalObject* global = xpc::NativeGlobal(xpc::PrivilegedJunkScope());
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}

SendGetSecurityInfo(
[promise](Maybe<nsCString>&& aResult) {
if (aResult) {
nsCOMPtr<nsISupports> infoObj;
nsresult rv =
NS_DeserializeObject(aResult.value(), getter_AddRefs(infoObj));
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeReject(NS_ERROR_FAILURE);
}
nsCOMPtr<nsITransportSecurityInfo> info = do_QueryInterface(infoObj);
if (!info) {
promise->MaybeReject(NS_ERROR_FAILURE);
}
promise->MaybeResolve(info);
} else {
promise->MaybeResolveWithUndefined();
}
},
[promise](ResponseRejectReason&& aReason) {
promise->MaybeReject(NS_ERROR_FAILURE);
});

return promise.forget();
}

void WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy) {
mIPCClosed = true;
gWindowGlobalParentsById->Remove(mInnerWindowId);
Expand Down
2 changes: 2 additions & 0 deletions dom/ipc/WindowGlobalParent.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ class WindowGlobalParent final : public WindowGlobalActor,
uint64_t aPendingSwitchId,
ErrorResult& aRv);

already_AddRefed<Promise> GetSecurityInfo(ErrorResult& aRv);

// Create a WindowGlobalParent from over IPC. This method should not be called
// from outside of the IPC constructors.
WindowGlobalParent(const WindowGlobalInit& aInit, bool aInProcess);
Expand Down

0 comments on commit 0be95c4

Please sign in to comment.