/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Bits in bit mask for SSL_REASONS_FOR_NOT_FALSE_STARTING telemetry probe // These bits are numbered so that the least subtle issues have higher values. // This should make it easier for us to interpret the results. const uint32_t POSSIBLE_VERSION_DOWNGRADE = 4; const uint32_t POSSIBLE_CIPHER_SUITE_DOWNGRADE = 2; const uint32_t KEA_NOT_SUPPORTED = 1;
} // namespace
class OCSPRequest final : public nsIStreamLoaderObserver, public nsIRunnable { public:
OCSPRequest(const nsACString& aiaLocation, const OriginAttributes& originAttributes, const uint8_t (&ocspRequest)[OCSP_REQUEST_MAX_LENGTH],
size_t ocspRequestLength, TimeDuration timeout);
// mMonitor provides the memory barrier protecting these member variables. // What happens is the originating thread creates an OCSPRequest object with // the information necessary to perform an OCSP request. It sends the object // to the main thread and waits on the monitor for the operation to complete. // On the main thread, a channel is set up to perform the request. This gets // dispatched to necko. At the same time, a timeout timer is initialized. If // the necko request completes, the response data is filled out, mNotifiedDone // is set to true, and the monitor is notified. The original thread then wakes // up and continues with the results that have been filled out. If the request // times out, again the response data is filled out, mNotifiedDone is set to // true, and the monitor is notified. The first of these two events wins. That // is, if the timeout timer fires but the request completes shortly after, the // caller will see the request as having timed out. // When the request completes (i.e. OnStreamComplete runs), the timer will be // cancelled. This is how we know the closure in OnTimeout is valid. If the // timer fires before OnStreamComplete runs, it should be safe to not cancel // the request because necko has a strong reference to it.
Monitor mMonitor MOZ_UNANNOTATED; bool mNotifiedDone;
nsCOMPtr<nsIStreamLoader> mLoader; const nsCString mAIALocation; const OriginAttributes mOriginAttributes; const mozilla::Span<constchar> mPOSTData; const TimeDuration mTimeout;
nsCOMPtr<nsITimer> mTimeoutTimer;
TimeStamp mStartTime;
nsresult mResponseResult;
Vector<uint8_t> mResponseBytes;
};
// See bug 1219935. // We should not send OCSP request if the PAC is still loading.
nsCOMPtr<nsIProtocolProxyService> pps =
do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) { return NotifyDone(rv, lock);
}
if (pps->GetIsPACLoading()) { return NotifyDone(NS_ERROR_FAILURE, lock);
}
// Security operations scheduled through normal HTTP channels are given // high priority to accommodate real time OCSP transactions.
nsCOMPtr<nsISupportsPriority> priorityChannel = do_QueryInterface(channel); if (priorityChannel) {
priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
}
// Prevent HTTPS-Only Mode from upgrading the OCSP request.
uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_EXEMPT;
loadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
// allow deprecated HTTP request from SystemPrincipal
loadInfo->SetAllowDeprecatedSystemRequests(true);
// For OCSP requests, only the first party domain and private browsing id // aspects of origin attributes are used. This means that: // a) if first party isolation is enabled, OCSP requests will be isolated // according to the first party domain of the original https request // b) OCSP requests are shared across different containers as long as first // party isolation is not enabled and none of the containers are in private // browsing mode. if (mOriginAttributes != OriginAttributes()) {
OriginAttributes attrs;
attrs.mFirstPartyDomain = mOriginAttributes.mFirstPartyDomain;
attrs.mPrivateBrowsingId = mOriginAttributes.mPrivateBrowsingId;
nsCOMPtr<nsIInputStream> uploadStream;
rv = NS_NewByteInputStream(getter_AddRefs(uploadStream), mPOSTData,
NS_ASSIGNMENT_COPY); if (NS_FAILED(rv)) { return NotifyDone(rv, lock);
}
nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(channel)); if (!uploadChannel) { return NotifyDone(NS_ERROR_FAILURE, lock);
}
rv = uploadChannel->SetUploadStream(uploadStream, OCSP_REQUEST_MIME_TYPE, -1); if (NS_FAILED(rv)) { return NotifyDone(rv, lock);
} // Do not use SPDY or HTTP3 for internal security operations. It could result // in the silent upgrade to ssl, which in turn could require an SSL // operation to fulfill something like an OCSP fetch, which is an // endless loop.
nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(channel); if (!internalChannel) { return NotifyDone(rv, lock);
}
rv = internalChannel->SetAllowSpdy(false); if (NS_FAILED(rv)) { return NotifyDone(rv, lock);
}
rv = internalChannel->SetAllowHttp3(false); if (NS_FAILED(rv)) { return NotifyDone(rv, lock);
}
rv = internalChannel->SetIsOCSP(true); if (NS_FAILED(rv)) { return NotifyDone(rv, lock);
}
nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(channel); if (!hchan) { return NotifyDone(NS_ERROR_FAILURE, lock);
}
rv = hchan->SetAllowSTS(false); if (NS_FAILED(rv)) { return NotifyDone(rv, lock);
}
rv = hchan->SetRequestMethod(OCSP_REQUEST_METHOD); if (NS_FAILED(rv)) { return NotifyDone(rv, lock);
}
// We know the OCSPRequest is still alive because if the request had completed // (i.e. OnStreamComplete ran), the timer would have been cancelled in // NotifyDone.
OCSPRequest* self = static_cast<OCSPRequest*>(closure);
MonitorAutoLock lock(self->mMonitor);
self->mTimeoutTimer = nullptr;
self->NotifyDone(NS_ERROR_NET_TIMEOUT, lock);
}
void PK11PasswordPromptRunnable::RunOnTargetThread() {
MOZ_ASSERT(NS_IsMainThread()); if (!NS_IsMainThread()) { return;
}
// If we've reentered due to the nested event loop implicit in using // nsIPrompt synchronously (or indeed the explicit nested event loop in the // protected authentication case), bail early, cancelling the password // prompt. This will probably cause the operation that resulted in the prompt // to fail, but this is better than littering the screen with a bunch of // password prompts that the user will probably just cancel anyway. if (mRunning) { return;
}
mRunning = true; auto setRunningToFalseOnExit = MakeScopeExit([&]() { mRunning = false; });
nsresult rv;
nsCOMPtr<nsIPrompt> prompt; if (!mIR) {
rv = nsNSSComponent::GetNewPrompter(getter_AddRefs(prompt)); if (NS_FAILED(rv)) { return;
}
} else {
prompt = do_GetInterface(mIR);
MOZ_ASSERT(prompt, "Interface requestor should implement nsIPrompt");
}
if (!prompt) { return;
}
if (PK11_ProtectedAuthenticationPath(mSlot)) {
mResult = ShowProtectedAuthPrompt(mSlot, prompt); return;
}
// Prevent version downgrade attacks from TLS 1.2, and avoid False Start for // TLS 1.3 and later. See Bug 861310 for all the details as to why. if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("CanFalseStartCallback [%p] failed - " "SSL Version must be TLS 1.2, was %x\n",
fd, static_cast<int32_t>(channelInfo.protocolVersion)));
reasonsForNotFalseStarting |= POSSIBLE_VERSION_DOWNGRADE;
}
// See bug 952863 for why ECDHE is allowed, but DHE (and RSA) are not. // Also note that ecdh_hybrid groups are not supported in TLS 1.2 and are out // of scope. if (channelInfo.keaType != ssl_kea_ecdh) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("CanFalseStartCallback [%p] failed - " "unsupported KEA %d\n",
fd, static_cast<int32_t>(channelInfo.keaType)));
reasonsForNotFalseStarting |= KEA_NOT_SUPPORTED;
}
// Prevent downgrade attacks on the symmetric cipher. We do not allow CBC // mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt // design. See bug 1109766 for more details. if (cipherInfo.macAlgorithm != ssl_mac_aead) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("CanFalseStartCallback [%p] failed - non-AEAD cipher used, %d, " "is not supported with False Start.\n",
fd, static_cast<int32_t>(cipherInfo.symCipher)));
reasonsForNotFalseStarting |= POSSIBLE_CIPHER_SUITE_DOWNGRADE;
}
// XXX: An attacker can choose which protocols are advertised in the // NPN extension. TODO(Bug 861311): We should restrict the ability // of an attacker leverage this capability by restricting false start // to the same protocol we previously saw for the server, after the // first successful connection to the server.
// XXX: This attempts to map a bit count to an ECC named curve identifier. In // the vast majority of situations, we only have the Suite B curves available. // In that case, this mapping works fine. If we were to have more curves // available, the mapping would be ambiguous since there could be multiple // named curves for a given size (e.g. secp256k1 vs. secp256r1). We punt on // that for now. See also NSS bug 323674. staticvoid AccumulateECCCurve(Telemetry::HistogramID probe, uint32_t bits) { unsignedint value = bits == 255 ? 29 // Curve25519
: bits == 256 ? 23 // P-256
: bits == 384 ? 24 // P-384
: bits == 521 ? 25 // P-521
: 0; // Unknown
Telemetry::Accumulate(probe, value);
}
staticvoid AccumulateCipherSuite(const SSLChannelInfo& channelInfo) {
uint32_t value; // Note: this list must include every cipher suite it is possible to enable // in nsNSSComponent.cpp (see sCipherPrefs and sDeprecatedTLS1CipherPrefs). switch (channelInfo.cipherSuite) { case TLS_RSA_WITH_3DES_EDE_CBC_SHA: // 0x000A
value = 1; break; case TLS_RSA_WITH_AES_128_CBC_SHA: // 0x002F
value = 2; break; case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: // 0x0033
value = 3; break; case TLS_RSA_WITH_AES_256_CBC_SHA: // 0x0035
value = 4; break; case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: // 0x0039
value = 5; break; case TLS_RSA_WITH_AES_128_GCM_SHA256: // 0x009C
value = 6; break; case TLS_RSA_WITH_AES_256_GCM_SHA384: // 0x009D
value = 7; break; case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: // 0xC009
value = 8; break; case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: // 0xC00A
value = 9; break; case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: // 0xC013
value = 10; break; case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: // 0xC014
value = 11; break; case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: // 0xC02B
value = 12; break; case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: // 0xC02C
value = 13; break; case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: // 0xC02F
value = 14; break; case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: // 0xC030
value = 15; break; case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: // 0xCCA8
value = 16; break; case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: // 0xCCA9
value = 17; break;
// TLS 1.3 cipher suites case TLS_AES_128_GCM_SHA256: // 0x1301
value = 18; break; case TLS_AES_256_GCM_SHA384: // 0x1302
value = 19; break; case TLS_CHACHA20_POLY1305_SHA256: // 0x1303
value = 20; break;
void HandshakeCallback(PRFileDesc* fd, void* client_data) { // Do the bookkeeping that needs to be done after the // server's ServerHello...ServerHelloDone have been processed, but that // doesn't need the handshake to be completed.
PreliminaryHandshakeDone(fd);
SSLVersionRange versions(infoObject->GetTLSVersionRange());
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%p] HandshakeCallback: succeeded using TLS version range " "(0x%04x,0x%04x)\n",
fd, static_cast<unsignedint>(versions.min), static_cast<unsignedint>(versions.max))); // If the handshake completed, then we know the site is TLS tolerant
infoObject->RememberTLSTolerant();
uint32_t state; if (renegotiationUnsafe || deprecatedTlsVer) {
state = nsIWebProgressListener::STATE_IS_BROKEN;
} else {
state = nsIWebProgressListener::STATE_IS_SECURE;
SSLVersionRange defVersion;
rv = SSL_VersionRangeGetDefault(ssl_variant_stream, &defVersion); if (rv == SECSuccess && versions.max >= defVersion.max) { // we know this site no longer requires a version fallback
infoObject->RemoveInsecureTLSFallback();
}
}
// Check if the user has added an override for a certificate error. if (infoObject->HasUserOverriddenCertificateError()) {
state |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
}
infoObject->SetSecurityState(state);
// XXX Bug 883674: We shouldn't be formatting messages here in PSM; instead, // we should set a flag on the channel that higher (UI) level code can check // to log the warning. In particular, these warnings should go to the web // console instead of to the error console. Also, the warning is not // localized. if (!siteSupportsSafeRenego) {
NS_ConvertASCIItoUTF16 msg(infoObject->GetHostName());
msg.AppendLiteral(" : server does not support RFC 5746, see CVE-2009-3555");
nsContentUtils::LogSimpleConsoleError(
msg, "SSL"_ns, infoObject->GetOriginAttributes().IsPrivateBrowsing(), true/* from chrome context */);
}
void SecretCallback(PRFileDesc* fd, PRUint16 epoch, SSLSecretDirection dir,
PK11SymKey* secret, void* arg) { // arg must be set to an NSSSocketControl* in SSL_SecretCallback
MOZ_ASSERT(arg);
NSSSocketControl* infoObject = (NSSSocketControl*)arg; if (epoch == 2 && dir == ssl_secret_read) { // |secret| is the server_handshake_traffic_secret. Set a flag to indicate // that the Server Hello has been processed successfully. We use this when // deciding whether to retry a connection in which an mlkem768x25519 share // was sent.
infoObject->SetHasTls13HandshakeSecrets();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.