Bug 1721220 - Add BAD_STS_CERT error r=geckoview-reviewers,nika,agi,owlish

Differential Revision: https://phabricator.services.mozilla.com/D146234
This commit is contained in:
Cathy Lu 2022-05-25 17:51:11 +00:00
parent 0cf67ce1eb
commit 803a4e8449
10 changed files with 83 additions and 8 deletions

View file

@ -119,6 +119,7 @@ https://sub2.test1.example.com:443 privileged
https://sub2.test2.example.com:443 privileged
https://example.net:443 privileged
https://nocert.example.com:443 privileged,nocert
https://nocert.example.org:443 privileged,nocert
https://self-signed.example.com:443 privileged,cert=selfsigned
https://untrusted.example.com:443 privileged,cert=untrusted
https://expired.example.com:443 privileged,cert=expired

View file

@ -3561,6 +3561,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
const char* errorDescriptionID = nullptr;
AutoTArray<nsString, 3> formatStrs;
bool addHostPort = false;
bool isBadStsCertError = false;
nsresult rv = NS_OK;
nsAutoString messageStr;
nsAutoCString cssClass;
@ -3710,6 +3711,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
// In the future we should differentiate between an HSTS host and a
// pinned host and display a more informative message to the user.
if (isStsHost || isPinnedHost) {
isBadStsCertError = true;
cssClass.AssignLiteral("badStsCert");
}
@ -3870,19 +3872,21 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
}
}
nsresult delegateErrorCode = aError;
// If the HTTPS-Only Mode upgraded this request and the upgrade might have
// caused this error, we replace the error-page with about:httpsonlyerror
bool isHttpsOnlyError =
nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(aFailedChannel, aError);
if (isHttpsOnlyError) {
if (nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(aFailedChannel, aError)) {
errorPage.AssignLiteral("httpsonlyerror");
delegateErrorCode = NS_ERROR_HTTPS_ONLY;
} else if (isBadStsCertError) {
delegateErrorCode = NS_ERROR_BAD_HSTS_CERT;
}
if (nsCOMPtr<nsILoadURIDelegate> loadURIDelegate = GetLoadURIDelegate()) {
nsresult code = isHttpsOnlyError ? NS_ERROR_HTTPS_ONLY : aError;
nsCOMPtr<nsIURI> errorPageURI;
rv = loadURIDelegate->HandleLoadError(aURI, code, NS_ERROR_GET_MODULE(code),
getter_AddRefs(errorPageURI));
rv = loadURIDelegate->HandleLoadError(
aURI, delegateErrorCode, NS_ERROR_GET_MODULE(delegateErrorCode),
getter_AddRefs(errorPageURI));
// If the docshell is going away there's no point in showing an error page.
if (NS_FAILED(rv) || mIsBeingDestroyed) {
*aDisplayedErrorPage = false;

View file

@ -2376,6 +2376,7 @@ package org.mozilla.geckoview {
@AnyThread public class WebRequestError extends Exception {
ctor public WebRequestError(int, int);
ctor public WebRequestError(int, int, X509Certificate);
field public static final int ERROR_BAD_HSTS_CERT = 179;
field public static final int ERROR_CATEGORY_CONTENT = 4;
field public static final int ERROR_CATEGORY_NETWORK = 3;
field public static final int ERROR_CATEGORY_PROXY = 6;

View file

@ -0,0 +1,6 @@
function handleRequest(request, response) {
response.setHeader(
"Strict-Transport-Security",
"max-age=60; includeSubDomains"
);
}

View file

@ -625,6 +625,51 @@ class NavigationDelegateTest : BaseSessionTest() {
sessionRule.runtime.settings.setAllowInsecureConnections(GeckoRuntimeSettings.ALLOW_ALL)
}
@Test fun loadHSTSBadCert() {
// TODO: Bug 1673954
assumeThat(sessionRule.env.isFission, equalTo(false))
val httpsFirstPref = "dom.security.https_first"
assertThat("https pref should be false", sessionRule.getPrefs(httpsFirstPref)[0] as Boolean, equalTo(false))
// load secure url with hsts header
val uri = "https://example.org/tests/junit/hsts_header.sjs"
mainSession.loadUri(uri)
mainSession.waitForPageStop()
// load insecure subdomain url to see if it gets upgraded to https
val http_uri = "http://test1.example.org/"
val https_uri = "https://test1.example.org/"
mainSession.loadUri(http_uri)
mainSession.waitForPageStop()
mainSession.forCallbacksDuringWait(object : NavigationDelegate {
@AssertCalled(count = 2)
override fun onLoadRequest(session: GeckoSession,
request: LoadRequest):
GeckoResult<AllowOrDeny>? {
assertThat("URI should be HTTP then redirected to HTTPS",
request.uri, equalTo(forEachCall(http_uri, https_uri)))
return null
}
})
// load subdomain that will trigger the cert error
val no_cert_uri = "https://nocert.example.org/"
mainSession.loadUri(no_cert_uri)
mainSession.waitForPageStop()
mainSession.forCallbacksDuringWait(object : NavigationDelegate {
@AssertCalled(count = 1)
override fun onLoadError(session: GeckoSession, uri: String?, error: WebRequestError): GeckoResult<String>? {
assertThat("categories should match", error.category, equalTo(WebRequestError.ERROR_CATEGORY_NETWORK))
assertThat("codes should match", error.code, equalTo(WebRequestError.ERROR_BAD_HSTS_CERT))
return null
}
})
}
@Ignore // Disabled for bug 1619344.
@Test fun loadUnknownProtocol() {
testLoadEarlyError(UNKNOWN_PROTOCOL_URI,

View file

@ -67,7 +67,8 @@ public class WebRequestError extends Exception {
ERROR_UNSAFE_CONTENT_TYPE,
ERROR_CORRUPTED_CONTENT,
ERROR_DATA_URI_TOO_LONG,
ERROR_HTTPS_ONLY
ERROR_HTTPS_ONLY,
ERROR_BAD_HSTS_CERT
})
public @interface Error {}
@ -134,6 +135,12 @@ public class WebRequestError extends Exception {
*/
public static final int ERROR_HTTPS_ONLY = 0xA3;
/**
* A certificate validation error occurred when connecting to a site that does not allow error
* overrides.
*/
public static final int ERROR_BAD_HSTS_CERT = 0xB3;
// Content
/** A content type was returned which was deemed unsafe. */
public static final int ERROR_UNSAFE_CONTENT_TYPE = 0x24;
@ -326,6 +333,9 @@ public class WebRequestError extends Exception {
if (geckoError == XPCOMError.NS_ERROR_HTTPS_ONLY) {
return ERROR_HTTPS_ONLY;
}
if (geckoError == XPCOMError.NS_ERROR_BAD_HSTS_CERT) {
return ERROR_BAD_HSTS_CERT;
}
if (geckoError == XPCOMError.NS_ERROR_OFFLINE) {
return ERROR_OFFLINE;
}

View file

@ -30,6 +30,8 @@ exclude: true
([bug 1758800]({{bugzilla}}1758800))
- Deprecated [`GeckoSession.autofill`][102.18], use [`Autofill.Session.autofill`][102.19] instead.
([bug 1770010]({{bugzilla}}1770010))
- Added [`WebRequestError.ERROR_BAD_HSTS_CERT`][102.20] error code to notify the app of a connection to a site that does not allow error overrides.
([bug 1721220]({{bugzilla}}1721220))
[102.1]: {{javadoc_uri}}/GeckoSession.PromptDelegate.DateTimePrompt.html#stepValue
[102.2]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date#step
@ -50,6 +52,7 @@ exclude: true
[102.17]: {{javadoc_uri}}/GeckoSession.PromptDelegate.PromptInstanceDelegate.html#onPromptUpdate(org.mozilla.geckoview.GeckoSession.PromptDelegate.BasePrompt)
[102.18]: {{javadoc_uri}}/GeckoSession.html#autofill(android.util.SparseArray)
[102.19]: {{javadoc_uri}}/Autofill.Session.html#autofill(android.util.SparseArray)
[102.20]: {{javadoc_uri}}/WebRequestError.html#ERROR_BAD_HSTS_CERT
## v101
- Added [`GeckoDisplay.surfaceChanged`][101.1] function taking new type [`GeckoDisplay.SurfaceInfo`][101.2].
@ -1204,4 +1207,4 @@ to allow adding gecko profiler markers.
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport(android.content.Context,android.os.Bundle,java.lang.String)
[65.25]: {{javadoc_uri}}/GeckoResult.html
[api-version]: dc9516b62971d881de4059eae2ea1b88a1ebb3d1
[api-version]: d06ece1a8d568d3c62ee1f6786f4ffe13476b29f

View file

@ -2161,6 +2161,8 @@ public class GeckoViewActivity extends AppCompatActivity
return "ERROR_CORRUPTED_CONTENT";
case WebRequestError.ERROR_HTTPS_ONLY:
return "ERROR_HTTPS_ONLY";
case WebRequestError.ERROR_BAD_HSTS_CERT:
return "ERROR_BAD_HSTS_CERT";
default:
return "UNKNOWN";
}

View file

@ -75,6 +75,7 @@ TEST_HARNESS_FILES.testing.mochitest.tests.junit += [
"geckoview/src/androidTest/assets/www/forms_iframe.html",
"geckoview/src/androidTest/assets/www/forms_xorigin.html",
"geckoview/src/androidTest/assets/www/hello.html",
"geckoview/src/androidTest/assets/www/hsts_header.sjs",
"geckoview/src/androidTest/assets/www/iframe_http_only.html",
"geckoview/src/androidTest/assets/www/simple_redirect.sjs",
"geckoview/src/androidTest/assets/www/update_manifest.json",

View file

@ -343,6 +343,8 @@ with modules["NETWORK"]:
# A connection to a non local address is refused because
# xpc::AreNonLocalConnectionsDisabled() returns true.
errors["NS_ERROR_NON_LOCAL_CONNECTION_REFUSED"] = FAILURE(88)
# Connection to a sts host without a hsts header.
errors["NS_ERROR_BAD_HSTS_CERT"] = FAILURE(89)
# XXX really need to better rationalize these error codes. are consumers of
# necko really expected to know how to discern the meaning of these??