#590: TLS 1.3 support (consolidated) with locale workaround

This commit is contained in:
Cameron Kaiser 2020-02-17 20:51:23 -08:00
parent 91d1dfb59b
commit fae264c819
24 changed files with 453 additions and 112 deletions

View File

@ -90,6 +90,9 @@ var security = {
case nsISSLStatus.TLS_VERSION_1_2:
retval.version = "TLS 1.2"
break;
case nsISSLStatus.TLS_VERSION_1_3:
retval.version = "TLS 1.3"
break;
}
return retval;

View File

@ -122,6 +122,7 @@ DEFAULT_GMAKE_FLAGS += NSPR_LIB_DIR=$(NSPR_LIB_DIR)
DEFAULT_GMAKE_FLAGS += MOZILLA_CLIENT=1
DEFAULT_GMAKE_FLAGS += NO_MDUPDATE=1
DEFAULT_GMAKE_FLAGS += NSS_ENABLE_ECC=1
DEFAULT_GMAKE_FLAGS += NSS_ENABLE_TLS_1_3=1
ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_1)
DEFAULT_GMAKE_FLAGS += OS_DLLFLAGS='-static-libgcc' NSPR31_LIB_PREFIX=lib
endif

View File

@ -529,7 +529,7 @@ var NetworkHelper = {
* If state == broken:
* - errorMessage: full error message from nsITransportSecurityInfo.
* If state == secure:
* - protocolVersion: one of TLSv1, TLSv1.1, TLSv1.2.
* - protocolVersion: one of TLSv1, TLSv1.1, TLSv1.2, TLSv1.3.
* - cipherSuite: the cipher suite used in this connection.
* - cert: information about certificate used in this connection.
* See parseCertificateInfo for the contents.
@ -712,7 +712,7 @@ var NetworkHelper = {
* @param Number version
* One of nsISSLStatus version constants.
* @return string
* One of TLSv1, TLSv1.1, TLSv1.2 if @param version is valid,
* One of TLSv1, TLSv1.1, TLSv1.2, TLSv1.3 if @param version is valid,
* Unknown otherwise.
*/
formatSecurityProtocol: function NH_formatSecurityProtocol(version) {
@ -723,6 +723,8 @@ var NetworkHelper = {
return "TLSv1.1";
case Ci.nsISSLStatus.TLS_VERSION_1_2:
return "TLSv1.2";
case Ci.nsISSLStatus.TLS_VERSION_1_3:
return "TLSv1.3";
default:
DevToolsUtils.reportException("NetworkHelper.formatSecurityProtocol",
"protocolVersion " + version + " is unknown.");

View File

@ -1116,6 +1116,8 @@ NS_IMETHODIMP nsWebBrowserPersist::OnStatus(
case NS_NET_STATUS_END_FTP_TRANSACTION:
case NS_NET_STATUS_CONNECTING_TO:
case NS_NET_STATUS_CONNECTED_TO:
case NS_NET_STATUS_TLS_HANDSHAKE_STARTING:
case NS_NET_STATUS_TLS_HANDSHAKE_ENDED:
case NS_NET_STATUS_SENDING_TO:
case NS_NET_STATUS_RECEIVING_FROM:
case NS_NET_STATUS_WAITING_FOR:

View File

@ -454,6 +454,15 @@ TransportLayerDtls::SetVerificationDigest(const std::string digest_algorithm,
return NS_OK;
}
// These are the named groups that we will allow.
static const SSLNamedGroup NamedGroupPreferences[] = {
ssl_grp_ec_curve25519,
ssl_grp_ec_secp256r1,
ssl_grp_ec_secp384r1,
ssl_grp_ffdhe_2048,
ssl_grp_ffdhe_3072
};
// TODO: make sure this is called from STS. Otherwise
// we have thread safety issues
bool TransportLayerDtls::Setup() {
@ -588,6 +597,13 @@ bool TransportLayerDtls::Setup() {
return false;
}
rv = SSL_NamedGroupConfig(ssl_fd, NamedGroupPreferences,
mozilla::ArrayLength(NamedGroupPreferences));
if (rv != SECSuccess) {
MOZ_MTLOG(ML_ERROR, "Couldn't set named groups");
return false;
}
// Certificate validation
rv = SSL_AuthCertificateHook(ssl_fd, AuthCertificateHook,
reinterpret_cast<void *>(this));
@ -675,6 +691,7 @@ static const uint32_t EnabledCiphers[] = {
static const uint32_t DisabledCiphers[] = {
// ALL SHA384 ciphers are disabled per bug 1310061.
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
@ -702,22 +719,14 @@ static const uint32_t DisabledCiphers[] = {
TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
TLS_RSA_WITH_SEED_CBC_SHA,
SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_WITH_RC4_128_SHA,
TLS_RSA_WITH_RC4_128_MD5,
TLS_DHE_RSA_WITH_DES_CBC_SHA,
TLS_DHE_DSS_WITH_DES_CBC_SHA,
SSL_RSA_FIPS_WITH_DES_CBC_SHA,
TLS_RSA_WITH_DES_CBC_SHA,
TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,
TLS_RSA_EXPORT_WITH_RC4_40_MD5,
TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
TLS_ECDHE_ECDSA_WITH_NULL_SHA,
TLS_ECDHE_RSA_WITH_NULL_SHA,
TLS_ECDH_ECDSA_WITH_NULL_SHA,

View File

@ -893,13 +893,15 @@ typedef struct
#define ERROR(key, val) {key, #key}
ErrorEntry socketTransportStatuses[] = {
ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)),
ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)),
ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)),
ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)),
ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)),
ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)),
ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)),
ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)),
ERROR(NS_NET_STATUS_TLS_HANDSHAKE_STARTING, FAILURE(12)),
ERROR(NS_NET_STATUS_TLS_HANDSHAKE_ENDED, FAILURE(13)),
ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
};
#undef ERROR

View File

@ -100,6 +100,7 @@ interface nsITLSClientStatus : nsISupports
const short TLS_VERSION_1 = 0x0301;
const short TLS_VERSION_1_1 = 0x0302;
const short TLS_VERSION_1_2 = 0x0303;
const short TLS_VERSION_1_3 = 0x0304;
const short TLS_VERSION_UNKNOWN = -1;
/**

View File

@ -3,10 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
pref("security.tls.version.min", 1);
pref("security.tls.version.max", 3);
pref("security.tls.version.max", 4);
pref("security.tls.version.fallback-limit", 3);
pref("security.tls.insecure_fallback_hosts", "");
pref("security.tls.unrestricted_rc4_fallback", false);
pref("security.tls.enable_0rtt_data", true);
pref("security.ssl.treat_unsafe_negotiation_as_broken", false);
pref("security.ssl.require_safe_negotiation", false);

View File

@ -17,6 +17,8 @@
9=Wrote %1$S
10=Waiting for %1$S…
11=Looked up %1$S…
12=Performing a TLS handshake to %1$S…
13=The TLS handshake finished for %1$S…
27=Beginning FTP transaction…
28=Finished FTP transaction

View File

@ -2025,6 +2025,8 @@ nsFtpState::OnTransportStatus(nsITransport *transport, nsresult status,
case NS_NET_STATUS_RESOLVED_HOST:
case NS_NET_STATUS_CONNECTING_TO:
case NS_NET_STATUS_CONNECTED_TO:
case NS_NET_STATUS_TLS_HANDSHAKE_STARTING:
case NS_NET_STATUS_TLS_HANDSHAKE_ENDED:
break;
default:
return NS_OK;

View File

@ -2240,6 +2240,8 @@ Http2Session::OnTransportStatus(nsITransport* aTransport,
case NS_NET_STATUS_RESOLVED_HOST:
case NS_NET_STATUS_CONNECTING_TO:
case NS_NET_STATUS_CONNECTED_TO:
case NS_NET_STATUS_TLS_HANDSHAKE_STARTING:
case NS_NET_STATUS_TLS_HANDSHAKE_ENDED:
{
Http2Stream *target = mStreamIDHash.Get(1);
nsAHttpTransaction *transaction = target ? target->Transaction() : nullptr;
@ -2306,7 +2308,13 @@ Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader *reader,
if (!stream) {
LOG3(("Http2Session %p could not identify a stream to write; suspending.",
this));
uint32_t availBeforeFlush = mOutputQueueUsed - mOutputQueueSent;
FlushOutputQueue();
uint32_t availAfterFlush = mOutputQueueUsed - mOutputQueueSent;
if (availBeforeFlush != availAfterFlush) {
LOG3(("Http2Session %p ResumeRecv After early flush in ReadSegments", this));
ResumeRecv();
}
SetWriteCallbacks();
return NS_BASE_STREAM_WOULD_BLOCK;
}

View File

@ -204,6 +204,22 @@ public:
virtual void DisableSpdy() { }
virtual void ReuseConnectionOnRestartOK(bool) { }
// Returns true if early-data is possible.
virtual bool Do0RTT() {
return false;
}
// This function will be called when a tls handshake has been finished and
// we know whether early-data that was sent has been accepted or not, e.g.
// do we need to restart a transaction. This will be called only if Do0RTT
// returns true.
// If aRestart parameter is true we need to restart the transaction,
// otherwise the erly-data has been accepted and we can continue the
// transaction.
// The function will return success or failure of the transaction restart.
virtual nsresult Finish0RTT(bool aRestart) {
return NS_ERROR_NOT_IMPLEMENTED;
}
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsAHttpTransaction, NS_AHTTPTRANSACTION_IID)

View File

@ -79,6 +79,9 @@ nsHttpConnection::nsHttpConnection()
, mResponseTimeoutEnabled(false)
, mTCPKeepaliveConfig(kTCPKeepaliveDisabled)
, mForceSendPending(false)
, m0RTTChecked(false)
, mWaitingFor0RTTResponse(false)
, mContentBytesWritten0RTT(0)
{
LOG(("Creating nsHttpConnection @%p\n", this));
@ -96,18 +99,22 @@ nsHttpConnection::~nsHttpConnection()
if (!mEverUsedSpdy) {
LOG(("nsHttpConnection %p performed %d HTTP/1.x transactions\n",
this, mHttp1xTransactionCount));
/*
Telemetry::Accumulate(Telemetry::HTTP_REQUEST_PER_CONN,
mHttp1xTransactionCount);
*/
}
if (mTotalBytesRead) {
uint32_t totalKBRead = static_cast<uint32_t>(mTotalBytesRead >> 10);
LOG(("nsHttpConnection %p read %dkb on connection spdy=%d\n",
this, totalKBRead, mEverUsedSpdy));
/*
Telemetry::Accumulate(mEverUsedSpdy ?
Telemetry::SPDY_KBREAD_PER_CONN :
Telemetry::HTTP_KBREAD_PER_CONN,
totalKBRead);
*/
}
if (mForceSendTimer) {
mForceSendTimer->Cancel();
@ -268,8 +275,12 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
}
bool
nsHttpConnection::EnsureNPNComplete()
nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
uint32_t &aOut0RTTBytesWritten)
{
aOut0RTTWriteHandshakeValue = NS_OK;
aOut0RTTBytesWritten = 0;
// If for some reason the components to check on NPN aren't available,
// this function will just return true to continue on and disable SPDY
@ -294,16 +305,81 @@ nsHttpConnection::EnsureNPNComplete()
goto npnComplete;
}
if (!m0RTTChecked) {
// We reuse m0RTTChecked. We want to send this status only once.
mTransaction->OnTransportStatus(mSocketTransport,
NS_NET_STATUS_TLS_HANDSHAKE_STARTING,
0);
}
ssl = do_QueryInterface(securityInfo, &rv);
if (NS_FAILED(rv))
goto npnComplete;
rv = ssl->GetNegotiatedNPN(negotiatedNPN);
if (!m0RTTChecked && (rv == NS_ERROR_NOT_CONNECTED) &&
!mConnInfo->UsingProxy()) {
// There is no ALPN info (yet!). We need to consider doing 0RTT. We
// will do so if there is ALPN information from a previous session
// (AlpnEarlySelection), we are using HTTP/1, and the request data can
// be safely retried.
m0RTTChecked = true;
nsAutoCString earlyNegotiatedNPN;
nsresult rvEarlyAlpn = ssl->GetAlpnEarlySelection(earlyNegotiatedNPN);
if (NS_FAILED(rvEarlyAlpn)) {
// if ssl->DriveHandshake() has never been called the value
// for AlpnEarlySelection is still not set. So call it here and
// check again.
LOG(("nsHttpConnection::EnsureNPNComplete %p - "
"early selected alpn not available, we will try one more time.",
this));
// Let's do DriveHandshake again.
rv = ssl->DriveHandshake();
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
goto npnComplete;
}
// Check NegotiatedNPN first.
rv = ssl->GetNegotiatedNPN(negotiatedNPN);
if (rv == NS_ERROR_NOT_CONNECTED) {
rvEarlyAlpn = ssl->GetAlpnEarlySelection(earlyNegotiatedNPN);
}
}
if (NS_FAILED(rvEarlyAlpn)) {
LOG(("nsHttpConnection::EnsureNPNComplete %p - "
"early selected alpn not available", this));
} else {
LOG(("nsHttpConnection::EnsureNPNComplete %p -"
"early selected alpn: %s", this, earlyNegotiatedNPN.get()));
uint32_t infoIndex;
const SpdyInformation *info = gHttpHandler->SpdyInfo();
// We are doing 0RTT only with Http/1 right now!
if (NS_FAILED(info->GetNPNIndex(earlyNegotiatedNPN, &infoIndex))) {
// Check if early-data is allowed for this transaction.
if (mTransaction->Do0RTT()) {
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - We "
"can do 0RTT!", this));
mWaitingFor0RTTResponse = true;
}
}
}
}
if (rv == NS_ERROR_NOT_CONNECTED) {
// By writing 0 bytes to the socket the SSL handshake machine is
// pushed forward.
uint32_t count = 0;
rv = mSocketOut->Write("", 0, &count);
if (mWaitingFor0RTTResponse) {
aOut0RTTWriteHandshakeValue = mTransaction->ReadSegments(this,
nsIOService::gDefaultSegmentSize, &aOut0RTTBytesWritten);
if (NS_FAILED(aOut0RTTWriteHandshakeValue) &&
aOut0RTTWriteHandshakeValue != NS_BASE_STREAM_WOULD_BLOCK) {
goto npnComplete;
}
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - written %d "
"bytes during 0RTT", this, aOut0RTTBytesWritten));
mContentBytesWritten0RTT += aOut0RTTBytesWritten;
}
rv = ssl->DriveHandshake();
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
goto npnComplete;
}
@ -316,18 +392,49 @@ nsHttpConnection::EnsureNPNComplete()
this, mConnInfo->HashKey().get(), negotiatedNPN.get(),
mTLSFilter ? " [Double Tunnel]" : ""));
uint32_t infoIndex;
const SpdyInformation *info = gHttpHandler->SpdyInfo();
if (NS_SUCCEEDED(info->GetNPNIndex(negotiatedNPN, &infoIndex))) {
StartSpdy(info->Version[infoIndex]);
bool ealyDataAccepted = false;
if (mWaitingFor0RTTResponse) {
mWaitingFor0RTTResponse = false;
// Check if early data has been accepted.
rv = ssl->GetEarlyDataAccepted(&ealyDataAccepted);
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - early data "
"that was sent during 0RTT %s been accepted.",
this, ealyDataAccepted ? "has" : "has not"));
if (NS_FAILED(rv) ||
NS_FAILED(mTransaction->Finish0RTT(!ealyDataAccepted))) {
mTransaction->Close(NS_ERROR_NET_RESET);
goto npnComplete;
}
}
if (!ealyDataAccepted) {
uint32_t infoIndex;
const SpdyInformation *info = gHttpHandler->SpdyInfo();
if (NS_SUCCEEDED(info->GetNPNIndex(negotiatedNPN, &infoIndex))) {
StartSpdy(info->Version[infoIndex]);
}
} else {
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - %d bytes "
"has been sent during 0RTT.", this, mContentBytesWritten0RTT));
mContentBytesWritten = mContentBytesWritten0RTT;
}
Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy());
//Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy());
}
npnComplete:
LOG(("nsHttpConnection::EnsureNPNComplete setting complete to true"));
mNPNComplete = true;
mTransaction->OnTransportStatus(mSocketTransport,
NS_NET_STATUS_TLS_HANDSHAKE_ENDED,
0);
if (mWaitingFor0RTTResponse) {
mWaitingFor0RTTResponse = false;
if (NS_FAILED(mTransaction->Finish0RTT(true))) {
mTransaction->Close(NS_ERROR_NET_RESET);
}
mContentBytesWritten0RTT = 0;
}
return true;
}
@ -1572,7 +1679,9 @@ nsHttpConnection::OnSocketWritable()
// request differently for http/1, http/2, spdy, etc.. and that is
// negotiated with NPN/ALPN in the SSL handshake.
if (mConnInfo->UsingHttpsProxy() && !EnsureNPNComplete()) {
if (mConnInfo->UsingHttpsProxy() &&
!EnsureNPNComplete(rv, transactionBytes)) {
MOZ_ASSERT(!transactionBytes);
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
} else if (mProxyConnectStream) {
// If we're need an HTTP/1 CONNECT tunnel through a proxy
@ -1581,8 +1690,11 @@ nsHttpConnection::OnSocketWritable()
rv = mProxyConnectStream->ReadSegments(ReadFromStream, this,
nsIOService::gDefaultSegmentSize,
&transactionBytes);
} else if (!EnsureNPNComplete()) {
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
} else if (!EnsureNPNComplete(rv, transactionBytes)) {
if (NS_SUCCEEDED(rv) && !transactionBytes &&
NS_SUCCEEDED(mSocketOutCondition)) {
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
}
} else {
// for non spdy sessions let the connection manager know
@ -1630,7 +1742,7 @@ nsHttpConnection::OnSocketWritable()
} else if (!transactionBytes) {
rv = NS_OK;
if (mTransaction) { // in case the ReadSegments stack called CloseTransaction()
if (mTransaction && !mWaitingFor0RTTResponse) { // in case the ReadSegments stack called CloseTransaction()
//
// at this point we've written out the entire transaction, and now we
// must wait for the server's response. we manufacture a status message

View File

@ -241,7 +241,8 @@ private:
// Makes certain the SSL handshake is complete and NPN negotiation
// has had a chance to happen
bool EnsureNPNComplete();
bool EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
uint32_t &aOut0RTTBytesWritten);
void SetupSSL();
// Start the Spdy transaction handler when NPN indicates spdy/*
@ -350,6 +351,17 @@ private:
uint32_t mTCPKeepaliveConfig;
nsCOMPtr<nsITimer> mTCPKeepaliveTransitionTimer;
// Helper variable for 0RTT handshake;
bool m0RTTChecked; // Possible 0RTT has been
// checked.
bool mWaitingFor0RTTResponse; // We have are
// sending 0RTT
// data and we
// are waiting
// for the end of
// the handsake.
int64_t mContentBytesWritten0RTT;
private:
// For ForceSend()
static void ForceSendIO(nsITimer *aTimer, void *aClosure);

View File

@ -142,6 +142,8 @@ nsHttpTransaction::nsHttpTransaction()
, mAppId(NECKO_NO_APP_ID)
, mIsInBrowser(false)
, mClassOfService(0)
, m0RTTInProgress(false)
, mTransportStatus(NS_OK)
{
LOG(("Creating nsHttpTransaction @%p\n", this));
gHttpHandler->GetMaxPipelineObjectSize(&mMaxPipelineObjectSize);
@ -532,6 +534,50 @@ nsHttpTransaction::OnTransportStatus(nsITransport* transport,
}
}
// A transaction can given to multiple HalfOpen sockets (this is a bug in
// nsHttpConnectionMgr). We are going to fix it here as a work around to be
// able to uplift it.
switch(status) {
case NS_NET_STATUS_RESOLVING_HOST:
if (mTransportStatus != NS_OK) {
LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events "
"from backup transport"));
return;
}
break;
case NS_NET_STATUS_RESOLVED_HOST:
if (mTransportStatus != NS_NET_STATUS_RESOLVING_HOST &&
mTransportStatus != NS_OK) {
LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events "
"from backup transport"));
return;
}
break;
case NS_NET_STATUS_CONNECTING_TO:
if (mTransportStatus != NS_NET_STATUS_RESOLVING_HOST &&
mTransportStatus != NS_NET_STATUS_RESOLVED_HOST &&
mTransportStatus != NS_OK) {
LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events "
"from backup transport"));
return;
}
break;
case NS_NET_STATUS_CONNECTED_TO:
if (mTransportStatus != NS_NET_STATUS_RESOLVING_HOST &&
mTransportStatus != NS_NET_STATUS_RESOLVED_HOST &&
mTransportStatus != NS_NET_STATUS_CONNECTING_TO &&
mTransportStatus != NS_OK) {
LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events "
"from backup transport"));
return;
}
break;
default:
LOG(("nsHttpTransaction::OnSocketStatus - a new event"));
}
mTransportStatus = status;
// If the timing is enabled, and we are not using a persistent connection
// then the requestStart timestamp will be null, so we mark the timestamps
// for domainLookupStart/End and connectStart/End
@ -545,7 +591,9 @@ nsHttpTransaction::OnTransportStatus(nsITransport* transport,
} else if (status == NS_NET_STATUS_CONNECTING_TO) {
SetConnectStart(TimeStamp::Now());
} else if (status == NS_NET_STATUS_CONNECTED_TO) {
SetConnectEnd(TimeStamp::Now());
SetConnectEnd(TimeStamp::Now(), true);
} else if (status == NS_NET_STATUS_TLS_HANDSHAKE_ENDED) {
SetConnectEnd(TimeStamp::Now(), false);
}
}
@ -690,7 +738,7 @@ nsHttpTransaction::ReadSegments(nsAHttpSegmentReader *reader,
return mStatus;
}
if (!mConnected) {
if (!mConnected && !m0RTTInProgress) {
mConnected = true;
mConnection->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
}
@ -1274,6 +1322,8 @@ nsHttpTransaction::Restart()
}
}
mTransportStatus = NS_OK;
return gHttpHandler->InitiateTransaction(this, mPriority);
}
@ -2307,5 +2357,38 @@ nsHttpTransaction::GetNetworkAddresses(NetAddr &self, NetAddr &peer)
peer = mPeerAddr;
}
bool
nsHttpTransaction::Do0RTT()
{
if (mRequestHead->IsSafeMethod() &&
!mConnection->IsProxyConnectInProgress()) {
m0RTTInProgress = true;
}
return m0RTTInProgress;
}
nsresult
nsHttpTransaction::Finish0RTT(bool aRestart)
{
LOG(("nsHttpTransaction::Finish0RTT %p %d\n", this, aRestart));
MOZ_ASSERT(m0RTTInProgress);
m0RTTInProgress = false;
if (aRestart) {
// Reset request headers to be sent again.
nsCOMPtr<nsISeekableStream> seekable =
do_QueryInterface(mRequestStream);
if (seekable) {
seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
} else {
return NS_ERROR_FAILURE;
}
} else if (!mConnected) {
// this is code that was skipped in ::ReadSegments while in 0RTT
mConnected = true;
mConnection->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
}
return NS_OK;
}
} // namespace net
} // namespace mozilla

View File

@ -166,6 +166,8 @@ public:
int64_t GetTransferSize() { return mTransferSize; }
bool Do0RTT() override;
nsresult Finish0RTT(bool aRestart) override;
private:
friend class DeleteHttpTransaction;
virtual ~nsHttpTransaction();
@ -453,6 +455,10 @@ public:
private:
RefPtr<ASpdySession> mTunnelProvider;
bool m0RTTInProgress;
nsresult mTransportStatus;
public:
void GetNetworkAddresses(NetAddr &self, NetAddr &peer);

View File

@ -44,6 +44,22 @@ interface nsISSLSocketControl : nsISupports {
*/
readonly attribute ACString negotiatedNPN;
/* For 0RTT we need to know the alpn protocol selected for the last tls
* session. This function will return a value if applicable or an error
* NS_ERROR_NOT_AVAILABLE.
*/
ACString getAlpnEarlySelection();
/* If 0RTT handshake was applied and some data has been sent, as soon as
* the handshake finishes this attribute will be set to appropriate value.
*/
readonly attribute bool earlyDataAccepted;
/* When 0RTT is performed, PR_Write will not drive the handshake forward.
* It must be forced by calling this function.
*/
void driveHandshake();
/* Determine if a potential SSL connection to hostname:port with
* a desired NPN negotiated protocol of npnProtocol can use the socket
* associated with this object instead of making a new one.
@ -83,6 +99,7 @@ interface nsISSLSocketControl : nsISupports {
const short TLS_VERSION_1 = 0x0301;
const short TLS_VERSION_1_1 = 0x0302;
const short TLS_VERSION_1_2 = 0x0303;
const short TLS_VERSION_1_3 = 0x0304;
const short SSL_VERSION_UNKNOWN = -1;
[infallible] readonly attribute short SSLVersionUsed;

View File

@ -20,6 +20,7 @@ interface nsISSLStatus : nsISupports {
const short TLS_VERSION_1 = 1;
const short TLS_VERSION_1_1 = 2;
const short TLS_VERSION_1_2 = 3;
const short TLS_VERSION_1_3 = 4;
readonly attribute unsigned short protocolVersion;
readonly attribute boolean isDomainMismatch;

View File

@ -891,6 +891,7 @@ PreliminaryHandshakeDone(PRFileDesc* fd)
SSLChannelInfo channelInfo;
if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) == SECSuccess) {
infoObject->SetSSLVersionUsed(channelInfo.protocolVersion);
infoObject->SetEarlyDataAccepted(channelInfo.earlyDataAccepted);
SSLCipherSuiteInfo cipherInfo;
if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
@ -905,7 +906,7 @@ PreliminaryHandshakeDone(PRFileDesc* fd)
status->mHaveCipherSuiteAndProtocol = true;
status->mCipherSuite = channelInfo.cipherSuite;
status->mProtocolVersion = channelInfo.protocolVersion & 0xFF;
infoObject->SetKEAUsed(cipherInfo.keaType);
infoObject->SetKEAUsed(channelInfo.keaType);
infoObject->SetKEAKeyBits(channelInfo.keaKeyBits);
infoObject->SetMACAlgorithmUsed(cipherInfo.macAlgorithm);
}
@ -966,7 +967,7 @@ CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart)
sizeof (cipherInfo)) != SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] failed - "
" KEA %d\n", fd,
static_cast<int32_t>(cipherInfo.keaType)));
static_cast<int32_t>(channelInfo.keaType)));
return SECSuccess;
}
@ -982,10 +983,10 @@ CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart)
}
// See bug 952863 for why ECDHE is allowed, but DHE (and RSA) are not.
if (cipherInfo.keaType != ssl_kea_ecdh) {
if (channelInfo.keaType != ssl_kea_ecdh) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] failed - "
"unsupported KEA %d\n", fd,
static_cast<int32_t>(cipherInfo.keaType)));
static_cast<int32_t>(channelInfo.keaType)));
reasonsForNotFalseStarting |= KEA_NOT_SUPPORTED;
}
@ -1032,6 +1033,7 @@ CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart)
}
#if(0) // TenFourFox issue 334
#error this no longer has correct constants and should not be reenabled
static void
AccumulateNonECCKeySize(Telemetry::ID probe, uint32_t bits)
{
@ -1156,7 +1158,7 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
if (rv == SECSuccess) {
#if(0) // TenFourFox issue 334
// Get the protocol version for telemetry
// 1=tls1, 2=tls1.1, 3=tls1.2
// 1=tls1, 2=tls1.1, 3=tls1.2, 4=tls1.3
unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
MOZ_ASSERT(versionEnum > 0);
Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_VERSION, versionEnum);
@ -1179,16 +1181,16 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
infoObject->IsFullHandshake()
? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL
: Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED,
cipherInfo.keaType);
channelInfo.keaType);
#endif
DebugOnly<int16_t> KEAUsed;
MOZ_ASSERT(NS_SUCCEEDED(infoObject->GetKEAUsed(&KEAUsed)) &&
(KEAUsed == cipherInfo.keaType));
(KEAUsed == channelInfo.keaType));
#if(0)
if (infoObject->IsFullHandshake()) {
switch (cipherInfo.keaType) {
switch (channelInfo.keaType) {
case ssl_kea_rsa:
AccumulateNonECCKeySize(Telemetry::SSL_KEA_RSA_KEY_SIZE_FULL,
channelInfo.keaKeyBits);
@ -1210,7 +1212,7 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
cipherInfo.authAlgorithm);
// RSA key exchange doesn't use a signature for auth.
if (cipherInfo.keaType != ssl_kea_rsa) {
if (channelInfo.keaType != ssl_kea_rsa) {
switch (cipherInfo.authAlgorithm) {
case ssl_auth_rsa:
AccumulateNonECCKeySize(Telemetry::SSL_AUTH_RSA_KEY_SIZE_FULL,
@ -1241,11 +1243,16 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
}
PRBool siteSupportsSafeRenego;
rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn,
&siteSupportsSafeRenego);
MOZ_ASSERT(rv == SECSuccess);
if (rv != SECSuccess) {
siteSupportsSafeRenego = false;
if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_3) {
rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn,
&siteSupportsSafeRenego);
MOZ_ASSERT(rv == SECSuccess);
if (rv != SECSuccess) {
siteSupportsSafeRenego = false;
}
} else {
// TLS 1.3 dropped support for renegotiation.
siteSupportsSafeRenego = true;
}
bool renegotiationUnsafe = !siteSupportsSafeRenego &&
ioLayerHelpers.treatUnsafeNegotiationAsBroken();

View File

@ -646,6 +646,13 @@ static const CipherPref sCipherPrefs[] = {
{ "security.ssl3.dhe_rsa_aes_256_sha",
TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true },
{ "security.tls13.aes_128_gcm_sha256",
TLS_AES_128_GCM_SHA256, true },
{ "security.tls13.chacha20_poly1305_sha256",
TLS_CHACHA20_POLY1305_SHA256, true },
{ "security.tls13.aes_256_gcm_sha384",
TLS_AES_256_GCM_SHA384, true },
{ "security.ssl3.ecdhe_rsa_rc4_128_sha",
TLS_ECDHE_RSA_WITH_RC4_128_SHA, true, true }, // deprecated (RC4)
{ "security.ssl3.ecdhe_ecdsa_rc4_128_sha",
@ -730,6 +737,7 @@ static const bool REQUIRE_SAFE_NEGOTIATION_DEFAULT = false;
static const bool FALSE_START_ENABLED_DEFAULT = true;
static const bool NPN_ENABLED_DEFAULT = true;
static const bool ALPN_ENABLED_DEFAULT = false;
static const bool ENABLED_0RTT_DATA_DEFAULT = false;
static void
ConfigureTLSSessionIdentifiers()
@ -899,7 +907,7 @@ nsNSSComponent::setEnabledTLSVersions()
// keep these values in sync with security-prefs.js
// 1 means TLS 1.0, 2 means TLS 1.1, etc.
static const uint32_t PSM_DEFAULT_MIN_TLS_VERSION = 1;
static const uint32_t PSM_DEFAULT_MAX_TLS_VERSION = 3;
static const uint32_t PSM_DEFAULT_MAX_TLS_VERSION = 4;
uint32_t minFromPrefs = Preferences::GetUint("security.tls.version.min",
PSM_DEFAULT_MIN_TLS_VERSION);
@ -1091,6 +1099,9 @@ nsNSSComponent::InitializeNSS()
SSL_OptionSetDefault(SSL_ENABLE_ALPN,
Preferences::GetBool("security.ssl.enable_alpn",
ALPN_ENABLED_DEFAULT));
SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,
Preferences::GetBool("security.tls.enable_0rtt_data",
ENABLED_0RTT_DATA_DEFAULT));
if (NS_FAILED(InitializeCipherSuite())) {
MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("Unable to initialize cipher suite settings\n"));
@ -1306,6 +1317,10 @@ nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic,
SSL_OptionSetDefault(SSL_ENABLE_ALPN,
Preferences::GetBool("security.ssl.enable_alpn",
ALPN_ENABLED_DEFAULT));
} else if (prefName.EqualsLiteral("security.tls.enable_0rtt_data")) {
SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,
Preferences::GetBool("security.tls.enable_0rtt_data",
ENABLED_0RTT_DATA_DEFAULT));
} else if (prefName.Equals("security.ssl.disable_session_identifiers")) {
ConfigureTLSSessionIdentifiers();
} else if (prefName.EqualsLiteral("security.OCSP.enabled") ||

View File

@ -61,6 +61,8 @@ using namespace mozilla::psm;
namespace {
#define MAX_ALPN_LENGTH 255
void
getSiteKey(const nsACString& hostName, uint16_t port,
/*out*/ nsCSubstring& key)
@ -93,6 +95,7 @@ nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags)
mRememberClientAuthCertificate(false),
mPreliminaryHandshakeDone(false),
mNPNCompleted(false),
mEarlyDataAccepted(false),
mFalseStartCallbackCalled(false),
mFalseStarted(false),
mIsFullHandshake(false),
@ -316,6 +319,71 @@ nsNSSSocketInfo::GetNegotiatedNPN(nsACString& aNegotiatedNPN)
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::GetAlpnEarlySelection(nsACString& aAlpnSelected)
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown() || isPK11LoggedOut()) {
return NS_ERROR_NOT_AVAILABLE;
}
SSLNextProtoState alpnState;
unsigned char chosenAlpn[MAX_ALPN_LENGTH];
unsigned int chosenAlpnLen;
SECStatus rv = SSL_GetNextProto(mFd, &alpnState, chosenAlpn, &chosenAlpnLen,
AssertedCast<unsigned int>(ArrayLength(chosenAlpn)));
if (rv != SECSuccess || alpnState != SSL_NEXT_PROTO_EARLY_VALUE ||
chosenAlpnLen == 0) {
return NS_ERROR_NOT_AVAILABLE;
}
aAlpnSelected.Assign(BitwiseCast<char*, unsigned char*>(chosenAlpn),
chosenAlpnLen);
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::GetEarlyDataAccepted(bool* aAccepted)
{
*aAccepted = mEarlyDataAccepted;
return NS_OK;
}
void
nsNSSSocketInfo::SetEarlyDataAccepted(bool aAccepted)
{
mEarlyDataAccepted = aAccepted;
}
NS_IMETHODIMP
nsNSSSocketInfo::DriveHandshake()
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown() || isPK11LoggedOut()) {
return NS_ERROR_NOT_AVAILABLE;
}
if (!mFd) {
return NS_ERROR_FAILURE;
}
PRErrorCode errorCode = GetErrorCode();
if (errorCode) {
return GetXPCOMFromNSSError(errorCode);
}
SECStatus rv = SSL_ForceHandshake(mFd);
if (rv != SECSuccess) {
errorCode = PR_GetError();
if (errorCode == PR_WOULD_BLOCK_ERROR) {
return NS_BASE_STREAM_WOULD_BLOCK;
}
SetCanceled(errorCode, PlainErrorMessage);
return GetXPCOMFromNSSError(errorCode);
}
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname, bool* _retval)
{
@ -704,7 +772,7 @@ nsSSLIOLayerHelpers::rememberTolerantAtVersion(const nsACString& hostName,
mTLSIntoleranceInfo.Put(key, entry);
}
uint16_t
void
nsSSLIOLayerHelpers::forgetIntolerance(const nsACString& hostName,
int16_t port)
{
@ -713,12 +781,10 @@ nsSSLIOLayerHelpers::forgetIntolerance(const nsACString& hostName,
MutexAutoLock lock(mutex);
uint16_t tolerant = 0;
IntoleranceEntry entry;
if (mTLSIntoleranceInfo.Get(key, &entry)) {
entry.AssertInvariant();
tolerant = entry.tolerant;
entry.intolerant = 0;
entry.intoleranceReason = 0;
if (entry.strongCipherStatus != StrongCiphersWorked) {
@ -728,8 +794,6 @@ nsSSLIOLayerHelpers::forgetIntolerance(const nsACString& hostName,
entry.AssertInvariant();
mTLSIntoleranceInfo.Put(key, entry);
}
return tolerant;
}
bool
@ -753,49 +817,7 @@ nsSSLIOLayerHelpers::rememberIntolerantAtVersion(const nsACString& hostName,
{
if (intolerant <= minVersion || fallbackLimitReached(hostName, intolerant)) {
// We can't fall back any further. Assume that intolerance isn't the issue.
uint32_t tolerant = forgetIntolerance(hostName, port);
// If we know the server is tolerant at the version, we don't have to
// gather the telemetry.
if (intolerant <= tolerant) {
return false;
}
uint32_t fallbackLimitBucket = 0;
// added if the version has reached the min version.
if (intolerant <= minVersion) {
switch (minVersion) {
case SSL_LIBRARY_VERSION_TLS_1_0:
fallbackLimitBucket += 1;
break;
case SSL_LIBRARY_VERSION_TLS_1_1:
fallbackLimitBucket += 2;
break;
case SSL_LIBRARY_VERSION_TLS_1_2:
fallbackLimitBucket += 3;
break;
}
}
// added if the version has reached the fallback limit.
if (intolerant <= mVersionFallbackLimit) {
switch (mVersionFallbackLimit) {
case SSL_LIBRARY_VERSION_TLS_1_0:
fallbackLimitBucket += 4;
break;
case SSL_LIBRARY_VERSION_TLS_1_1:
fallbackLimitBucket += 8;
break;
case SSL_LIBRARY_VERSION_TLS_1_2:
fallbackLimitBucket += 12;
break;
}
}
#if(0)
if (fallbackLimitBucket) {
Telemetry::Accumulate(Telemetry::SSL_FALLBACK_LIMIT_REACHED,
fallbackLimitBucket);
}
#endif
forgetIntolerance(hostName, port);
return false;
}
@ -1047,6 +1069,7 @@ class SSLErrorRunnable : public SyncRunnableBase
namespace {
#if(0)
uint32_t tlsIntoleranceTelemetryBucket(PRErrorCode err)
{
// returns a numeric code for where we track various errors in telemetry
@ -1065,9 +1088,11 @@ uint32_t tlsIntoleranceTelemetryBucket(PRErrorCode err)
case SSL_ERROR_DECODE_ERROR_ALERT: return 14;
case PR_CONNECT_RESET_ERROR: return 16;
case PR_END_OF_FILE_ERROR: return 17;
case SSL_ERROR_INTERNAL_ERROR_ALERT: return 18;
default: return 0;
}
}
#endif
bool
retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo)
@ -1143,12 +1168,13 @@ retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo)
return false;
}
#if(0)
#error doesn't support TLS 1.3
uint32_t reason = tlsIntoleranceTelemetryBucket(err);
if (reason == 0) {
return false;
}
#if(0)
Telemetry::ID pre;
Telemetry::ID post;
switch (range.max) {
@ -2564,8 +2590,11 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
if (range.max < maxEnabledVersion) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%p] nsSSLIOLayerSetOptions: enabling TLS_FALLBACK_SCSV\n", fd));
if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) {
return NS_ERROR_FAILURE;
// Some servers will choke if we send the fallback SCSV with TLS 1.2.
if (range.max < SSL_LIBRARY_VERSION_TLS_1_2) {
if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) {
return NS_ERROR_FAILURE;
}
}
}

View File

@ -52,6 +52,7 @@ public:
const nsNSSShutDownPreventionLock& proofOfLock);
void SetNegotiatedNPN(const char* value, uint32_t length);
void SetEarlyDataAccepted(bool aAccepted);
void SetHandshakeCompleted();
void NoteTimeUntilReady();
@ -139,6 +140,7 @@ private:
nsCString mNegotiatedNPN;
bool mNPNCompleted;
bool mEarlyDataAccepted;
bool mFalseStartCallbackCalled;
bool mFalseStarted;
bool mIsFullHandshake;
@ -216,9 +218,7 @@ public:
PRErrorCode intoleranceReason);
bool rememberStrongCiphersFailed(const nsACString& hostName, int16_t port,
PRErrorCode intoleranceReason);
// returns the known tolerant version
// or 0 if there is no known tolerant version
uint16_t forgetIntolerance(const nsACString& hostname, int16_t port);
void forgetIntolerance(const nsACString& hostname, int16_t port);
void adjustForTLSIntolerance(const nsACString& hostname, int16_t port,
/*in/out*/ SSLVersionRange& range,
/*out*/ StrongCipherStatus& strongCipherStatus);

View File

@ -1090,7 +1090,15 @@ NS_IMETHODIMP nsDocLoader::OnStatus(nsIRequest* aRequest, nsISupports* ctxt,
if (!sbs)
return NS_ERROR_FAILURE;
nsXPIDLString msg;
nsresult rv = sbs->FormatStatusMessage(aStatus, aStatusArg,
/* TenFourFox issue 590. Map NS_NET_STATUS_TLS_HANDSHAKE_STARTING and
NS_NET_STATUS_TLS_HANDSHAKE_ENDED to NS_NET_STATUS_CONNECTED_TO so
that we don't instantly invalidate all our locales. See also
netwerk/locales/en-US/necko.properties XXX */
nsresult rv = sbs->FormatStatusMessage(
(aStatus == NS_NET_STATUS_TLS_HANDSHAKE_STARTING ||
aStatus == NS_NET_STATUS_TLS_HANDSHAKE_ENDED) ?
NS_NET_STATUS_CONNECTED_TO : aStatus,
aStatusArg,
getter_Copies(msg));
if (NS_FAILED(rv))
return rv;

View File

@ -313,13 +313,15 @@
ERROR(NS_NET_STATUS_WRITING, FAILURE(9)),
/* nsISocketTransport */
ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)),
ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)),
ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)),
ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)),
ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)),
ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)),
ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)),
ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)),
ERROR(NS_NET_STATUS_TLS_HANDSHAKE_STARTING, FAILURE(12)),
ERROR(NS_NET_STATUS_TLS_HANDSHAKE_ENDED, FAILURE(13)),
ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
/* nsIInterceptedChannel */
/* Generic error for non-specific failures during service worker interception */