Back to index

lightning-sunbird  0.9+nobinonly
nsClientAuthRemember.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Red Hat, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 2008
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Kai Engert <kengert@redhat.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsClientAuthRemember.h"
00041 
00042 #include "nsIX509Cert.h"
00043 #include "nsCRT.h"
00044 #include "nsNetUtil.h"
00045 #include "nsIObserverService.h"
00046 #include "nsNetUtil.h"
00047 #include "nsISupportsPrimitives.h"
00048 #include "nsPromiseFlatString.h"
00049 #include "nsProxiedService.h"
00050 #include "nsStringBuffer.h"
00051 #include "nsAutoLock.h"
00052 #include "nspr.h"
00053 #include "pk11pub.h"
00054 #include "certdb.h"
00055 #include "sechash.h"
00056 #include "ssl.h" // For SSL_ClearSessionCache
00057 
00058 #include "nsNSSCleaner.h"
00059 NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
00060 
00061 NS_IMPL_THREADSAFE_ISUPPORTS2(nsClientAuthRememberService, 
00062                               nsIObserver,
00063                               nsISupportsWeakReference)
00064 
00065 nsClientAuthRememberService::nsClientAuthRememberService()
00066 {
00067   monitor = PR_NewMonitor();
00068 }
00069 
00070 nsClientAuthRememberService::~nsClientAuthRememberService()
00071 {
00072   RemoveAllFromMemory();
00073   if (monitor)
00074     PR_DestroyMonitor(monitor);
00075 }
00076 
00077 nsresult
00078 nsClientAuthRememberService::Init()
00079 {
00080   if (!mSettingsTable.Init())
00081     return NS_ERROR_OUT_OF_MEMORY;
00082 
00083   nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
00084   if (!proxyman)
00085     return NS_ERROR_FAILURE;
00086 
00087   nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1"));
00088   nsCOMPtr<nsIObserverService> proxiedObserver;
00089 
00090   proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ,
00091                               NS_GET_IID(nsIObserverService),
00092                               NS_STATIC_CAST(nsIObserverService*, observerService),
00093                               PROXY_SYNC,
00094                               getter_AddRefs(proxiedObserver));
00095 
00096   if (proxiedObserver) {
00097     proxiedObserver->AddObserver(this, "profile-before-change", PR_TRUE);
00098   }
00099 
00100   return NS_OK;
00101 }
00102 
00103 NS_IMETHODIMP
00104 nsClientAuthRememberService::Observe(nsISupports     *aSubject,
00105                                const char      *aTopic,
00106                                const PRUnichar *aData)
00107 {
00108   // check the topic
00109   if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
00110     // The profile is about to change,
00111     // or is going away because the application is shutting down.
00112 
00113     nsAutoMonitor lock(monitor);
00114     RemoveAllFromMemory();
00115   }
00116 
00117   return NS_OK;
00118 }
00119 
00120 void nsClientAuthRememberService::ClearRememberedDecisions()
00121 {
00122   nsAutoMonitor lock(monitor);
00123   RemoveAllFromMemory();
00124 }
00125 
00126 void
00127 nsClientAuthRememberService::RemoveAllFromMemory()
00128 {
00129   mSettingsTable.Clear();
00130 }
00131 
00132 static nsresult
00133 GetCertFingerprintByOidTag(CERTCertificate* nsscert,
00134                            SECOidTag aOidTag, 
00135                            nsCString &fp)
00136 {
00137   unsigned int hash_len = HASH_ResultLenByOidTag(aOidTag);
00138   nsRefPtr<nsStringBuffer> fingerprint = nsStringBuffer::Alloc(hash_len);
00139   if (!fingerprint)
00140     return NS_ERROR_OUT_OF_MEMORY;
00141 
00142   PK11_HashBuf(aOidTag, (unsigned char*)fingerprint->Data(), 
00143                nsscert->derCert.data, nsscert->derCert.len);
00144 
00145   SECItem fpItem;
00146   fpItem.data = (unsigned char*)fingerprint->Data();
00147   fpItem.len = hash_len;
00148 
00149   fp.Adopt(CERT_Hexify(&fpItem, 1));
00150   return NS_OK;
00151 }
00152 
00153 nsresult
00154 nsClientAuthRememberService::RememberDecision(const nsACString & aHostName, 
00155                                               CERTCertificate *aServerCert, CERTCertificate *aClientCert)
00156 {
00157   // aClientCert == NULL means: remember that user does not want to use a cert
00158   NS_ENSURE_ARG_POINTER(aServerCert);
00159   if (aHostName.IsEmpty())
00160     return NS_ERROR_INVALID_ARG;
00161 
00162   nsCAutoString fpStr;
00163   nsresult rv = GetCertFingerprintByOidTag(aServerCert, SEC_OID_SHA256, fpStr);
00164   if (NS_FAILED(rv))
00165     return rv;
00166 
00167   {
00168     nsAutoMonitor lock(monitor);
00169     if (aClientCert) {
00170       AddEntryToList(aHostName, fpStr, 
00171                      nsDependentCString(aClientCert->nickname));
00172     }
00173     else {
00174       nsCString empty;
00175       AddEntryToList(aHostName, fpStr, empty);
00176     }
00177   }
00178 
00179   return NS_OK;
00180 }
00181 
00182 nsresult
00183 nsClientAuthRememberService::HasRememberedDecision(const nsACString & aHostName, 
00184                                                    CERTCertificate *aCert, 
00185                                                    nsACString & aClientNickname,
00186                                                    PRBool *_retval)
00187 {
00188   if (aHostName.IsEmpty())
00189     return NS_ERROR_INVALID_ARG;
00190 
00191   NS_ENSURE_ARG_POINTER(aCert);
00192   NS_ENSURE_ARG_POINTER(_retval);
00193   *_retval = PR_FALSE;
00194 
00195   nsresult rv;
00196   nsCAutoString fpStr;
00197   rv = GetCertFingerprintByOidTag(aCert, SEC_OID_SHA256, fpStr);
00198   if (NS_FAILED(rv))
00199     return rv;
00200 
00201   nsCAutoString hostCert;
00202   GetHostWithCert(aHostName, fpStr, hostCert);
00203   nsClientAuthRemember settings;
00204 
00205   {
00206     nsAutoMonitor lock(monitor);
00207     nsClientAuthRememberEntry *entry = mSettingsTable.GetEntry(hostCert.get());
00208     if (!entry)
00209       return NS_OK;
00210     settings = entry->mSettings; // copy
00211   }
00212 
00213   aClientNickname = settings.mClientNickname;
00214   *_retval = PR_TRUE;
00215   return NS_OK;
00216 }
00217 
00218 nsresult
00219 nsClientAuthRememberService::AddEntryToList(const nsACString &aHostName, 
00220                                       const nsACString &fingerprint,
00221                                       const nsACString &client_nickname)
00222 
00223 {
00224   nsCAutoString hostCert;
00225   GetHostWithCert(aHostName, fingerprint, hostCert);
00226 
00227   {
00228     nsAutoMonitor lock(monitor);
00229     nsClientAuthRememberEntry *entry = mSettingsTable.PutEntry(hostCert.get());
00230 
00231     if (!entry) {
00232       NS_ERROR("can't insert a null entry!");
00233       return NS_ERROR_OUT_OF_MEMORY;
00234     }
00235 
00236     entry->mHostWithCert = hostCert;
00237 
00238     nsClientAuthRemember &settings = entry->mSettings;
00239     settings.mAsciiHost = aHostName;
00240     settings.mFingerprint = fingerprint;
00241     settings.mClientNickname = client_nickname;
00242   }
00243 
00244   return NS_OK;
00245 }
00246 
00247 void
00248 nsClientAuthRememberService::GetHostWithCert(const nsACString & aHostName, 
00249                                              const nsACString & fingerprint, 
00250                                              nsACString& _retval)
00251 {
00252   nsCAutoString hostCert(aHostName);
00253   hostCert.AppendLiteral(":");
00254   hostCert.Append(fingerprint);
00255   
00256   _retval.Assign(hostCert);
00257 }