summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/nsClientAuthRemember.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'security/manager/ssl/nsClientAuthRemember.cpp')
-rw-r--r--security/manager/ssl/nsClientAuthRemember.cpp213
1 files changed, 213 insertions, 0 deletions
diff --git a/security/manager/ssl/nsClientAuthRemember.cpp b/security/manager/ssl/nsClientAuthRemember.cpp
new file mode 100644
index 000000000..059955901
--- /dev/null
+++ b/security/manager/ssl/nsClientAuthRemember.cpp
@@ -0,0 +1,213 @@
+/* -*- 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();
+ svc->ClearRememberedDecisions();
+
+ svc = PrivateSSLState()->GetClientAuthRememberService();
+ svc->ClearRememberedDecisions();
+}
+
+void
+nsClientAuthRememberService::RemoveAllFromMemory()
+{
+ mSettingsTable.Clear();
+}
+
+nsresult
+nsClientAuthRememberService::RememberDecision(
+ const nsACString& aHostName, const NeckoOriginAttributes& 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 NeckoOriginAttributes& 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 NeckoOriginAttributes& 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 NeckoOriginAttributes& 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);
+}