mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1124649 - Part 1 - Add specific error messages for various types of STS and PKP header failures. r=keeler,hurley
This commit is contained in:
parent
d055b1efb8
commit
434f38e0f3
@ -7,8 +7,9 @@
|
||||
|
||||
const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/" +
|
||||
"test/test-bug-846918-hsts-invalid-headers.html";
|
||||
const HSTS_INVALID_HEADER_MSG = "The site specified an invalid " +
|
||||
"Strict-Transport-Security header.";
|
||||
const HSTS_INVALID_HEADER_MSG = "Strict-Transport-Security: The site " +
|
||||
"specified a header that did not include a " +
|
||||
"'max-age' directive.";
|
||||
const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Security/" +
|
||||
"HTTP_Strict_Transport_Security";
|
||||
|
||||
|
@ -8,11 +8,11 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,Web Console subresource STS " +
|
||||
const TEST_URI = "data:text/html;charset=utf-8,Web Console subresource STS " +
|
||||
"warning test";
|
||||
const TEST_DOC = "https://example.com/browser/browser/devtools/webconsole/" +
|
||||
"test/test_bug1092055_shouldwarn.html";
|
||||
const SAMPLE_MSG = "invalid Strict-Transport-Security header";
|
||||
const SAMPLE_MSG = "specified a header that could not be parsed successfully.";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
let { browser } = yield loadTab(TEST_URI);
|
||||
|
@ -16,10 +16,32 @@ CORSInvalidAllowMethod=Cross-Origin Request Blocked: The Same Origin Policy disa
|
||||
CORSInvalidAllowHeader=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: invalid token '%2$S' in CORS header 'Access-Control-Allow-Headers').
|
||||
CORSMissingAllowHeaderFromPreflight=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: missing token '%2$S' in CORS header 'Access-Control-Allow-Headers' from CORS preflight channel).
|
||||
|
||||
# LOCALIZATION NOTE: Do not translate "Strict-Transport-Security" or "HSTS"
|
||||
InvalidSTSHeaders=The site specified an invalid Strict-Transport-Security header.
|
||||
# LOCALIZATION NOTE: Do not translate "Public-Key-Pins or HPKP"
|
||||
InvalidPKPHeaders=The site specified an invalid Public-Key-Pins header.
|
||||
# LOCALIZATION NOTE: Do not translate "Strict-Transport-Security", "HSTS", "max-age" or "includeSubDomains"
|
||||
STSUnknownError=Strict-Transport-Security: An unknown error occurred processing the header specified by the site.
|
||||
STSUntrustworthyConnection=Strict-Transport-Security: The connection to the site is untrustworthy, so the specified header was ignored.
|
||||
STSCouldNotParseHeader=Strict-Transport-Security: The site specified a header that could not be parsed successfully.
|
||||
STSNoMaxAge=Strict-Transport-Security: The site specified a header that did not include a 'max-age' directive.
|
||||
STSMultipleMaxAges=Strict-Transport-Security: The site specified a header that included multiple 'max-age' directives.
|
||||
STSInvalidMaxAge=Strict-Transport-Security: The site specified a header that included an invalid 'max-age' directive.
|
||||
STSMultipleIncludeSubdomains=Strict-Transport-Security: The site specified a header that included multiple 'includeSubDomains' directives.
|
||||
STSInvalidIncludeSubdomains=Strict-Transport-Security: The site specified a header that included an invalid 'includeSubDomains' directive.
|
||||
STSCouldNotSaveState=Strict-Transport-Security: An error occurred noting the site as a Strict-Transport-Security host.
|
||||
|
||||
# LOCALIZATION NOTE: Do not translate "Public-Key-Pins", "HPKP", "max-age" or "includeSubDomains"
|
||||
PKPUnknownError=Public-Key-Pins: An unknown error occurred processing the header specified by the site.
|
||||
PKPUntrustworthyConnection=Public-Key-Pins: The connection to the site is untrustworthy, so the specified header was ignored.
|
||||
PKPCouldNotParseHeader=Public-Key-Pins: The site specified a header that could not be parsed successfully.
|
||||
PKPNoMaxAge=Public-Key-Pins: The site specified a header that did not include a 'max-age' directive.
|
||||
PKPMultipleMaxAges=Public-Key-Pins: The site specified a header that included multiple 'max-age' directives.
|
||||
PKPInvalidMaxAge=Public-Key-Pins: The site specified a header that included an invalid 'max-age' directive.
|
||||
PKPMultipleIncludeSubdomains=Public-Key-Pins: The site specified a header that included multiple 'includeSubDomains' directives.
|
||||
PKPInvalidIncludeSubdomains=Public-Key-Pins: The site specified a header that included an invalid 'includeSubDomains' directive.
|
||||
PKPInvalidPin=Public-Key-Pins: The site specified a header that included an invalid pin.
|
||||
PKPMultipleReportURIs=Public-Key-Pins: The site specified a header that included multiple 'report-uri' directives.
|
||||
PKPPinsetDoesNotMatch=Public-Key-Pins: The site specified a header that did not include a matching pin.
|
||||
PKPNoBackupPin=Public-Key-Pins: The site specified a header that did not include a backup pin.
|
||||
PKPCouldNotSaveState=Public-Key-Pins: An error occurred noting the site as a Public-Key-Pins host.
|
||||
|
||||
# LOCALIZATION NOTE: Do not translate "SHA-1"
|
||||
SHA1Sig=This site makes use of a SHA-1 Certificate; it's recommended you use certificates with signature algorithms that use hash functions stronger than SHA-1.
|
||||
InsecurePasswordsPresentOnPage=Password fields present on an insecure (http://) page. This is a security risk that allows user login credentials to be stolen.
|
||||
|
@ -1150,8 +1150,88 @@ nsHttpChannel::ProcessFailedProxyConnect(uint32_t httpStatus)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void
|
||||
GetSTSConsoleErrorTag(uint32_t failureResult, nsAString& consoleErrorTag)
|
||||
{
|
||||
switch (failureResult) {
|
||||
case nsISiteSecurityService::ERROR_UNTRUSTWORTHY_CONNECTION:
|
||||
consoleErrorTag = NS_LITERAL_STRING("STSUntrustworthyConnection");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_COULD_NOT_PARSE_HEADER:
|
||||
consoleErrorTag = NS_LITERAL_STRING("STSCouldNotParseHeader");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_NO_MAX_AGE:
|
||||
consoleErrorTag = NS_LITERAL_STRING("STSNoMaxAge");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_MULTIPLE_MAX_AGES:
|
||||
consoleErrorTag = NS_LITERAL_STRING("STSMultipleMaxAges");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_INVALID_MAX_AGE:
|
||||
consoleErrorTag = NS_LITERAL_STRING("STSInvalidMaxAge");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_MULTIPLE_INCLUDE_SUBDOMAINS:
|
||||
consoleErrorTag = NS_LITERAL_STRING("STSMultipleIncludeSubdomains");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_INVALID_INCLUDE_SUBDOMAINS:
|
||||
consoleErrorTag = NS_LITERAL_STRING("STSInvalidIncludeSubdomains");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE:
|
||||
consoleErrorTag = NS_LITERAL_STRING("STSCouldNotSaveState");
|
||||
break;
|
||||
default:
|
||||
consoleErrorTag = NS_LITERAL_STRING("STSUnknownError");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
GetPKPConsoleErrorTag(uint32_t failureResult, nsAString& consoleErrorTag)
|
||||
{
|
||||
switch (failureResult) {
|
||||
case nsISiteSecurityService::ERROR_UNTRUSTWORTHY_CONNECTION:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPUntrustworthyConnection");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_COULD_NOT_PARSE_HEADER:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPCouldNotParseHeader");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_NO_MAX_AGE:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPNoMaxAge");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_MULTIPLE_MAX_AGES:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPMultipleMaxAges");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_INVALID_MAX_AGE:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPInvalidMaxAge");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_MULTIPLE_INCLUDE_SUBDOMAINS:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPMultipleIncludeSubdomains");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_INVALID_INCLUDE_SUBDOMAINS:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPInvalidIncludeSubdomains");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_INVALID_PIN:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPInvalidPin");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_MULTIPLE_REPORT_URIS:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPMultipleReportURIs");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_PINSET_DOES_NOT_MATCH_CHAIN:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPPinsetDoesNotMatch");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_NO_BACKUP_PIN:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPNoBackupPin");
|
||||
break;
|
||||
case nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPCouldNotSaveState");
|
||||
break;
|
||||
default:
|
||||
consoleErrorTag = NS_LITERAL_STRING("PKPUnknownError");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single security header. Only two types are suported HSTS and HPKP.
|
||||
* Process a single security header. Only two types are supported: HSTS and HPKP.
|
||||
*/
|
||||
nsresult
|
||||
nsHttpChannel::ProcessSingleSecurityHeader(uint32_t aType,
|
||||
@ -1178,18 +1258,19 @@ nsHttpChannel::ProcessSingleSecurityHeader(uint32_t aType,
|
||||
NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
|
||||
// Process header will now discard the headers itself if the channel
|
||||
// wasn't secure (whereas before it had to be checked manually)
|
||||
uint32_t failureResult;
|
||||
rv = sss->ProcessHeader(aType, mURI, securityHeader.get(), aSSLStatus,
|
||||
aFlags, nullptr, nullptr);
|
||||
aFlags, nullptr, nullptr, &failureResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
nsAutoString consoleErrorCategory;
|
||||
nsAutoString consoleErrorTag;
|
||||
switch (aType) {
|
||||
case nsISiteSecurityService::HEADER_HSTS:
|
||||
consoleErrorTag = NS_LITERAL_STRING("InvalidSTSHeaders");
|
||||
GetSTSConsoleErrorTag(failureResult, consoleErrorTag);
|
||||
consoleErrorCategory = NS_LITERAL_STRING("Invalid HSTS Headers");
|
||||
break;
|
||||
case nsISiteSecurityService::HEADER_HPKP:
|
||||
consoleErrorTag = NS_LITERAL_STRING("InvalidPKPHeaders");
|
||||
GetPKPConsoleErrorTag(failureResult, consoleErrorTag);
|
||||
consoleErrorCategory = NS_LITERAL_STRING("Invalid HPKP Headers");
|
||||
break;
|
||||
default:
|
||||
|
@ -23,13 +23,28 @@ namespace mozilla
|
||||
[ref] native nsCStringTArrayRef(nsTArray<nsCString>);
|
||||
[ref] native mozillaPkixTime(mozilla::pkix::Time);
|
||||
|
||||
[scriptable, uuid(e219eace-0e04-42ba-b203-58a8b327867c)]
|
||||
[scriptable, uuid(e6cac961-9f03-4cc3-ad00-a829ae7304dc)]
|
||||
interface nsISiteSecurityService : nsISupports
|
||||
{
|
||||
const uint32_t HEADER_HSTS = 0;
|
||||
const uint32_t HEADER_HPKP = 1;
|
||||
const uint32_t HEADER_OMS = 2;
|
||||
|
||||
const uint32_t Success = 0;
|
||||
const uint32_t ERROR_UNKNOWN = 1;
|
||||
const uint32_t ERROR_UNTRUSTWORTHY_CONNECTION = 2;
|
||||
const uint32_t ERROR_COULD_NOT_PARSE_HEADER = 3;
|
||||
const uint32_t ERROR_NO_MAX_AGE = 4;
|
||||
const uint32_t ERROR_MULTIPLE_MAX_AGES = 5;
|
||||
const uint32_t ERROR_INVALID_MAX_AGE = 6;
|
||||
const uint32_t ERROR_MULTIPLE_INCLUDE_SUBDOMAINS = 7;
|
||||
const uint32_t ERROR_INVALID_INCLUDE_SUBDOMAINS = 8;
|
||||
const uint32_t ERROR_INVALID_PIN = 9;
|
||||
const uint32_t ERROR_MULTIPLE_REPORT_URIS = 10;
|
||||
const uint32_t ERROR_PINSET_DOES_NOT_MATCH_CHAIN = 11;
|
||||
const uint32_t ERROR_NO_BACKUP_PIN = 12;
|
||||
const uint32_t ERROR_COULD_NOT_SAVE_STATE = 13;
|
||||
|
||||
/**
|
||||
* Parses a given HTTP header and records the results internally.
|
||||
* Currently two header types are supported: HSTS (aka STS) and HPKP
|
||||
@ -37,9 +52,9 @@ interface nsISiteSecurityService : nsISupports
|
||||
* https://tools.ietf.org/html/rfc6797
|
||||
* and allows a host to specify that future HTTP requests should be
|
||||
* upgraded to HTTPS.
|
||||
* The Format of the HPKP header is currently defined by:
|
||||
* https://tools.ietf.org/html/draft-ietf-websec-key-pinning-20
|
||||
* and allows a host to speficy a subset of trusted anchors to be used
|
||||
* The format of the HPKP header is defined by the HPKP specification:
|
||||
* https://tools.ietf.org/html/rfc7469
|
||||
* and allows a host to specify a subset of trusted anchors to be used
|
||||
* in future HTTPS connections.
|
||||
*
|
||||
* @param aType the type of security header in question.
|
||||
@ -50,6 +65,8 @@ interface nsISiteSecurityService : nsISupports
|
||||
* NO_PERMANENT_STORAGE
|
||||
* @param aMaxAge the parsed max-age directive of the header.
|
||||
* @param aIncludeSubdomains the parsed includeSubdomains directive.
|
||||
* @param aFailureResult a more specific failure result if NS_ERROR_FAILURE
|
||||
was returned.
|
||||
* @return NS_OK if it succeeds
|
||||
* NS_ERROR_FAILURE if it can't be parsed
|
||||
* NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
|
||||
@ -61,7 +78,8 @@ interface nsISiteSecurityService : nsISupports
|
||||
in nsISSLStatus aSSLStatus,
|
||||
in uint32_t aFlags,
|
||||
[optional] out unsigned long long aMaxAge,
|
||||
[optional] out boolean aIncludeSubdomains);
|
||||
[optional] out boolean aIncludeSubdomains,
|
||||
[optional] out uint32_t aFailureResult);
|
||||
|
||||
/**
|
||||
* Same as processHeader but without checking for the security properties
|
||||
@ -72,7 +90,8 @@ interface nsISiteSecurityService : nsISupports
|
||||
in string aHeader,
|
||||
in uint32_t aFlags,
|
||||
[optional] out unsigned long long aMaxAge,
|
||||
[optional] out boolean aIncludeSubdomains);
|
||||
[optional] out boolean aIncludeSubdomains,
|
||||
[optional] out uint32_t aFailureResult);
|
||||
|
||||
/**
|
||||
* Given a header type, removes state relating to that header of a host,
|
||||
|
@ -397,15 +397,19 @@ nsSiteSecurityService::ProcessHeader(uint32_t aType,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains)
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
}
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
|
||||
aType == nsISiteSecurityService::HEADER_HPKP,
|
||||
NS_ERROR_NOT_IMPLEMENTED);
|
||||
|
||||
NS_ENSURE_ARG(aSSLStatus);
|
||||
return ProcessHeaderInternal(aType, aSourceURI, aHeader, aSSLStatus, aFlags,
|
||||
aMaxAge, aIncludeSubdomains);
|
||||
aMaxAge, aIncludeSubdomains, aFailureResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -414,10 +418,11 @@ nsSiteSecurityService::UnsafeProcessHeader(uint32_t aType,
|
||||
const char* aHeader,
|
||||
uint32_t aFlags,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains)
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
return ProcessHeaderInternal(aType, aSourceURI, aHeader, nullptr, aFlags,
|
||||
aMaxAge, aIncludeSubdomains);
|
||||
aMaxAge, aIncludeSubdomains, aFailureResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -427,8 +432,12 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains)
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
}
|
||||
// Only HSTS and HPKP are supported at the moment.
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
|
||||
aType == nsISiteSecurityService::HEADER_HPKP,
|
||||
@ -459,6 +468,9 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
|
||||
tlsIsBroken = tlsIsBroken || trustcheck;
|
||||
if (tlsIsBroken) {
|
||||
SSSLOG(("SSS: discarding header from untrustworthy connection"));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNTRUSTWORTHY_CONNECTION;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -474,11 +486,11 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
|
||||
switch (aType) {
|
||||
case nsISiteSecurityService::HEADER_HSTS:
|
||||
rv = ProcessSTSHeader(aSourceURI, aHeader, aFlags, aMaxAge,
|
||||
aIncludeSubdomains);
|
||||
aIncludeSubdomains, aFailureResult);
|
||||
break;
|
||||
case nsISiteSecurityService::HEADER_HPKP:
|
||||
rv = ProcessPKPHeader(aSourceURI, aHeader, aSSLStatus, aFlags, aMaxAge,
|
||||
aIncludeSubdomains);
|
||||
aIncludeSubdomains, aFailureResult);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected header type");
|
||||
@ -486,7 +498,7 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
|
||||
return rv;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
static uint32_t
|
||||
ParseSSSHeaders(uint32_t aType,
|
||||
const char* aHeader,
|
||||
bool& foundIncludeSubdomains,
|
||||
@ -495,7 +507,7 @@ ParseSSSHeaders(uint32_t aType,
|
||||
int64_t& maxAge,
|
||||
nsTArray<nsCString>& sha256keys)
|
||||
{
|
||||
// Stric transport security and Public Key Pinning have very similar
|
||||
// Strict transport security and Public Key Pinning have very similar
|
||||
// Header formats.
|
||||
|
||||
// "Strict-Transport-Security" ":" OWS
|
||||
@ -547,7 +559,7 @@ ParseSSSHeaders(uint32_t aType,
|
||||
nsresult rv = parser.Parse();
|
||||
if (NS_FAILED(rv)) {
|
||||
SSSLOG(("SSS: could not parse header"));
|
||||
return rv;
|
||||
return nsISiteSecurityService::ERROR_COULD_NOT_PARSE_HEADER;
|
||||
}
|
||||
mozilla::LinkedList<nsSecurityHeaderDirective>* directives = parser.GetDirectives();
|
||||
|
||||
@ -559,7 +571,7 @@ ParseSSSHeaders(uint32_t aType,
|
||||
max_age_var.Length())) {
|
||||
if (foundMaxAge) {
|
||||
SSSLOG(("SSS: found two max-age directives"));
|
||||
return NS_ERROR_FAILURE;
|
||||
return nsISiteSecurityService::ERROR_MULTIPLE_MAX_AGES;
|
||||
}
|
||||
|
||||
SSSLOG(("SSS: found max-age directive"));
|
||||
@ -570,13 +582,13 @@ ParseSSSHeaders(uint32_t aType,
|
||||
char chr = directive->mValue.CharAt(i);
|
||||
if (chr < '0' || chr > '9') {
|
||||
SSSLOG(("SSS: invalid value for max-age directive"));
|
||||
return NS_ERROR_FAILURE;
|
||||
return nsISiteSecurityService::ERROR_INVALID_MAX_AGE;
|
||||
}
|
||||
}
|
||||
|
||||
if (PR_sscanf(directive->mValue.get(), "%lld", &maxAge) != 1) {
|
||||
SSSLOG(("SSS: could not parse delta-seconds"));
|
||||
return NS_ERROR_FAILURE;
|
||||
return nsISiteSecurityService::ERROR_INVALID_MAX_AGE;
|
||||
}
|
||||
|
||||
SSSLOG(("SSS: parsed delta-seconds: %lld", maxAge));
|
||||
@ -585,7 +597,7 @@ ParseSSSHeaders(uint32_t aType,
|
||||
include_subd_var.Length())) {
|
||||
if (foundIncludeSubdomains) {
|
||||
SSSLOG(("SSS: found two includeSubdomains directives"));
|
||||
return NS_ERROR_FAILURE;
|
||||
return nsISiteSecurityService::ERROR_MULTIPLE_INCLUDE_SUBDOMAINS;
|
||||
}
|
||||
|
||||
SSSLOG(("SSS: found includeSubdomains directive"));
|
||||
@ -594,7 +606,7 @@ ParseSSSHeaders(uint32_t aType,
|
||||
if (directive->mValue.Length() != 0) {
|
||||
SSSLOG(("SSS: includeSubdomains directive unexpectedly had value '%s'",
|
||||
directive->mValue.get()));
|
||||
return NS_ERROR_FAILURE;
|
||||
return nsISiteSecurityService::ERROR_INVALID_INCLUDE_SUBDOMAINS;
|
||||
}
|
||||
} else if (aType == nsISiteSecurityService::HEADER_HPKP &&
|
||||
directive->mName.Length() == pin_sha256_var.Length() &&
|
||||
@ -603,18 +615,18 @@ ParseSSSHeaders(uint32_t aType,
|
||||
SSSLOG(("SSS: found pinning entry '%s' length=%d",
|
||||
directive->mValue.get(), directive->mValue.Length()));
|
||||
if (!stringIsBase64EncodingOf256bitValue(directive->mValue)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return nsISiteSecurityService::ERROR_INVALID_PIN;
|
||||
}
|
||||
sha256keys.AppendElement(directive->mValue);
|
||||
} else if (aType == nsISiteSecurityService::HEADER_HPKP &&
|
||||
directive->mName.Length() == report_uri_var.Length() &&
|
||||
directive->mName.EqualsIgnoreCase(report_uri_var.get(),
|
||||
report_uri_var.Length())) {
|
||||
// We doni't support the report-uri yet, but to avoid unrecognized
|
||||
// We don't support the report-uri yet, but to avoid unrecognized
|
||||
// directive warnings, we still have to handle its presence
|
||||
if (foundReportURI) {
|
||||
SSSLOG(("SSS: found two report-uri directives"));
|
||||
return NS_ERROR_FAILURE;
|
||||
return nsISiteSecurityService::ERROR_MULTIPLE_REPORT_URIS;
|
||||
}
|
||||
SSSLOG(("SSS: found report-uri directive"));
|
||||
foundReportURI = true;
|
||||
@ -624,7 +636,7 @@ ParseSSSHeaders(uint32_t aType,
|
||||
foundUnrecognizedDirective = true;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
return nsISiteSecurityService::Success;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -633,8 +645,12 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains)
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
}
|
||||
SSSLOG(("SSS: processing HPKP header '%s'", aHeader));
|
||||
NS_ENSURE_ARG(aSSLStatus);
|
||||
|
||||
@ -644,15 +660,23 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
||||
bool foundUnrecognizedDirective = false;
|
||||
int64_t maxAge = 0;
|
||||
nsTArray<nsCString> sha256keys;
|
||||
nsresult rv = ParseSSSHeaders(aType, aHeader, foundIncludeSubdomains,
|
||||
foundMaxAge, foundUnrecognizedDirective,
|
||||
maxAge, sha256keys);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
uint32_t sssrv = ParseSSSHeaders(aType, aHeader, foundIncludeSubdomains,
|
||||
foundMaxAge, foundUnrecognizedDirective,
|
||||
maxAge, sha256keys);
|
||||
if (sssrv != nsISiteSecurityService::Success) {
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = sssrv;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// after processing all the directives, make sure we came across max-age
|
||||
// somewhere.
|
||||
if (!foundMaxAge) {
|
||||
SSSLOG(("SSS: did not encounter required max-age directive"));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_NO_MAX_AGE;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -661,7 +685,7 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
||||
// 1. recompute a valid chain (no external ocsp)
|
||||
// 2. use this chain to check if things would have broken!
|
||||
nsAutoCString host;
|
||||
rv = GetHost(aSourceURI, host);
|
||||
nsresult rv = GetHost(aSourceURI, host);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIX509Cert> cert;
|
||||
rv = aSSLStatus->GetServerCert(getter_AddRefs(cert));
|
||||
@ -711,11 +735,14 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
||||
if (!chainMatchesPinset) {
|
||||
// is invalid
|
||||
SSSLOG(("SSS: Pins provided by %s are invalid no match with certList\n", host.get()));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_PINSET_DOES_NOT_MATCH_CHAIN;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// finally we need to ensure that there is a "backup pin" ie. There must be
|
||||
// at least one fingerprint hash that does NOT valiate against the verified
|
||||
// at least one fingerprint hash that does NOT validate against the verified
|
||||
// chain (Section 2.5 of the spec)
|
||||
bool hasBackupPin = false;
|
||||
for (uint32_t i = 0; i < sha256keys.Length(); i++) {
|
||||
@ -733,6 +760,9 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
||||
if (!hasBackupPin) {
|
||||
// is invalid
|
||||
SSSLOG(("SSS: Pins provided by %s are invalid no backupPin\n", host.get()));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_NO_BACKUP_PIN;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -743,7 +773,13 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
||||
host.get(), expireTime, PR_Now() / PR_USEC_PER_MSEC, maxAge));
|
||||
|
||||
rv = SetHPKPState(host.get(), dynamicEntry, aFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
SSSLOG(("SSS: failed to set pins for %s\n", host.get()));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aMaxAge != nullptr) {
|
||||
*aMaxAge = (uint64_t)maxAge;
|
||||
@ -763,8 +799,12 @@ nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
|
||||
const char* aHeader,
|
||||
uint32_t aFlags,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains)
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
}
|
||||
SSSLOG(("SSS: processing HSTS header '%s'", aHeader));
|
||||
|
||||
const uint32_t aType = nsISiteSecurityService::HEADER_HSTS;
|
||||
@ -772,22 +812,38 @@ nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
|
||||
bool foundIncludeSubdomains = false;
|
||||
bool foundUnrecognizedDirective = false;
|
||||
int64_t maxAge = 0;
|
||||
nsTArray<nsCString> unusedSHA256keys; // Requred for sane internal interface
|
||||
nsTArray<nsCString> unusedSHA256keys; // Required for sane internal interface
|
||||
|
||||
nsresult rv = ParseSSSHeaders(aType, aHeader, foundIncludeSubdomains,
|
||||
foundMaxAge, foundUnrecognizedDirective,
|
||||
maxAge, unusedSHA256keys);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
uint32_t sssrv = ParseSSSHeaders(aType, aHeader, foundIncludeSubdomains,
|
||||
foundMaxAge, foundUnrecognizedDirective,
|
||||
maxAge, unusedSHA256keys);
|
||||
if (sssrv != nsISiteSecurityService::Success) {
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = sssrv;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// after processing all the directives, make sure we came across max-age
|
||||
// somewhere.
|
||||
if (!foundMaxAge) {
|
||||
SSSLOG(("SSS: did not encounter required max-age directive"));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_NO_MAX_AGE;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// record the successfully parsed header data.
|
||||
SetHSTSState(aType, aSourceURI, maxAge, foundIncludeSubdomains, aFlags);
|
||||
nsresult rv = SetHSTSState(aType, aSourceURI, maxAge, foundIncludeSubdomains,
|
||||
aFlags);
|
||||
if (NS_FAILED(rv)) {
|
||||
SSSLOG(("SSS: failed to set STS state"));
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aMaxAge != nullptr) {
|
||||
*aMaxAge = (uint64_t)maxAge;
|
||||
|
@ -132,13 +132,15 @@ private:
|
||||
nsresult ProcessHeaderInternal(uint32_t aType, nsIURI* aSourceURI,
|
||||
const char* aHeader, nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags, uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains);
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult);
|
||||
nsresult ProcessSTSHeader(nsIURI* aSourceURI, const char* aHeader,
|
||||
uint32_t flags, uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains);
|
||||
bool* aIncludeSubdomains, uint32_t* aFailureResult);
|
||||
nsresult ProcessPKPHeader(nsIURI* aSourceURI, const char* aHeader,
|
||||
nsISSLStatus* aSSLStatus, uint32_t flags,
|
||||
uint64_t* aMaxAge, bool* aIncludeSubdomains);
|
||||
uint64_t* aMaxAge, bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult);
|
||||
nsresult SetHPKPState(const char* aHost, SiteHPKPState& entry, uint32_t flags);
|
||||
|
||||
const nsSTSPreload *GetPreloadListEntry(const char *aHost);
|
||||
|
@ -44,7 +44,7 @@ TestSuccess(const char* hdr, bool extraTokens,
|
||||
uint64_t maxAge = 0;
|
||||
bool includeSubdomains = false;
|
||||
rv = sss->UnsafeProcessHeader(nsISiteSecurityService::HEADER_HSTS, dummyUri,
|
||||
hdr, 0, &maxAge, &includeSubdomains);
|
||||
hdr, 0, &maxAge, &includeSubdomains, nullptr);
|
||||
EXPECT_SUCCESS(rv, "Failed to process valid header: %s", hdr);
|
||||
|
||||
REQUIRE_EQUAL(maxAge, expectedMaxAge, "Did not correctly parse maxAge");
|
||||
@ -69,7 +69,7 @@ bool TestFailure(const char* hdr,
|
||||
EXPECT_SUCCESS(rv, "Failed to create URI");
|
||||
|
||||
rv = sss->UnsafeProcessHeader(nsISiteSecurityService::HEADER_HSTS, dummyUri,
|
||||
hdr, 0, nullptr, nullptr);
|
||||
hdr, 0, nullptr, nullptr, nullptr);
|
||||
EXPECT_FAILURE(rv, "Parsed invalid header: %s", hdr);
|
||||
passed(hdr);
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user