зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1580138 - Use peer id to isolate token cache r=dragana,keeler
Differential Revision: https://phabricator.services.mozilla.com/D45406 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
1aa0236c9b
Коммит
d2ab74115b
|
@ -23,12 +23,12 @@ static LazyLogModule gSSLTokensCacheLog("SSLTokensCache");
|
|||
|
||||
class ExpirationComparator {
|
||||
public:
|
||||
bool Equals(SSLTokensCache::HostRecord* a,
|
||||
SSLTokensCache::HostRecord* b) const {
|
||||
bool Equals(SSLTokensCache::TokenCacheRecord* a,
|
||||
SSLTokensCache::TokenCacheRecord* b) const {
|
||||
return a->mExpirationTime == b->mExpirationTime;
|
||||
}
|
||||
bool LessThan(SSLTokensCache::HostRecord* a,
|
||||
SSLTokensCache::HostRecord* b) const {
|
||||
bool LessThan(SSLTokensCache::TokenCacheRecord* a,
|
||||
SSLTokensCache::TokenCacheRecord* b) const {
|
||||
return a->mExpirationTime < b->mExpirationTime;
|
||||
}
|
||||
};
|
||||
|
@ -78,12 +78,12 @@ SSLTokensCache::SSLTokensCache() : mCacheSize(0) {
|
|||
SSLTokensCache::~SSLTokensCache() { LOG(("SSLTokensCache::~SSLTokensCache")); }
|
||||
|
||||
// static
|
||||
nsresult SSLTokensCache::Put(const nsACString& aHost, const uint8_t* aToken,
|
||||
nsresult SSLTokensCache::Put(const nsACString& aKey, const uint8_t* aToken,
|
||||
uint32_t aTokenLen) {
|
||||
StaticMutexAutoLock lock(sLock);
|
||||
|
||||
LOG(("SSLTokensCache::Put [host=%s, tokenLen=%u]",
|
||||
PromiseFlatCString(aHost).get(), aTokenLen));
|
||||
LOG(("SSLTokensCache::Put [key=%s, tokenLen=%u]",
|
||||
PromiseFlatCString(aKey).get(), aTokenLen));
|
||||
|
||||
if (!gInstance) {
|
||||
LOG((" service not initialized"));
|
||||
|
@ -101,12 +101,12 @@ nsresult SSLTokensCache::Put(const nsACString& aHost, const uint8_t* aToken,
|
|||
expirationTime = tokenInfo.expirationTime;
|
||||
SSL_DestroyResumptionTokenInfo(&tokenInfo);
|
||||
|
||||
HostRecord* rec = nullptr;
|
||||
TokenCacheRecord* rec = nullptr;
|
||||
|
||||
if (!gInstance->mHostRecs.Get(aHost, &rec)) {
|
||||
rec = new HostRecord();
|
||||
rec->mHost = aHost;
|
||||
gInstance->mHostRecs.Put(aHost, rec);
|
||||
if (!gInstance->mTokenCacheRecords.Get(aKey, &rec)) {
|
||||
rec = new TokenCacheRecord();
|
||||
rec->mKey = aKey;
|
||||
gInstance->mTokenCacheRecords.Put(aKey, rec);
|
||||
gInstance->mExpirationArray.AppendElement(rec);
|
||||
} else {
|
||||
gInstance->mCacheSize -= rec->mToken.Length();
|
||||
|
@ -126,20 +126,20 @@ nsresult SSLTokensCache::Put(const nsACString& aHost, const uint8_t* aToken,
|
|||
}
|
||||
|
||||
// static
|
||||
nsresult SSLTokensCache::Get(const nsACString& aHost,
|
||||
nsresult SSLTokensCache::Get(const nsACString& aKey,
|
||||
nsTArray<uint8_t>& aToken) {
|
||||
StaticMutexAutoLock lock(sLock);
|
||||
|
||||
LOG(("SSLTokensCache::Get [host=%s]", PromiseFlatCString(aHost).get()));
|
||||
LOG(("SSLTokensCache::Get [key=%s]", PromiseFlatCString(aKey).get()));
|
||||
|
||||
if (!gInstance) {
|
||||
LOG((" service not initialized"));
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
HostRecord* rec = nullptr;
|
||||
TokenCacheRecord* rec = nullptr;
|
||||
|
||||
if (gInstance->mHostRecs.Get(aHost, &rec)) {
|
||||
if (gInstance->mTokenCacheRecords.Get(aKey, &rec)) {
|
||||
if (rec->mToken.Length()) {
|
||||
aToken = rec->mToken;
|
||||
return NS_OK;
|
||||
|
@ -151,28 +151,28 @@ nsresult SSLTokensCache::Get(const nsACString& aHost,
|
|||
}
|
||||
|
||||
// static
|
||||
nsresult SSLTokensCache::Remove(const nsACString& aHost) {
|
||||
nsresult SSLTokensCache::Remove(const nsACString& aKey) {
|
||||
StaticMutexAutoLock lock(sLock);
|
||||
|
||||
LOG(("SSLTokensCache::Remove [host=%s]", PromiseFlatCString(aHost).get()));
|
||||
LOG(("SSLTokensCache::Remove [key=%s]", PromiseFlatCString(aKey).get()));
|
||||
|
||||
if (!gInstance) {
|
||||
LOG((" service not initialized"));
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
return gInstance->RemoveLocked(aHost);
|
||||
return gInstance->RemoveLocked(aKey);
|
||||
}
|
||||
|
||||
nsresult SSLTokensCache::RemoveLocked(const nsACString& aHost) {
|
||||
nsresult SSLTokensCache::RemoveLocked(const nsACString& aKey) {
|
||||
sLock.AssertCurrentThreadOwns();
|
||||
|
||||
LOG(("SSLTokensCache::RemoveLocked [host=%s]",
|
||||
PromiseFlatCString(aHost).get()));
|
||||
LOG(("SSLTokensCache::RemoveLocked [key=%s]",
|
||||
PromiseFlatCString(aKey).get()));
|
||||
|
||||
nsAutoPtr<HostRecord> rec;
|
||||
nsAutoPtr<TokenCacheRecord> rec;
|
||||
|
||||
if (!mHostRecs.Remove(aHost, &rec)) {
|
||||
if (!mTokenCacheRecords.Remove(aKey, &rec)) {
|
||||
LOG((" token not found"));
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
@ -206,8 +206,9 @@ void SSLTokensCache::EvictIfNecessary() {
|
|||
mExpirationArray.Sort(ExpirationComparator());
|
||||
|
||||
while (mCacheSize > capacity && mExpirationArray.Length() > 0) {
|
||||
if (NS_FAILED(RemoveLocked(mExpirationArray[0]->mHost))) {
|
||||
MOZ_ASSERT(false, "mExpirationArray and mHostRecs are out of sync!");
|
||||
if (NS_FAILED(RemoveLocked(mExpirationArray[0]->mKey))) {
|
||||
MOZ_ASSERT(false,
|
||||
"mExpirationArray and mTokenCacheRecords are out of sync!");
|
||||
mExpirationArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
@ -222,12 +223,12 @@ size_t SSLTokensCache::SizeOfIncludingThis(
|
|||
mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
size_t n = mallocSizeOf(this);
|
||||
|
||||
n += mHostRecs.ShallowSizeOfExcludingThis(mallocSizeOf);
|
||||
n += mTokenCacheRecords.ShallowSizeOfExcludingThis(mallocSizeOf);
|
||||
n += mExpirationArray.ShallowSizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
for (uint32_t i = 0; i < mExpirationArray.Length(); ++i) {
|
||||
n += mallocSizeOf(mExpirationArray[i]);
|
||||
n += mExpirationArray[i]->mHost.SizeOfExcludingThisIfUnshared(mallocSizeOf);
|
||||
n += mExpirationArray[i]->mKey.SizeOfExcludingThisIfUnshared(mallocSizeOf);
|
||||
n += mExpirationArray[i]->mToken.ShallowSizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,16 +27,16 @@ class SSLTokensCache : public nsIMemoryReporter {
|
|||
|
||||
static bool IsEnabled() { return sEnabled; }
|
||||
|
||||
static nsresult Put(const nsACString& aHost, const uint8_t* aToken,
|
||||
static nsresult Put(const nsACString& aKey, const uint8_t* aToken,
|
||||
uint32_t aTokenLen);
|
||||
static nsresult Get(const nsACString& aHost, nsTArray<uint8_t>& aToken);
|
||||
static nsresult Remove(const nsACString& aHost);
|
||||
static nsresult Get(const nsACString& aKey, nsTArray<uint8_t>& aToken);
|
||||
static nsresult Remove(const nsACString& aKey);
|
||||
|
||||
private:
|
||||
SSLTokensCache();
|
||||
virtual ~SSLTokensCache();
|
||||
|
||||
nsresult RemoveLocked(const nsACString& aHost);
|
||||
nsresult RemoveLocked(const nsACString& aKey);
|
||||
|
||||
void InitPrefs();
|
||||
void EvictIfNecessary();
|
||||
|
@ -53,15 +53,15 @@ class SSLTokensCache : public nsIMemoryReporter {
|
|||
|
||||
uint32_t mCacheSize; // Actual cache size in bytes
|
||||
|
||||
class HostRecord {
|
||||
class TokenCacheRecord {
|
||||
public:
|
||||
nsCString mHost;
|
||||
nsCString mKey;
|
||||
PRUint32 mExpirationTime;
|
||||
nsTArray<uint8_t> mToken;
|
||||
};
|
||||
|
||||
nsClassHashtable<nsCStringHashKey, HostRecord> mHostRecs;
|
||||
nsTArray<HostRecord*> mExpirationArray;
|
||||
nsClassHashtable<nsCStringHashKey, TokenCacheRecord> mTokenCacheRecords;
|
||||
nsTArray<TokenCacheRecord*> mExpirationArray;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -1238,8 +1238,15 @@ SECStatus nsSocketTransport::StoreResumptionToken(
|
|||
return SECFailure;
|
||||
}
|
||||
|
||||
SSLTokensCache::Put(static_cast<nsSocketTransport*>(ctx)->mHost,
|
||||
resumptionToken, len);
|
||||
nsCOMPtr<nsISSLSocketControl> secCtrl =
|
||||
do_QueryInterface(static_cast<nsSocketTransport*>(ctx)->mSecInfo);
|
||||
if (!secCtrl) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
nsAutoCString peerId;
|
||||
secCtrl->GetPeerId(peerId);
|
||||
SSLTokensCache::Put(peerId, resumptionToken, len);
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
@ -1534,19 +1541,22 @@ nsresult nsSocketTransport::InitiateSocket() {
|
|||
}
|
||||
}
|
||||
|
||||
if (usingSSL && SSLTokensCache::IsEnabled()) {
|
||||
nsCOMPtr<nsISSLSocketControl> secCtrl = do_QueryInterface(mSecInfo);
|
||||
if (usingSSL && secCtrl && SSLTokensCache::IsEnabled()) {
|
||||
PRIntn val;
|
||||
// If SSL_NO_CACHE option was set, we must not use the cache
|
||||
if (SSL_OptionGet(fd, SSL_NO_CACHE, &val) == SECSuccess && val == 0) {
|
||||
nsTArray<uint8_t> token;
|
||||
nsresult rv2 = SSLTokensCache::Get(mHost, token);
|
||||
nsAutoCString peerId;
|
||||
secCtrl->GetPeerId(peerId);
|
||||
nsresult rv2 = SSLTokensCache::Get(peerId, token);
|
||||
if (NS_SUCCEEDED(rv2) && token.Length() != 0) {
|
||||
SECStatus srv =
|
||||
SSL_SetResumptionToken(fd, token.Elements(), token.Length());
|
||||
if (srv == SECFailure) {
|
||||
SOCKET_LOG(("Setting token failed with NSS error %d [host=%s]",
|
||||
PORT_GetError(), PromiseFlatCString(mHost).get()));
|
||||
SSLTokensCache::Remove(mHost);
|
||||
SOCKET_LOG(("Setting token failed with NSS error %d [id=%s]",
|
||||
PORT_GetError(), PromiseFlatCString(peerId).get()));
|
||||
SSLTokensCache::Remove(peerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,5 +166,10 @@ interface nsISSLSocketControl : nsISupports {
|
|||
* True iff the connection was resumed using the resumption token.
|
||||
*/
|
||||
readonly attribute boolean resumed;
|
||||
|
||||
/**
|
||||
* The id used to uniquely identify the connection to the peer.
|
||||
*/
|
||||
readonly attribute ACString peerId;
|
||||
};
|
||||
|
||||
|
|
|
@ -887,6 +887,37 @@ nsNSSSocketInfo::SetEsniTxt(const nsACString& aEsniTxt) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSSocketInfo::GetPeerId(nsACString& aResult) {
|
||||
if (!mPeerId.IsEmpty()) {
|
||||
aResult.Assign(mPeerId);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mProviderFlags &
|
||||
nsISocketProvider::ANONYMOUS_CONNECT) { // See bug 466080
|
||||
mPeerId.AppendLiteral("anon:");
|
||||
}
|
||||
if (mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE) {
|
||||
mPeerId.AppendLiteral("private:");
|
||||
}
|
||||
if (mProviderFlags & nsISocketProvider::BE_CONSERVATIVE) {
|
||||
mPeerId.AppendLiteral("beConservative:");
|
||||
}
|
||||
|
||||
mPeerId.AppendPrintf("tlsflags0x%08x:", mProviderTlsFlags);
|
||||
|
||||
mPeerId.Append(GetHostName());
|
||||
mPeerId.Append(':');
|
||||
mPeerId.AppendInt(GetPort());
|
||||
nsAutoCString suffix;
|
||||
GetOriginAttributes().CreateSuffix(suffix);
|
||||
mPeerId.Append(suffix);
|
||||
|
||||
aResult.Assign(mPeerId);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
|
||||
// Dumps a (potentially binary) buffer using SSM_DEBUG. (We could have used
|
||||
// the version in ssltrace.c, but that's specifically tailored to SSLTRACE.)
|
||||
|
@ -2293,30 +2324,13 @@ static nsresult nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
|
|||
|
||||
// Set the Peer ID so that SSL proxy connections work properly and to
|
||||
// separate anonymous and/or private browsing connections.
|
||||
uint32_t flags = infoObject->GetProviderFlags();
|
||||
nsAutoCString peerId;
|
||||
if (flags & nsISocketProvider::ANONYMOUS_CONNECT) { // See bug 466080
|
||||
peerId.AppendLiteral("anon:");
|
||||
}
|
||||
if (flags & nsISocketProvider::NO_PERMANENT_STORAGE) {
|
||||
peerId.AppendLiteral("private:");
|
||||
}
|
||||
if (flags & nsISocketProvider::BE_CONSERVATIVE) {
|
||||
peerId.AppendLiteral("beConservative:");
|
||||
}
|
||||
|
||||
peerId.AppendPrintf("tlsflags0x%08x:", infoObject->GetProviderTlsFlags());
|
||||
|
||||
peerId.Append(host);
|
||||
peerId.Append(':');
|
||||
peerId.AppendInt(port);
|
||||
nsAutoCString suffix;
|
||||
infoObject->GetOriginAttributes().CreateSuffix(suffix);
|
||||
peerId.Append(suffix);
|
||||
infoObject->GetPeerId(peerId);
|
||||
if (SECSuccess != SSL_SetSockPeerID(fd, peerId.get())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t flags = infoObject->GetProviderFlags();
|
||||
if (flags & nsISocketProvider::NO_PERMANENT_STORAGE) {
|
||||
if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_SESSION_TICKETS, false) ||
|
||||
SECSuccess != SSL_OptionSet(fd, SSL_NO_CACHE, true)) {
|
||||
|
|
|
@ -163,6 +163,7 @@ class nsNSSSocketInfo final : public mozilla::psm::TransportSecurityInfo,
|
|||
|
||||
nsCString mNegotiatedNPN;
|
||||
nsCString mEsniTxt;
|
||||
nsCString mPeerId;
|
||||
bool mNPNCompleted;
|
||||
bool mEarlyDataAccepted;
|
||||
bool mDenyClientCert;
|
||||
|
|
Загрузка…
Ссылка в новой задаче