зеркало из https://github.com/mozilla/gecko-dev.git
220 строки
5.5 KiB
C++
220 строки
5.5 KiB
C++
/* -*- 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/. */
|
|
|
|
#include "nsClientAuthRemember.h"
|
|
|
|
#include "nsIX509Cert.h"
|
|
#include "mozilla/BasePrincipal.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "nsCRT.h"
|
|
#include "nsNSSCertHelper.h"
|
|
#include "nsIObserverService.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsPromiseFlatString.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsStringBuffer.h"
|
|
#include "cert.h"
|
|
#include "nspr.h"
|
|
#include "pk11pub.h"
|
|
#include "certdb.h"
|
|
#include "sechash.h"
|
|
#include "SharedSSLState.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::psm;
|
|
|
|
NS_IMPL_ISUPPORTS(nsClientAuthRememberService,
|
|
nsIObserver,
|
|
nsISupportsWeakReference)
|
|
|
|
nsClientAuthRememberService::nsClientAuthRememberService()
|
|
: monitor("nsClientAuthRememberService.monitor")
|
|
{
|
|
}
|
|
|
|
nsClientAuthRememberService::~nsClientAuthRememberService()
|
|
{
|
|
RemoveAllFromMemory();
|
|
}
|
|
|
|
nsresult
|
|
nsClientAuthRememberService::Init()
|
|
{
|
|
if (!NS_IsMainThread()) {
|
|
NS_ERROR("nsClientAuthRememberService::Init called off the main thread");
|
|
return NS_ERROR_NOT_SAME_THREAD;
|
|
}
|
|
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
mozilla::services::GetObserverService();
|
|
if (observerService) {
|
|
observerService->AddObserver(this, "profile-before-change", true);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsClientAuthRememberService::Observe(nsISupports* aSubject,
|
|
const char* aTopic,
|
|
const char16_t* aData)
|
|
{
|
|
// check the topic
|
|
if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
|
|
// The profile is about to change,
|
|
// or is going away because the application is shutting down.
|
|
|
|
ReentrantMonitorAutoEnter lock(monitor);
|
|
RemoveAllFromMemory();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsClientAuthRememberService::ClearRememberedDecisions()
|
|
{
|
|
ReentrantMonitorAutoEnter lock(monitor);
|
|
RemoveAllFromMemory();
|
|
}
|
|
|
|
void nsClientAuthRememberService::ClearAllRememberedDecisions()
|
|
{
|
|
RefPtr<nsClientAuthRememberService> svc =
|
|
PublicSSLState()->GetClientAuthRememberService();
|
|
MOZ_ASSERT(svc);
|
|
if (svc) {
|
|
svc->ClearRememberedDecisions();
|
|
}
|
|
|
|
svc = PrivateSSLState()->GetClientAuthRememberService();
|
|
MOZ_ASSERT(svc);
|
|
if (svc) {
|
|
svc->ClearRememberedDecisions();
|
|
}
|
|
}
|
|
|
|
void
|
|
nsClientAuthRememberService::RemoveAllFromMemory()
|
|
{
|
|
mSettingsTable.Clear();
|
|
}
|
|
|
|
nsresult
|
|
nsClientAuthRememberService::RememberDecision(
|
|
const nsACString& aHostName, const OriginAttributes& aOriginAttributes,
|
|
CERTCertificate* aServerCert, CERTCertificate* aClientCert)
|
|
{
|
|
// aClientCert == nullptr means: remember that user does not want to use a cert
|
|
NS_ENSURE_ARG_POINTER(aServerCert);
|
|
if (aHostName.IsEmpty()) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
nsAutoCString fpStr;
|
|
nsresult rv = GetCertFingerprintByOidTag(aServerCert, SEC_OID_SHA256, fpStr);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
{
|
|
ReentrantMonitorAutoEnter lock(monitor);
|
|
if (aClientCert) {
|
|
RefPtr<nsNSSCertificate> pipCert(new nsNSSCertificate(aClientCert));
|
|
nsAutoCString dbkey;
|
|
rv = pipCert->GetDbKey(dbkey);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
AddEntryToList(aHostName, aOriginAttributes, fpStr, dbkey);
|
|
}
|
|
} else {
|
|
nsCString empty;
|
|
AddEntryToList(aHostName, aOriginAttributes, fpStr, empty);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsClientAuthRememberService::HasRememberedDecision(
|
|
const nsACString& aHostName, const OriginAttributes& aOriginAttributes,
|
|
CERTCertificate* aCert, nsACString& aCertDBKey, bool* aRetVal)
|
|
{
|
|
if (aHostName.IsEmpty())
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
NS_ENSURE_ARG_POINTER(aCert);
|
|
NS_ENSURE_ARG_POINTER(aRetVal);
|
|
*aRetVal = false;
|
|
|
|
nsresult rv;
|
|
nsAutoCString fpStr;
|
|
rv = GetCertFingerprintByOidTag(aCert, SEC_OID_SHA256, fpStr);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
nsAutoCString entryKey;
|
|
GetEntryKey(aHostName, aOriginAttributes, fpStr, entryKey);
|
|
nsClientAuthRemember settings;
|
|
|
|
{
|
|
ReentrantMonitorAutoEnter lock(monitor);
|
|
nsClientAuthRememberEntry* entry = mSettingsTable.GetEntry(entryKey.get());
|
|
if (!entry)
|
|
return NS_OK;
|
|
settings = entry->mSettings; // copy
|
|
}
|
|
|
|
aCertDBKey = settings.mDBKey;
|
|
*aRetVal = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsClientAuthRememberService::AddEntryToList(
|
|
const nsACString& aHostName, const OriginAttributes& aOriginAttributes,
|
|
const nsACString& aFingerprint, const nsACString& aDBKey)
|
|
{
|
|
nsAutoCString entryKey;
|
|
GetEntryKey(aHostName, aOriginAttributes, aFingerprint, entryKey);
|
|
|
|
{
|
|
ReentrantMonitorAutoEnter lock(monitor);
|
|
nsClientAuthRememberEntry* entry = mSettingsTable.PutEntry(entryKey.get());
|
|
|
|
if (!entry) {
|
|
NS_ERROR("can't insert a null entry!");
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
entry->mEntryKey = entryKey;
|
|
|
|
nsClientAuthRemember& settings = entry->mSettings;
|
|
settings.mAsciiHost = aHostName;
|
|
settings.mFingerprint = aFingerprint;
|
|
settings.mDBKey = aDBKey;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsClientAuthRememberService::GetEntryKey(
|
|
const nsACString& aHostName,
|
|
const OriginAttributes& aOriginAttributes,
|
|
const nsACString& aFingerprint,
|
|
nsACString& aEntryKey)
|
|
{
|
|
nsAutoCString hostCert(aHostName);
|
|
nsAutoCString suffix;
|
|
aOriginAttributes.CreateSuffix(suffix);
|
|
hostCert.Append(suffix);
|
|
hostCert.Append(':');
|
|
hostCert.Append(aFingerprint);
|
|
|
|
aEntryKey.Assign(hostCert);
|
|
}
|