Back to index

lightning-sunbird  0.9+nobinonly
nsCertPicker.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corp..
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s): Kai Engert <kaie@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsCertPicker.h"
00039 #include "nsMemory.h"
00040 #include "nsCOMPtr.h"
00041 #include "nsXPIDLString.h"
00042 #include "nsIServiceManager.h"
00043 #include "nsNSSComponent.h"
00044 #include "nsNSSCertificate.h"
00045 #include "nsReadableUtils.h"
00046 #include "nsNSSCleaner.h"
00047 #include "nsICertPickDialogs.h"
00048 #include "nsNSSShutDown.h"
00049 #include "nsNSSCertHelper.h"
00050 
00051 NSSCleanupAutoPtrClass(CERTCertNicknames, CERT_FreeNicknames)
00052 NSSCleanupAutoPtrClass(CERTCertList, CERT_DestroyCertList)
00053 
00054 #include "cert.h"
00055 
00056 NS_IMPL_ISUPPORTS1(nsCertPicker, nsIUserCertPicker)
00057 
00058 nsCertPicker::nsCertPicker()
00059 {
00060 }
00061 
00062 nsCertPicker::~nsCertPicker()
00063 {
00064 }
00065 
00066 NS_IMETHODIMP nsCertPicker::PickByUsage(nsIInterfaceRequestor *ctx, 
00067                                         const PRUnichar *selectedNickname, 
00068                                         PRInt32 certUsage, 
00069                                         PRBool allowInvalid, 
00070                                         PRBool allowDuplicateNicknames, 
00071                                         PRBool *canceled, 
00072                                         nsIX509Cert **_retval)
00073 {
00074   nsNSSShutDownPreventionLock locker;
00075   PRInt32 selectedIndex = -1;
00076   PRBool selectionFound = PR_FALSE;
00077   PRUnichar **certNicknameList = nsnull;
00078   PRUnichar **certDetailsList = nsnull;
00079   CERTCertListNode* node = nsnull;
00080   nsresult rv = NS_OK;
00081 
00082   {
00083     // Iterate over all certs. This assures that user is logged in to all hardware tokens.
00084     CERTCertList *allcerts = nsnull;
00085     nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
00086     allcerts = PK11_ListCerts(PK11CertListUnique, ctx);
00087     CERT_DestroyCertList(allcerts);
00088   }
00089 
00090   /* find all user certs that are valid and for SSL */
00091   /* note that we are allowing expired certs in this list */
00092 
00093   CERTCertList *certList = 
00094     CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), 
00095                               (SECCertUsage)certUsage,
00096                               !allowDuplicateNicknames,
00097                               !allowInvalid,
00098                               ctx);
00099   CERTCertListCleaner clc(certList);
00100 
00101   if (!certList) {
00102     return NS_ERROR_NOT_AVAILABLE;
00103   }
00104 
00105   CERTCertNicknames *nicknames = getNSSCertNicknamesFromCertList(certList);
00106 
00107   CERTCertNicknamesCleaner cnc(nicknames);
00108 
00109   if (!nicknames) {
00110     return NS_ERROR_NOT_AVAILABLE;
00111   }
00112 
00113   certNicknameList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
00114   certDetailsList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
00115 
00116   if (!certNicknameList || !certDetailsList) {
00117     nsMemory::Free(certNicknameList);
00118     nsMemory::Free(certDetailsList);
00119     return NS_ERROR_OUT_OF_MEMORY;
00120   }
00121 
00122   PRInt32 CertsToUse;
00123 
00124   for (CertsToUse = 0, node = CERT_LIST_HEAD(certList);
00125        !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
00126        node = CERT_LIST_NEXT(node)
00127       )
00128   {
00129     nsNSSCertificate *tempCert = new nsNSSCertificate(node->cert);
00130 
00131     if (tempCert) {
00132 
00133       // XXX we really should be using an nsCOMPtr instead of manually add-refing,
00134       // but nsNSSCertificate does not have a default constructor.
00135 
00136       NS_ADDREF(tempCert);
00137 
00138       nsAutoString i_nickname(NS_ConvertUTF8toUCS2(nicknames->nicknames[CertsToUse]));
00139       nsAutoString nickWithSerial;
00140       nsAutoString details;
00141 
00142       if (!selectionFound) {
00143         if (i_nickname == nsDependentString(selectedNickname)) {
00144           selectedIndex = CertsToUse;
00145           selectionFound = PR_TRUE;
00146         }
00147       }
00148 
00149       if (NS_SUCCEEDED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details))) {
00150         certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial);
00151         certDetailsList[CertsToUse] = ToNewUnicode(details);
00152       }
00153       else {
00154         certNicknameList[CertsToUse] = nsnull;
00155         certDetailsList[CertsToUse] = nsnull;
00156       }
00157 
00158       NS_RELEASE(tempCert);
00159 
00160       ++CertsToUse;
00161     }
00162   }
00163 
00164   if (CertsToUse) {
00165     nsICertPickDialogs *dialogs = nsnull;
00166     rv = getNSSDialogs((void**)&dialogs, 
00167       NS_GET_IID(nsICertPickDialogs), 
00168       NS_CERTPICKDIALOGS_CONTRACTID);
00169 
00170     if (NS_SUCCEEDED(rv)) {
00171       nsPSMUITracker tracker;
00172       if (tracker.isUIForbidden()) {
00173         rv = NS_ERROR_NOT_AVAILABLE;
00174       }
00175       else {
00176         /* Throw up the cert picker dialog and get back the index of the selected cert */
00177         rv = dialogs->PickCertificate(ctx,
00178           (const PRUnichar**)certNicknameList, (const PRUnichar**)certDetailsList,
00179           CertsToUse, &selectedIndex, canceled);
00180       }
00181 
00182       NS_RELEASE(dialogs);
00183     }
00184   }
00185 
00186   PRInt32 i;
00187   for (i = 0; i < CertsToUse; ++i) {
00188     nsMemory::Free(certNicknameList[i]);
00189     nsMemory::Free(certDetailsList[i]);
00190   }
00191   nsMemory::Free(certNicknameList);
00192   nsMemory::Free(certDetailsList);
00193   
00194   if (!CertsToUse) {
00195     return NS_ERROR_NOT_AVAILABLE;
00196   }
00197 
00198   if (NS_SUCCEEDED(rv) && !*canceled) {
00199     for (i = 0, node = CERT_LIST_HEAD(certList);
00200          !CERT_LIST_END(node, certList);
00201          ++i, node = CERT_LIST_NEXT(node)) {
00202 
00203       if (i == selectedIndex) {
00204         nsNSSCertificate *cert = new nsNSSCertificate(node->cert);
00205         if (!cert) {
00206           rv = NS_ERROR_OUT_OF_MEMORY;
00207           break;
00208         }
00209 
00210         nsIX509Cert *x509 = 0;
00211         nsresult rv = cert->QueryInterface(NS_GET_IID(nsIX509Cert), (void**)&x509);
00212         if (NS_FAILED(rv)) {
00213           break;
00214         }
00215 
00216         NS_ADDREF(x509);
00217         *_retval = x509;
00218         NS_RELEASE(cert);
00219         break;
00220       }
00221     }
00222   }
00223 
00224   return rv;
00225 }