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://sub2.test2.example.com:443 privileged
https://example.net:443 privileged https://example.net:443 privileged
https://nocert.example.com:443 privileged,nocert https://nocert.example.com:443 privileged,nocert
https://nocert.example.org:443 privileged,nocert
https://self-signed.example.com:443 privileged,cert=selfsigned https://self-signed.example.com:443 privileged,cert=selfsigned
https://untrusted.example.com:443 privileged,cert=untrusted https://untrusted.example.com:443 privileged,cert=untrusted
https://expired.example.com:443 privileged,cert=expired https://expired.example.com:443 privileged,cert=expired

View file

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

View file

@ -2376,6 +2376,7 @@ package org.mozilla.geckoview {
@AnyThread public class WebRequestError extends Exception { @AnyThread public class WebRequestError extends Exception {
ctor public WebRequestError(int, int); ctor public WebRequestError(int, int);
ctor public WebRequestError(int, int, X509Certificate); 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_CONTENT = 4;
field public static final int ERROR_CATEGORY_NETWORK = 3; field public static final int ERROR_CATEGORY_NETWORK = 3;
field public static final int ERROR_CATEGORY_PROXY = 6; 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) 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. @Ignore // Disabled for bug 1619344.
@Test fun loadUnknownProtocol() { @Test fun loadUnknownProtocol() {
testLoadEarlyError(UNKNOWN_PROTOCOL_URI, testLoadEarlyError(UNKNOWN_PROTOCOL_URI,

View file

@ -67,7 +67,8 @@ public class WebRequestError extends Exception {
ERROR_UNSAFE_CONTENT_TYPE, ERROR_UNSAFE_CONTENT_TYPE,
ERROR_CORRUPTED_CONTENT, ERROR_CORRUPTED_CONTENT,
ERROR_DATA_URI_TOO_LONG, ERROR_DATA_URI_TOO_LONG,
ERROR_HTTPS_ONLY ERROR_HTTPS_ONLY,
ERROR_BAD_HSTS_CERT
}) })
public @interface Error {} public @interface Error {}
@ -134,6 +135,12 @@ public class WebRequestError extends Exception {
*/ */
public static final int ERROR_HTTPS_ONLY = 0xA3; 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 // Content
/** A content type was returned which was deemed unsafe. */ /** A content type was returned which was deemed unsafe. */
public static final int ERROR_UNSAFE_CONTENT_TYPE = 0x24; 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) { if (geckoError == XPCOMError.NS_ERROR_HTTPS_ONLY) {
return 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) { if (geckoError == XPCOMError.NS_ERROR_OFFLINE) {
return ERROR_OFFLINE; return ERROR_OFFLINE;
} }

View file

@ -30,6 +30,8 @@ exclude: true
([bug 1758800]({{bugzilla}}1758800)) ([bug 1758800]({{bugzilla}}1758800))
- Deprecated [`GeckoSession.autofill`][102.18], use [`Autofill.Session.autofill`][102.19] instead. - Deprecated [`GeckoSession.autofill`][102.18], use [`Autofill.Session.autofill`][102.19] instead.
([bug 1770010]({{bugzilla}}1770010)) ([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.1]: {{javadoc_uri}}/GeckoSession.PromptDelegate.DateTimePrompt.html#stepValue
[102.2]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date#step [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.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.18]: {{javadoc_uri}}/GeckoSession.html#autofill(android.util.SparseArray)
[102.19]: {{javadoc_uri}}/Autofill.Session.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 ## v101
- Added [`GeckoDisplay.surfaceChanged`][101.1] function taking new type [`GeckoDisplay.SurfaceInfo`][101.2]. - 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.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport(android.content.Context,android.os.Bundle,java.lang.String)
[65.25]: {{javadoc_uri}}/GeckoResult.html [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"; return "ERROR_CORRUPTED_CONTENT";
case WebRequestError.ERROR_HTTPS_ONLY: case WebRequestError.ERROR_HTTPS_ONLY:
return "ERROR_HTTPS_ONLY"; return "ERROR_HTTPS_ONLY";
case WebRequestError.ERROR_BAD_HSTS_CERT:
return "ERROR_BAD_HSTS_CERT";
default: default:
return "UNKNOWN"; 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_iframe.html",
"geckoview/src/androidTest/assets/www/forms_xorigin.html", "geckoview/src/androidTest/assets/www/forms_xorigin.html",
"geckoview/src/androidTest/assets/www/hello.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/iframe_http_only.html",
"geckoview/src/androidTest/assets/www/simple_redirect.sjs", "geckoview/src/androidTest/assets/www/simple_redirect.sjs",
"geckoview/src/androidTest/assets/www/update_manifest.json", "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 # A connection to a non local address is refused because
# xpc::AreNonLocalConnectionsDisabled() returns true. # xpc::AreNonLocalConnectionsDisabled() returns true.
errors["NS_ERROR_NON_LOCAL_CONNECTION_REFUSED"] = FAILURE(88) 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 # XXX really need to better rationalize these error codes. are consumers of
# necko really expected to know how to discern the meaning of these?? # necko really expected to know how to discern the meaning of these??