Re-add two files added by bug 431819 that didn't need to be backed out for fixing bug 454406.
authorReed Loden <reed@reedloden.com>
Wed, 01 Oct 2008 01:36:49 -0500
changeset 20052 90f5e3562b46b3c8a93d7e873d1a1fe896b75e4a
parent 20051 3331da81af4d2b67512b961d0c43308f023cb58e
child 20053 0f8280132011969743f89895f8da2bd4891a7763
push id2605
push userreed@reedloden.com
push dateWed, 01 Oct 2008 06:36:47 +0000
treeherdermozilla-central@90f5e3562b46 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs431819, 454406
milestone1.9.1b1pre
Re-add two files added by bug 431819 that didn't need to be backed out for fixing bug 454406.
security/manager/ssl/src/nsClientAuthRemember.cpp
security/manager/ssl/src/nsClientAuthRemember.h
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/src/nsClientAuthRemember.cpp
@@ -0,0 +1,257 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kai Engert <kengert@redhat.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsClientAuthRemember.h"
+
+#include "nsIX509Cert.h"
+#include "nsCRT.h"
+#include "nsNetUtil.h"
+#include "nsIObserverService.h"
+#include "nsNetUtil.h"
+#include "nsISupportsPrimitives.h"
+#include "nsPromiseFlatString.h"
+#include "nsProxiedService.h"
+#include "nsStringBuffer.h"
+#include "nsAutoLock.h"
+#include "nspr.h"
+#include "pk11pub.h"
+#include "certdb.h"
+#include "sechash.h"
+#include "ssl.h" // For SSL_ClearSessionCache
+
+#include "nsNSSCleaner.h"
+NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
+
+NS_IMPL_THREADSAFE_ISUPPORTS2(nsClientAuthRememberService, 
+                              nsIObserver,
+                              nsISupportsWeakReference)
+
+nsClientAuthRememberService::nsClientAuthRememberService()
+{
+  monitor = PR_NewMonitor();
+}
+
+nsClientAuthRememberService::~nsClientAuthRememberService()
+{
+  RemoveAllFromMemory();
+  if (monitor)
+    PR_DestroyMonitor(monitor);
+}
+
+nsresult
+nsClientAuthRememberService::Init()
+{
+  if (!mSettingsTable.Init())
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
+  if (!proxyman)
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1"));
+  nsCOMPtr<nsIObserverService> proxiedObserver;
+
+  NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
+                       NS_GET_IID(nsIObserverService),
+                       observerService,
+                       NS_PROXY_SYNC,
+                       getter_AddRefs(proxiedObserver));
+
+  if (proxiedObserver) {
+    proxiedObserver->AddObserver(this, "profile-before-change", PR_TRUE);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsClientAuthRememberService::Observe(nsISupports     *aSubject,
+                               const char      *aTopic,
+                               const PRUnichar *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.
+
+    nsAutoMonitor lock(monitor);
+    RemoveAllFromMemory();
+  }
+
+  return NS_OK;
+}
+
+void nsClientAuthRememberService::ClearRememberedDecisions()
+{
+  nsAutoMonitor lock(monitor);
+  RemoveAllFromMemory();
+}
+
+void
+nsClientAuthRememberService::RemoveAllFromMemory()
+{
+  mSettingsTable.Clear();
+}
+
+static nsresult
+GetCertFingerprintByOidTag(CERTCertificate* nsscert,
+                           SECOidTag aOidTag, 
+                           nsCString &fp)
+{
+  unsigned int hash_len = HASH_ResultLenByOidTag(aOidTag);
+  nsRefPtr<nsStringBuffer> fingerprint = nsStringBuffer::Alloc(hash_len);
+  if (!fingerprint)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  PK11_HashBuf(aOidTag, (unsigned char*)fingerprint->Data(), 
+               nsscert->derCert.data, nsscert->derCert.len);
+
+  SECItem fpItem;
+  fpItem.data = (unsigned char*)fingerprint->Data();
+  fpItem.len = hash_len;
+
+  fp.Adopt(CERT_Hexify(&fpItem, 1));
+  return NS_OK;
+}
+
+nsresult
+nsClientAuthRememberService::RememberDecision(const nsACString & aHostName, 
+                                              CERTCertificate *aServerCert, CERTCertificate *aClientCert)
+{
+  // aClientCert == NULL means: remember that user does not want to use a cert
+  NS_ENSURE_ARG_POINTER(aServerCert);
+  if (aHostName.IsEmpty())
+    return NS_ERROR_INVALID_ARG;
+
+  nsCAutoString fpStr;
+  nsresult rv = GetCertFingerprintByOidTag(aServerCert, SEC_OID_SHA256, fpStr);
+  if (NS_FAILED(rv))
+    return rv;
+
+  {
+    nsAutoMonitor lock(monitor);
+    if (aClientCert) {
+      AddEntryToList(aHostName, fpStr, 
+                     nsDependentCString(aClientCert->nickname));
+    }
+    else {
+      nsCString empty;
+      AddEntryToList(aHostName, fpStr, empty);
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsClientAuthRememberService::HasRememberedDecision(const nsACString & aHostName, 
+                                                   CERTCertificate *aCert, 
+                                                   nsACString & aClientNickname,
+                                                   PRBool *_retval)
+{
+  if (aHostName.IsEmpty())
+    return NS_ERROR_INVALID_ARG;
+
+  NS_ENSURE_ARG_POINTER(aCert);
+  NS_ENSURE_ARG_POINTER(_retval);
+  *_retval = PR_FALSE;
+
+  nsresult rv;
+  nsCAutoString fpStr;
+  rv = GetCertFingerprintByOidTag(aCert, SEC_OID_SHA256, fpStr);
+  if (NS_FAILED(rv))
+    return rv;
+
+  nsCAutoString hostCert;
+  GetHostWithCert(aHostName, fpStr, hostCert);
+  nsClientAuthRemember settings;
+
+  {
+    nsAutoMonitor lock(monitor);
+    nsClientAuthRememberEntry *entry = mSettingsTable.GetEntry(hostCert.get());
+    if (!entry)
+      return NS_OK;
+    settings = entry->mSettings; // copy
+  }
+
+  aClientNickname = settings.mClientNickname;
+  *_retval = PR_TRUE;
+  return NS_OK;
+}
+
+nsresult
+nsClientAuthRememberService::AddEntryToList(const nsACString &aHostName, 
+                                      const nsACString &fingerprint,
+                                      const nsACString &client_nickname)
+
+{
+  nsCAutoString hostCert;
+  GetHostWithCert(aHostName, fingerprint, hostCert);
+
+  {
+    nsAutoMonitor lock(monitor);
+    nsClientAuthRememberEntry *entry = mSettingsTable.PutEntry(hostCert.get());
+
+    if (!entry) {
+      NS_ERROR("can't insert a null entry!");
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    entry->mHostWithCert = hostCert;
+
+    nsClientAuthRemember &settings = entry->mSettings;
+    settings.mAsciiHost = aHostName;
+    settings.mFingerprint = fingerprint;
+    settings.mClientNickname = client_nickname;
+  }
+
+  return NS_OK;
+}
+
+void
+nsClientAuthRememberService::GetHostWithCert(const nsACString & aHostName, 
+                                             const nsACString & fingerprint, 
+                                             nsACString& _retval)
+{
+  nsCAutoString hostCert(aHostName);
+  hostCert.AppendLiteral(":");
+  hostCert.Append(fingerprint);
+  
+  _retval.Assign(hostCert);
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/src/nsClientAuthRemember.h
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kai Engert <kengert@redhat.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __NSCLIENTAUTHREMEMBER_H__
+#define __NSCLIENTAUTHREMEMBER_H__
+
+#include "nsTHashtable.h"
+#include "nsIObserver.h"
+#include "nsIX509Cert.h"
+#include "nsAutoPtr.h"
+#include "nsNSSCertificate.h"
+#include "nsString.h"
+#include "nsWeakReference.h"
+#include "prmon.h"
+
+class nsClientAuthRemember
+{
+public:
+
+  nsClientAuthRemember()
+  {
+  }
+
+  nsClientAuthRemember(const nsClientAuthRemember &other)
+  {
+    this->operator=(other);
+  }
+
+  nsClientAuthRemember &operator=(const nsClientAuthRemember &other)
+  {
+    mAsciiHost = other.mAsciiHost;
+    mFingerprint = other.mFingerprint;
+    mClientNickname = other.mClientNickname;
+    return *this;
+  }
+
+  nsCString mAsciiHost;
+  nsCString mFingerprint;
+  nsCString mClientNickname;
+};
+
+
+// hash entry class
+class nsClientAuthRememberEntry : public PLDHashEntryHdr
+{
+  public:
+    // Hash methods
+    typedef const char* KeyType;
+    typedef const char* KeyTypePointer;
+
+    // do nothing with aHost - we require mHead to be set before we're live!
+    nsClientAuthRememberEntry(KeyTypePointer aHostWithCertUTF8)
+    {
+    }
+
+    nsClientAuthRememberEntry(const nsClientAuthRememberEntry& toCopy)
+    {
+      mSettings = toCopy.mSettings;
+    }
+
+    ~nsClientAuthRememberEntry()
+    {
+    }
+
+    KeyType GetKey() const
+    {
+      return HostWithCertPtr();
+    }
+
+    KeyTypePointer GetKeyPointer() const
+    {
+      return HostWithCertPtr();
+    }
+
+    PRBool KeyEquals(KeyTypePointer aKey) const
+    {
+      return !strcmp(HostWithCertPtr(), aKey);
+    }
+
+    static KeyTypePointer KeyToPointer(KeyType aKey)
+    {
+      return aKey;
+    }
+
+    static PLDHashNumber HashKey(KeyTypePointer aKey)
+    {
+      // PL_DHashStringKey doesn't use the table parameter, so we can safely
+      // pass nsnull
+      return PL_DHashStringKey(nsnull, aKey);
+    }
+
+    enum { ALLOW_MEMMOVE = PR_FALSE };
+
+    // get methods
+    inline const nsCString &HostWithCert() const { return mHostWithCert; }
+
+    inline KeyTypePointer HostWithCertPtr() const
+    {
+      return mHostWithCert.get();
+    }
+
+    nsClientAuthRemember mSettings;
+    nsCString mHostWithCert;
+};
+
+class nsClientAuthRememberService : public nsIObserver,
+                                    public nsSupportsWeakReference
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  nsClientAuthRememberService();
+  ~nsClientAuthRememberService();
+
+  nsresult Init();
+
+  static void GetHostWithCert(const nsACString & aHostName, 
+                              const nsACString & nickname, nsACString& _retval);
+
+  nsresult RememberDecision(const nsACString & aHostName, 
+                            CERTCertificate *aServerCert, CERTCertificate *aClientCert);
+  nsresult HasRememberedDecision(const nsACString & aHostName, 
+                                 CERTCertificate *aCert, nsACString & aClientNickname, PRBool *_retval);
+
+  void ClearRememberedDecisions();
+
+protected:
+    PRMonitor *monitor;
+    nsTHashtable<nsClientAuthRememberEntry> mSettingsTable;
+
+    void RemoveAllFromMemory();
+    nsresult AddEntryToList(const nsACString &host, 
+                            const nsACString &server_fingerprint,
+                            const nsACString &client_nickname);
+};
+
+#endif