Back to index

lightning-sunbird  0.9+nobinonly
nsNSSCertificate.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Ian McGreer <mcgreer@netscape.com>
00023  *   Javier Delgadillo <javi@netscape.com>
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 "prmem.h"
00041 #include "prerror.h"
00042 #include "prprf.h"
00043 
00044 #include "nsNSSComponent.h" // for PIPNSS string bundle calls.
00045 #include "nsCOMPtr.h"
00046 #include "nsArray.h"
00047 #include "nsNSSCertificate.h"
00048 #include "nsNSSCertValidity.h"
00049 #include "nsPKCS12Blob.h"
00050 #include "nsPK11TokenDB.h"
00051 #include "nsIX509Cert.h"
00052 #include "nsIX509Cert3.h"
00053 #include "nsISMimeCert.h"
00054 #include "nsNSSASN1Object.h"
00055 #include "nsString.h"
00056 #include "nsXPIDLString.h"
00057 #include "nsReadableUtils.h"
00058 #include "nsILocaleService.h"
00059 #include "nsIURI.h"
00060 #include "nsTime.h"
00061 #include "nsIProxyObjectManager.h"
00062 #include "nsCRT.h"
00063 #include "nsAutoLock.h"
00064 #include "nsUsageArrayHelper.h"
00065 #include "nsICertificateDialogs.h"
00066 #include "nsNSSCertHelper.h"
00067 #include "nsISupportsPrimitives.h"
00068 #include "nsUnicharUtils.h"
00069 #include "nsCertVerificationThread.h"
00070 
00071 #include "nspr.h"
00072 extern "C" {
00073 #include "pk11func.h"
00074 #include "certdb.h"
00075 #include "cert.h"
00076 #include "secerr.h"
00077 #include "nssb64.h"
00078 #include "secasn1.h"
00079 #include "secder.h"
00080 }
00081 #include "ssl.h"
00082 #include "ocsp.h"
00083 #include "plbase64.h"
00084 
00085 #ifdef PR_LOGGING
00086 extern PRLogModuleInfo* gPIPNSSLog;
00087 #endif
00088 
00089 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
00090 
00091 
00092 /* nsNSSCertificate */
00093 
00094 NS_IMPL_THREADSAFE_ISUPPORTS4(nsNSSCertificate, nsIX509Cert,
00095                                                 nsIX509Cert3,
00096                                                 nsIX509Cert18Branch,
00097                                                 nsISMimeCert)
00098 
00099 nsNSSCertificate*
00100 nsNSSCertificate::ConstructFromDER(char *certDER, int derLen)
00101 {
00102   nsNSSShutDownPreventionLock locker;
00103 
00104   if (!certDER || !derLen)
00105     return nsnull;
00106 
00107   CERTCertificate *aCert = CERT_DecodeCertFromPackage(certDER, derLen);
00108   
00109   if (!aCert)
00110     return nsnull;
00111 
00112   if(aCert->dbhandle == nsnull)
00113   {
00114     aCert->dbhandle = CERT_GetDefaultCertDB();
00115   }
00116 
00117   nsNSSCertificate *newObject = new nsNSSCertificate(aCert);
00118   CERT_DestroyCertificate(aCert);
00119   return newObject;
00120 }
00121 
00122 nsNSSCertificate::nsNSSCertificate(CERTCertificate *cert) : 
00123                                            mCert(nsnull),
00124                                            mPermDelete(PR_FALSE),
00125                                            mCertType(nsIX509Cert::UNKNOWN_CERT)
00126 {
00127   nsNSSShutDownPreventionLock locker;
00128   if (isAlreadyShutDown())
00129     return;
00130 
00131   if (cert) 
00132     mCert = CERT_DupCertificate(cert);
00133 }
00134 
00135 nsNSSCertificate::~nsNSSCertificate()
00136 {
00137   nsNSSShutDownPreventionLock locker;
00138   if (isAlreadyShutDown())
00139     return;
00140 
00141   destructorSafeDestroyNSSReference();
00142   shutdown(calledFromObject);
00143 }
00144 
00145 void nsNSSCertificate::virtualDestroyNSSReference()
00146 {
00147   destructorSafeDestroyNSSReference();
00148 }
00149 
00150 void nsNSSCertificate::destructorSafeDestroyNSSReference()
00151 {
00152   if (isAlreadyShutDown())
00153     return;
00154 
00155   if (mPermDelete) {
00156     if (mCertType == nsNSSCertificate::USER_CERT) {
00157       nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
00158       PK11_DeleteTokenCertAndKey(mCert, cxt);
00159     } else if (!PK11_IsReadOnly(mCert->slot)) {
00160       // If the list of built-ins does contain a non-removable
00161       // copy of this certificate, our call will not remove
00162       // the certificate permanently, but rather remove all trust.
00163       SEC_DeletePermCertificate(mCert);
00164     }
00165   }
00166 
00167   if (mCert) {
00168     CERT_DestroyCertificate(mCert);
00169     mCert = nsnull;
00170   }
00171 }
00172 
00173 nsresult
00174 nsNSSCertificate::SetCertType(PRUint32 aCertType)
00175 {
00176   mCertType = aCertType;
00177   return NS_OK;
00178 }
00179 
00180 nsresult
00181 nsNSSCertificate::GetCertType(PRUint32 *aCertType)
00182 {
00183   *aCertType = mCertType;
00184   return NS_OK;
00185 }
00186 
00187 nsresult
00188 nsNSSCertificate::MarkForPermDeletion()
00189 {
00190   nsNSSShutDownPreventionLock locker;
00191   if (isAlreadyShutDown())
00192     return NS_ERROR_NOT_AVAILABLE;
00193 
00194   // make sure user is logged in to the token
00195   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
00196 
00197   if (PK11_NeedLogin(mCert->slot)
00198       && !PK11_NeedUserInit(mCert->slot)
00199       && !PK11_IsInternal(mCert->slot))
00200   {
00201     if (SECSuccess != PK11_Authenticate(mCert->slot, PR_TRUE, ctx))
00202     {
00203       return NS_ERROR_FAILURE;
00204     }
00205   }
00206 
00207   mPermDelete = PR_TRUE;
00208   return NS_OK;
00209 }
00210 
00211 nsresult
00212 nsNSSCertificate::FormatUIStrings(const nsAutoString &nickname, nsAutoString &nickWithSerial, nsAutoString &details)
00213 {
00214   nsresult rv = NS_OK;
00215 
00216   nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv));
00217   
00218   if (NS_FAILED(rv) || !proxyman) {
00219     return NS_ERROR_FAILURE;
00220   }
00221   
00222   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00223 
00224   if (NS_FAILED(rv) || !nssComponent) {
00225     return NS_ERROR_FAILURE;
00226   }
00227   
00228   nsCOMPtr<nsIX509Cert> x509Proxy;
00229   proxyman->GetProxyForObject( NS_UI_THREAD_EVENTQ,
00230                                nsIX509Cert::GetIID(),
00231                                NS_STATIC_CAST(nsIX509Cert*, this),
00232                                PROXY_SYNC | PROXY_ALWAYS,
00233                                getter_AddRefs(x509Proxy));
00234 
00235   if (!x509Proxy) {
00236     rv = NS_ERROR_OUT_OF_MEMORY;
00237   }
00238   else {
00239     rv = NS_OK;
00240 
00241     nsAutoString info;
00242     nsAutoString temp1;
00243 
00244     nickWithSerial.Append(nickname);
00245 
00246     if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedFor", info))) {
00247       details.Append(info);
00248       details.Append(PRUnichar(' '));
00249       if (NS_SUCCEEDED(x509Proxy->GetSubjectName(temp1)) && !temp1.IsEmpty()) {
00250         details.Append(temp1);
00251       }
00252       details.Append(PRUnichar('\n'));
00253     }
00254 
00255     if (NS_SUCCEEDED(x509Proxy->GetSerialNumber(temp1)) && !temp1.IsEmpty()) {
00256       details.AppendLiteral("  ");
00257       if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", info))) {
00258         details.Append(info);
00259         details.AppendLiteral(": ");
00260       }
00261       details.Append(temp1);
00262 
00263       nickWithSerial.AppendLiteral(" [");
00264       nickWithSerial.Append(temp1);
00265       nickWithSerial.Append(PRUnichar(']'));
00266 
00267       details.Append(PRUnichar('\n'));
00268     }
00269 
00270 
00271     {
00272       nsCOMPtr<nsIX509CertValidity> validity;
00273       nsCOMPtr<nsIX509CertValidity> originalValidity;
00274       rv = x509Proxy->GetValidity(getter_AddRefs(originalValidity));
00275       if (NS_SUCCEEDED(rv) && originalValidity) {
00276         proxyman->GetProxyForObject( NS_UI_THREAD_EVENTQ,
00277                                      nsIX509CertValidity::GetIID(),
00278                                      originalValidity,
00279                                      PROXY_SYNC | PROXY_ALWAYS,
00280                                      getter_AddRefs(validity));
00281       }
00282 
00283       if (validity) {
00284         details.AppendLiteral("  ");
00285         if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoValid", info))) {
00286           details.Append(info);
00287         }
00288 
00289         if (NS_SUCCEEDED(validity->GetNotBeforeLocalTime(temp1)) && !temp1.IsEmpty()) {
00290           details.Append(PRUnichar(' '));
00291           if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoFrom", info))) {
00292             details.Append(info);
00293             details.Append(PRUnichar(' '));
00294           }
00295           details.Append(temp1);
00296         }
00297 
00298         if (NS_SUCCEEDED(validity->GetNotAfterLocalTime(temp1)) && !temp1.IsEmpty()) {
00299           details.Append(PRUnichar(' '));
00300           if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoTo", info))) {
00301             details.Append(info);
00302             details.Append(PRUnichar(' '));
00303           }
00304           details.Append(temp1);
00305         }
00306 
00307         details.Append(PRUnichar('\n'));
00308       }
00309     }
00310 
00311     PRUint32 tempInt = 0;
00312     if (NS_SUCCEEDED(x509Proxy->GetUsagesString(PR_FALSE, &tempInt, temp1)) && !temp1.IsEmpty()) {
00313       details.AppendLiteral("  ");
00314       if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoPurposes", info))) {
00315         details.Append(info);
00316         details.AppendLiteral(": ");
00317       }
00318       details.Append(temp1);
00319       details.Append(PRUnichar('\n'));
00320     }
00321 
00322     if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedBy", info))) {
00323       details.Append(info);
00324       details.Append(PRUnichar(' '));
00325 
00326       if (NS_SUCCEEDED(x509Proxy->GetIssuerName(temp1)) && !temp1.IsEmpty()) {
00327         details.Append(temp1);
00328       }
00329 
00330       details.Append(PRUnichar('\n'));
00331     }
00332 
00333     if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoStoredIn", info))) {
00334       details.Append(info);
00335       details.Append(PRUnichar(' '));
00336 
00337       if (NS_SUCCEEDED(x509Proxy->GetTokenName(temp1)) && !temp1.IsEmpty()) {
00338         details.Append(temp1);
00339       }
00340     }
00341 
00342     /*
00343       the above produces output the following output:
00344 
00345       Issued to: $subjectName
00346         Serial number: $serialNumber
00347         Valid from: $starting_date to $expiration_date
00348         Purposes: $purposes
00349       Issued by: $issuerName
00350       Stored in: $token
00351     */
00352   }
00353   
00354   return rv;
00355 }
00356 
00357 
00358 /* readonly attribute string dbKey; */
00359 NS_IMETHODIMP 
00360 nsNSSCertificate::GetDbKey(char * *aDbKey)
00361 {
00362   nsNSSShutDownPreventionLock locker;
00363   if (isAlreadyShutDown())
00364     return NS_ERROR_NOT_AVAILABLE;
00365 
00366   SECItem key;
00367 
00368   NS_ENSURE_ARG(aDbKey);
00369   *aDbKey = nsnull;
00370   key.len = NS_NSS_LONG*4+mCert->serialNumber.len+mCert->derIssuer.len;
00371   key.data = (unsigned char *)nsMemory::Alloc(key.len);
00372   if (!key.data)
00373     return NS_ERROR_OUT_OF_MEMORY;
00374   NS_NSS_PUT_LONG(0,key.data); // later put moduleID
00375   NS_NSS_PUT_LONG(0,&key.data[NS_NSS_LONG]); // later put slotID
00376   NS_NSS_PUT_LONG(mCert->serialNumber.len,&key.data[NS_NSS_LONG*2]);
00377   NS_NSS_PUT_LONG(mCert->derIssuer.len,&key.data[NS_NSS_LONG*3]);
00378   memcpy(&key.data[NS_NSS_LONG*4], mCert->serialNumber.data,
00379          mCert->serialNumber.len);
00380   memcpy(&key.data[NS_NSS_LONG*4+mCert->serialNumber.len],
00381          mCert->derIssuer.data, mCert->derIssuer.len);
00382   
00383   *aDbKey = NSSBase64_EncodeItem(nsnull, nsnull, 0, &key);
00384   nsMemory::Free(key.data); // SECItem is a 'c' type without a destrutor
00385   return (*aDbKey) ? NS_OK : NS_ERROR_FAILURE;
00386 }
00387 
00388 /* readonly attribute string windowTitle; */
00389 NS_IMETHODIMP 
00390 nsNSSCertificate::GetWindowTitle(char * *aWindowTitle)
00391 {
00392   nsNSSShutDownPreventionLock locker;
00393   if (isAlreadyShutDown())
00394     return NS_ERROR_NOT_AVAILABLE;
00395 
00396   NS_ENSURE_ARG(aWindowTitle);
00397   if (mCert) {
00398     if (mCert->nickname) {
00399       *aWindowTitle = PL_strdup(mCert->nickname);
00400     } else {
00401       *aWindowTitle = CERT_GetCommonName(&mCert->subject);
00402       if (!*aWindowTitle) {
00403         *aWindowTitle = PL_strdup(mCert->subjectName);
00404       }
00405     }
00406   } else {
00407     NS_ASSERTION(0,"Somehow got nsnull for mCertificate in nsNSSCertificate.");
00408     *aWindowTitle = nsnull;
00409   }
00410   return NS_OK;
00411 }
00412 
00413 NS_IMETHODIMP
00414 nsNSSCertificate::GetNickname(nsAString &aNickname)
00415 {
00416   nsNSSShutDownPreventionLock locker;
00417   if (isAlreadyShutDown())
00418     return NS_ERROR_NOT_AVAILABLE;
00419 
00420   if (mCert->nickname) {
00421     CopyUTF8toUTF16(mCert->nickname, aNickname);
00422   } else {
00423     nsresult rv;
00424     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00425     if (NS_FAILED(rv) || !nssComponent) {
00426       return NS_ERROR_FAILURE;
00427     }
00428     nssComponent->GetPIPNSSBundleString("CertNoNickname", aNickname);
00429   }
00430   return NS_OK;
00431 }
00432 
00433 NS_IMETHODIMP
00434 nsNSSCertificate::GetEmailAddress(nsAString &aEmailAddress)
00435 {
00436   nsNSSShutDownPreventionLock locker;
00437   if (isAlreadyShutDown())
00438     return NS_ERROR_NOT_AVAILABLE;
00439 
00440   if (mCert->emailAddr) {
00441     CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress);
00442   } else {
00443     nsresult rv;
00444     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00445     if (NS_FAILED(rv) || !nssComponent) {
00446       return NS_ERROR_FAILURE;
00447     }
00448     nssComponent->GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
00449   }
00450   return NS_OK;
00451 }
00452 
00453 NS_IMETHODIMP
00454 nsNSSCertificate::GetEmailAddresses(PRUint32 *aLength, PRUnichar*** aAddresses)
00455 {
00456   nsNSSShutDownPreventionLock locker;
00457   if (isAlreadyShutDown())
00458     return NS_ERROR_NOT_AVAILABLE;
00459 
00460   NS_ENSURE_ARG(aLength);
00461   NS_ENSURE_ARG(aAddresses);
00462 
00463   *aLength = 0;
00464 
00465   const char *aAddr;
00466   for (aAddr = CERT_GetFirstEmailAddress(mCert)
00467        ;
00468        aAddr
00469        ;
00470        aAddr = CERT_GetNextEmailAddress(mCert, aAddr))
00471   {
00472     ++(*aLength);
00473   }
00474 
00475   *aAddresses = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * (*aLength));
00476   if (!*aAddresses)
00477     return NS_ERROR_OUT_OF_MEMORY;
00478 
00479   PRUint32 iAddr;
00480   for (aAddr = CERT_GetFirstEmailAddress(mCert), iAddr = 0
00481        ;
00482        aAddr
00483        ;
00484        aAddr = CERT_GetNextEmailAddress(mCert, aAddr), ++iAddr)
00485   {
00486     (*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUCS2(aAddr));
00487   }
00488 
00489   return NS_OK;
00490 }
00491 
00492 NS_IMETHODIMP
00493 nsNSSCertificate::ContainsEmailAddress(const nsAString &aEmailAddress, PRBool *result)
00494 {
00495   nsNSSShutDownPreventionLock locker;
00496   if (isAlreadyShutDown())
00497     return NS_ERROR_NOT_AVAILABLE;
00498 
00499   NS_ENSURE_ARG(result);
00500   *result = PR_FALSE;
00501 
00502   const char *aAddr = nsnull;
00503   for (aAddr = CERT_GetFirstEmailAddress(mCert)
00504        ;
00505        aAddr
00506        ;
00507        aAddr = CERT_GetNextEmailAddress(mCert, aAddr))
00508   {
00509     NS_ConvertUTF8toUCS2 certAddr(aAddr);
00510     ToLowerCase(certAddr);
00511 
00512     nsAutoString testAddr(aEmailAddress);
00513     ToLowerCase(testAddr);
00514     
00515     if (certAddr == testAddr)
00516     {
00517       *result = PR_TRUE;
00518       break;
00519     }
00520 
00521   }
00522   
00523   return NS_OK;
00524 }
00525 
00526 NS_IMETHODIMP
00527 nsNSSCertificate::GetCommonName(nsAString &aCommonName)
00528 {
00529   nsNSSShutDownPreventionLock locker;
00530   if (isAlreadyShutDown())
00531     return NS_ERROR_NOT_AVAILABLE;
00532 
00533   aCommonName.Truncate();
00534   if (mCert) {
00535     char *commonName = CERT_GetCommonName(&mCert->subject);
00536     if (commonName) {
00537       aCommonName = NS_ConvertUTF8toUCS2(commonName);
00538       PORT_Free(commonName);
00539     } /*else {
00540       *aCommonName = ToNewUnicode(NS_LITERAL_STRING("<not set>")), 
00541     }*/
00542   }
00543   return NS_OK;
00544 }
00545 
00546 NS_IMETHODIMP
00547 nsNSSCertificate::GetOrganization(nsAString &aOrganization)
00548 {
00549   nsNSSShutDownPreventionLock locker;
00550   if (isAlreadyShutDown())
00551     return NS_ERROR_NOT_AVAILABLE;
00552 
00553   aOrganization.Truncate();
00554   if (mCert) {
00555     char *organization = CERT_GetOrgName(&mCert->subject);
00556     if (organization) {
00557       aOrganization = NS_ConvertUTF8toUCS2(organization);
00558       PORT_Free(organization);
00559     } /*else {
00560       *aOrganization = ToNewUnicode(NS_LITERAL_STRING("<not set>")), 
00561     }*/
00562   }
00563   return NS_OK;
00564 }
00565 
00566 NS_IMETHODIMP
00567 nsNSSCertificate::GetIssuerCommonName(nsAString &aCommonName)
00568 {
00569   nsNSSShutDownPreventionLock locker;
00570   if (isAlreadyShutDown())
00571     return NS_ERROR_NOT_AVAILABLE;
00572 
00573   aCommonName.Truncate();
00574   if (mCert) {
00575     char *commonName = CERT_GetCommonName(&mCert->issuer);
00576     if (commonName) {
00577       aCommonName = NS_ConvertUTF8toUCS2(commonName);
00578       PORT_Free(commonName);
00579     }
00580   }
00581   return NS_OK;
00582 }
00583 
00584 NS_IMETHODIMP
00585 nsNSSCertificate::GetIssuerOrganization(nsAString &aOrganization)
00586 {
00587   nsNSSShutDownPreventionLock locker;
00588   if (isAlreadyShutDown())
00589     return NS_ERROR_NOT_AVAILABLE;
00590 
00591   aOrganization.Truncate();
00592   if (mCert) {
00593     char *organization = CERT_GetOrgName(&mCert->issuer);
00594     if (organization) {
00595       aOrganization = NS_ConvertUTF8toUCS2(organization);
00596       PORT_Free(organization);
00597     }
00598   }
00599   return NS_OK;
00600 }
00601 
00602 NS_IMETHODIMP
00603 nsNSSCertificate::GetIssuerOrganizationUnit(nsAString &aOrganizationUnit)
00604 {
00605   nsNSSShutDownPreventionLock locker;
00606   if (isAlreadyShutDown())
00607     return NS_ERROR_NOT_AVAILABLE;
00608 
00609   aOrganizationUnit.Truncate();
00610   if (mCert) {
00611     char *organizationUnit = CERT_GetOrgUnitName(&mCert->issuer);
00612     if (organizationUnit) {
00613       aOrganizationUnit = NS_ConvertUTF8toUCS2(organizationUnit);
00614       PORT_Free(organizationUnit);
00615     }
00616   }
00617   return NS_OK;
00618 }
00619 
00620 /* readonly attribute nsIX509Cert issuer; */
00621 NS_IMETHODIMP 
00622 nsNSSCertificate::GetIssuer(nsIX509Cert * *aIssuer)
00623 {
00624   nsNSSShutDownPreventionLock locker;
00625   if (isAlreadyShutDown())
00626     return NS_ERROR_NOT_AVAILABLE;
00627 
00628   NS_ENSURE_ARG(aIssuer);
00629   *aIssuer = nsnull;
00630   CERTCertificate *issuer;
00631   issuer = CERT_FindCertIssuer(mCert, PR_Now(), certUsageSSLClient);
00632   if (issuer) {
00633     nsCOMPtr<nsIX509Cert> cert = new nsNSSCertificate(issuer);
00634     *aIssuer = cert;
00635     NS_ADDREF(*aIssuer);
00636     CERT_DestroyCertificate(issuer);
00637   }
00638   return NS_OK;
00639 }
00640 
00641 NS_IMETHODIMP
00642 nsNSSCertificate::GetOrganizationalUnit(nsAString &aOrganizationalUnit)
00643 {
00644   nsNSSShutDownPreventionLock locker;
00645   if (isAlreadyShutDown())
00646     return NS_ERROR_NOT_AVAILABLE;
00647 
00648   aOrganizationalUnit.Truncate();
00649   if (mCert) {
00650     char *orgunit = CERT_GetOrgUnitName(&mCert->subject);
00651     if (orgunit) {
00652       aOrganizationalUnit = NS_ConvertUTF8toUCS2(orgunit);
00653       PORT_Free(orgunit);
00654     } /*else {
00655       *aOrganizationalUnit = ToNewUnicode(NS_LITERAL_STRING("<not set>")), 
00656     }*/
00657   }
00658   return NS_OK;
00659 }
00660 
00661 /* 
00662  * nsIEnumerator getChain(); 
00663  */
00664 NS_IMETHODIMP
00665 nsNSSCertificate::GetChain(nsIArray **_rvChain)
00666 {
00667   nsNSSShutDownPreventionLock locker;
00668   if (isAlreadyShutDown())
00669     return NS_ERROR_NOT_AVAILABLE;
00670 
00671   NS_ENSURE_ARG(_rvChain);
00672   nsresult rv;
00673   /* Get the cert chain from NSS */
00674   CERTCertList *nssChain = NULL;
00675   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting chain for \"%s\"\n", mCert->nickname));
00676   // XXX This function is buggy - if it can't find the issuer, it crashes
00677   //     on a null pointer.  Will have to wait until it is fixed in NSS.
00678 #ifdef NSS_CHAIN_BUG_FIXED
00679   nssChain = CERT_GetCertChainFromCert(mCert, PR_Now(), certUsageSSLClient);
00680   if (!nssChain)
00681     return NS_ERROR_FAILURE;
00682   /* enumerate the chain for scripting purposes */
00683   nsCOMPtr<nsIMutableArray> array;
00684   rv = NS_NewArray(getter_AddRefs(array));
00685   if (NS_FAILED(rv)) { 
00686     goto done; 
00687   }
00688   for (node = CERT_LIST_HEAD(nssChain);
00689        !CERT_LIST_END(node, nssChain);
00690        node = CERT_LIST_NEXT(node)) {
00691     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("adding %s to chain\n", node->cert->nickname));
00692     nsCOMPtr<nsIX509Cert> cert = new nsNSSCertificate(node->cert);
00693     array->AppendElement(cert, PR_FALSE);
00694   }
00695 #else // workaround here
00696   CERTCertificate *cert = nsnull;
00697   /* enumerate the chain for scripting purposes */
00698   nsCOMPtr<nsIMutableArray> array;
00699   rv = NS_NewArray(getter_AddRefs(array));
00700   if (NS_FAILED(rv)) { 
00701     goto done; 
00702   }
00703   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting chain for \"%s\"\n", mCert->nickname));
00704   cert = CERT_DupCertificate(mCert);
00705   while (cert) {
00706     nsCOMPtr<nsIX509Cert> pipCert = new nsNSSCertificate(cert);
00707     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("adding %s to chain\n", cert->nickname));
00708     array->AppendElement(pipCert, PR_FALSE);
00709     PRBool wantToBreak = PR_FALSE;
00710     CERTCertificate *next_cert = nsnull;
00711     if (SECITEM_CompareItem(&cert->derIssuer, &cert->derSubject) == SECEqual) {
00712       wantToBreak = PR_TRUE;
00713     }
00714     else {
00715       next_cert = CERT_FindCertIssuer(cert, PR_Now(), certUsageSSLClient);
00716     }
00717     CERT_DestroyCertificate(cert);
00718     if (wantToBreak) {
00719       break;
00720     }
00721     cert = next_cert;
00722   }
00723 #endif // NSS_CHAIN_BUG_FIXED
00724   *_rvChain = array;
00725   NS_IF_ADDREF(*_rvChain);
00726   rv = NS_OK;
00727 done:
00728   if (nssChain)
00729     CERT_DestroyCertList(nssChain);
00730   return rv;
00731 }
00732 
00733 NS_IMETHODIMP
00734 nsNSSCertificate::GetSubjectName(nsAString &_subjectName)
00735 {
00736   nsNSSShutDownPreventionLock locker;
00737   if (isAlreadyShutDown())
00738     return NS_ERROR_NOT_AVAILABLE;
00739 
00740   _subjectName.Truncate();
00741   if (mCert->subjectName) {
00742     _subjectName = NS_ConvertUTF8toUCS2(mCert->subjectName);
00743     return NS_OK;
00744   }
00745   return NS_ERROR_FAILURE;
00746 }
00747 
00748 NS_IMETHODIMP
00749 nsNSSCertificate::GetIssuerName(nsAString &_issuerName)
00750 {
00751   nsNSSShutDownPreventionLock locker;
00752   if (isAlreadyShutDown())
00753     return NS_ERROR_NOT_AVAILABLE;
00754 
00755   _issuerName.Truncate();
00756   if (mCert->issuerName) {
00757     _issuerName = NS_ConvertUTF8toUCS2(mCert->issuerName);
00758     return NS_OK;
00759   }
00760   return NS_ERROR_FAILURE;
00761 }
00762 
00763 NS_IMETHODIMP
00764 nsNSSCertificate::GetSerialNumber(nsAString &_serialNumber)
00765 {
00766   nsNSSShutDownPreventionLock locker;
00767   if (isAlreadyShutDown())
00768     return NS_ERROR_NOT_AVAILABLE;
00769 
00770   _serialNumber.Truncate();
00771   nsXPIDLCString tmpstr; tmpstr.Adopt(CERT_Hexify(&mCert->serialNumber, 1));
00772   if (tmpstr.get()) {
00773     _serialNumber = NS_ConvertASCIItoUCS2(tmpstr);
00774     return NS_OK;
00775   }
00776   return NS_ERROR_FAILURE;
00777 }
00778 
00779 NS_IMETHODIMP
00780 nsNSSCertificate::GetSha1Fingerprint(nsAString &_sha1Fingerprint)
00781 {
00782   nsNSSShutDownPreventionLock locker;
00783   if (isAlreadyShutDown())
00784     return NS_ERROR_NOT_AVAILABLE;
00785 
00786   _sha1Fingerprint.Truncate();
00787   unsigned char fingerprint[20];
00788   SECItem fpItem;
00789   memset(fingerprint, 0, sizeof fingerprint);
00790   PK11_HashBuf(SEC_OID_SHA1, fingerprint, 
00791                mCert->derCert.data, mCert->derCert.len);
00792   fpItem.data = fingerprint;
00793   fpItem.len = SHA1_LENGTH;
00794   nsXPIDLCString fpStr; fpStr.Adopt(CERT_Hexify(&fpItem, 1));
00795   if (fpStr.get()) {
00796     _sha1Fingerprint = NS_ConvertASCIItoUCS2(fpStr);
00797     return NS_OK;
00798   }
00799   return NS_ERROR_FAILURE;
00800 }
00801 
00802 NS_IMETHODIMP
00803 nsNSSCertificate::GetMd5Fingerprint(nsAString &_md5Fingerprint)
00804 {
00805   nsNSSShutDownPreventionLock locker;
00806   if (isAlreadyShutDown())
00807     return NS_ERROR_NOT_AVAILABLE;
00808 
00809   _md5Fingerprint.Truncate();
00810   unsigned char fingerprint[20];
00811   SECItem fpItem;
00812   memset(fingerprint, 0, sizeof fingerprint);
00813   PK11_HashBuf(SEC_OID_MD5, fingerprint, 
00814                mCert->derCert.data, mCert->derCert.len);
00815   fpItem.data = fingerprint;
00816   fpItem.len = MD5_LENGTH;
00817   nsXPIDLCString fpStr; fpStr.Adopt(CERT_Hexify(&fpItem, 1));
00818   if (fpStr.get()) {
00819     _md5Fingerprint = NS_ConvertASCIItoUCS2(fpStr);
00820     return NS_OK;
00821   }
00822   return NS_ERROR_FAILURE;
00823 }
00824 
00825 NS_IMETHODIMP
00826 nsNSSCertificate::GetTokenName(nsAString &aTokenName)
00827 {
00828   nsNSSShutDownPreventionLock locker;
00829   if (isAlreadyShutDown())
00830     return NS_ERROR_NOT_AVAILABLE;
00831 
00832   aTokenName.Truncate();
00833   if (mCert) {
00834     // HACK alert
00835     // When the trust of a builtin cert is modified, NSS copies it into the
00836     // cert db.  At this point, it is now "managed" by the user, and should
00837     // not be listed with the builtins.  However, in the collection code
00838     // used by PK11_ListCerts, the cert is found in the temp db, where it
00839     // has been loaded from the token.  Though the trust is correct (grabbed
00840     // from the cert db), the source is wrong.  I believe this is a safe
00841     // way to work around this.
00842     if (mCert->slot) {
00843       char *token = PK11_GetTokenName(mCert->slot);
00844       if (token) {
00845         aTokenName = NS_ConvertUTF8toUCS2(token);
00846       }
00847     } else {
00848       nsresult rv;
00849       nsAutoString tok;
00850       nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00851       if (NS_FAILED(rv)) return rv;
00852       rv = nssComponent->GetPIPNSSBundleString("InternalToken", tok);
00853       if (NS_SUCCEEDED(rv))
00854         aTokenName = tok;
00855     }
00856   }
00857   return NS_OK;
00858 }
00859 
00860 NS_IMETHODIMP
00861 nsNSSCertificate::GetRawDER(PRUint32 *aLength, PRUint8 **aArray)
00862 {
00863   nsNSSShutDownPreventionLock locker;
00864   if (isAlreadyShutDown())
00865     return NS_ERROR_NOT_AVAILABLE;
00866 
00867   if (mCert) {
00868     *aArray = (PRUint8*)nsMemory::Alloc(mCert->derCert.len);
00869     if (*aArray) {
00870       memcpy(*aArray, mCert->derCert.data, mCert->derCert.len);
00871       *aLength = mCert->derCert.len;
00872       return NS_OK;
00873     }
00874   }
00875   *aLength = 0;
00876   return NS_ERROR_FAILURE;
00877 }
00878 
00879 CERTCertificate *
00880 nsNSSCertificate::GetCert()
00881 {
00882   nsNSSShutDownPreventionLock locker;
00883   if (isAlreadyShutDown())
00884     return nsnull;
00885 
00886   return (mCert) ? CERT_DupCertificate(mCert) : nsnull;
00887 }
00888 
00889 NS_IMETHODIMP
00890 nsNSSCertificate::GetValidity(nsIX509CertValidity **aValidity)
00891 {
00892   nsNSSShutDownPreventionLock locker;
00893   if (isAlreadyShutDown())
00894     return NS_ERROR_NOT_AVAILABLE;
00895 
00896   NS_ENSURE_ARG(aValidity);
00897   nsX509CertValidity *validity = new nsX509CertValidity(mCert);
00898   if (nsnull == validity)
00899    return  NS_ERROR_OUT_OF_MEMORY; 
00900 
00901   NS_ADDREF(validity);
00902   *aValidity = NS_STATIC_CAST(nsIX509CertValidity*, validity);
00903   return NS_OK;
00904 }
00905 
00906 NS_IMETHODIMP
00907 nsNSSCertificate::VerifyForUsage(PRUint32 usage, PRUint32 *verificationResult)
00908 {
00909   nsNSSShutDownPreventionLock locker;
00910   if (isAlreadyShutDown())
00911     return NS_ERROR_NOT_AVAILABLE;
00912 
00913   NS_ENSURE_ARG(verificationResult);
00914 
00915   SECCertificateUsage nss_usage;
00916   
00917   switch (usage)
00918   {
00919     case CERT_USAGE_SSLClient:
00920       nss_usage = certificateUsageSSLClient;
00921       break;
00922 
00923     case CERT_USAGE_SSLServer:
00924       nss_usage = certificateUsageSSLServer;
00925       break;
00926 
00927     case CERT_USAGE_SSLServerWithStepUp:
00928       nss_usage = certificateUsageSSLServerWithStepUp;
00929       break;
00930 
00931     case CERT_USAGE_SSLCA:
00932       nss_usage = certificateUsageSSLCA;
00933       break;
00934 
00935     case CERT_USAGE_EmailSigner:
00936       nss_usage = certificateUsageEmailSigner;
00937       break;
00938 
00939     case CERT_USAGE_EmailRecipient:
00940       nss_usage = certificateUsageEmailRecipient;
00941       break;
00942 
00943     case CERT_USAGE_ObjectSigner:
00944       nss_usage = certificateUsageObjectSigner;
00945       break;
00946 
00947     case CERT_USAGE_UserCertImport:
00948       nss_usage = certificateUsageUserCertImport;
00949       break;
00950 
00951     case CERT_USAGE_VerifyCA:
00952       nss_usage = certificateUsageVerifyCA;
00953       break;
00954 
00955     case CERT_USAGE_ProtectedObjectSigner:
00956       nss_usage = certificateUsageProtectedObjectSigner;
00957       break;
00958 
00959     case CERT_USAGE_StatusResponder:
00960       nss_usage = certificateUsageStatusResponder;
00961       break;
00962 
00963     case CERT_USAGE_AnyCA:
00964       nss_usage = certificateUsageAnyCA;
00965       break;
00966 
00967     default:
00968       return NS_ERROR_FAILURE;
00969   }
00970 
00971   CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
00972 
00973   if (CERT_VerifyCertificateNow(defaultcertdb, mCert, PR_TRUE, 
00974                          nss_usage, NULL, NULL) == SECSuccess)
00975   {
00976     *verificationResult = VERIFIED_OK;
00977   }
00978   else
00979   {
00980     int err = PR_GetError();
00981 
00982     // this list was cloned from verifyFailed
00983 
00984     switch (err)
00985     {
00986       case SEC_ERROR_INADEQUATE_KEY_USAGE:
00987       case SEC_ERROR_INADEQUATE_CERT_TYPE:
00988         *verificationResult = USAGE_NOT_ALLOWED;
00989         break;
00990 
00991       case SEC_ERROR_REVOKED_CERTIFICATE:
00992         *verificationResult = CERT_REVOKED;
00993         break;
00994 
00995       case SEC_ERROR_EXPIRED_CERTIFICATE:
00996         *verificationResult = CERT_EXPIRED;
00997         break;
00998         
00999       case SEC_ERROR_UNTRUSTED_CERT:
01000         *verificationResult = CERT_NOT_TRUSTED;
01001         break;
01002         
01003       case SEC_ERROR_UNTRUSTED_ISSUER:
01004         *verificationResult = ISSUER_NOT_TRUSTED;
01005         break;
01006         
01007       case SEC_ERROR_UNKNOWN_ISSUER:
01008         *verificationResult = ISSUER_UNKNOWN;
01009         break;
01010         
01011       case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
01012         *verificationResult = INVALID_CA;
01013         break;
01014         
01015       case SEC_ERROR_CERT_USAGES_INVALID:
01016       default:
01017         *verificationResult = NOT_VERIFIED_UNKNOWN; 
01018         break;
01019     }
01020   }
01021   
01022   return NS_OK;  
01023 }
01024 
01025 
01026 NS_IMETHODIMP
01027 nsNSSCertificate::GetUsagesArray(PRBool ignoreOcsp,
01028                                  PRUint32 *_verified,
01029                                  PRUint32 *_count,
01030                                  PRUnichar ***_usages)
01031 {
01032   nsNSSShutDownPreventionLock locker;
01033   if (isAlreadyShutDown())
01034     return NS_ERROR_NOT_AVAILABLE;
01035 
01036   nsresult rv;
01037   const int max_usages = 13;
01038   PRUnichar *tmpUsages[max_usages];
01039   const char *suffix = "";
01040   PRUint32 tmpCount;
01041   nsUsageArrayHelper uah(mCert);
01042   rv = uah.GetUsagesArray(suffix, ignoreOcsp, max_usages, _verified, &tmpCount, tmpUsages);
01043   NS_ENSURE_SUCCESS(rv,rv);
01044   if (tmpCount > 0) {
01045     *_usages = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * tmpCount);
01046     if (!*_usages)
01047       return NS_ERROR_OUT_OF_MEMORY;
01048     for (PRUint32 i=0; i<tmpCount; i++) {
01049       (*_usages)[i] = tmpUsages[i];
01050     }
01051     *_count = tmpCount;
01052     return NS_OK;
01053   }
01054   *_usages = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *));
01055   if (!*_usages)
01056     return NS_ERROR_OUT_OF_MEMORY;
01057   *_count = 0;
01058   return NS_OK;
01059 }
01060 
01061 NS_IMETHODIMP
01062 nsNSSCertificate::RequestUsagesArrayAsync(nsICertVerificationListener *aResultListener)
01063 {
01064   if (!aResultListener)
01065     return NS_ERROR_FAILURE;
01066   
01067   nsCertVerificationJob *job = new nsCertVerificationJob;
01068   if (!job)
01069     return NS_ERROR_OUT_OF_MEMORY;
01070 
01071   job->mCert = this;
01072   job->mListener = aResultListener;
01073 
01074   nsresult rv = nsCertVerificationThread::addJob(job);
01075   if (NS_FAILED(rv))
01076     delete job;
01077 
01078   return rv;
01079 }
01080 
01081 NS_IMETHODIMP
01082 nsNSSCertificate::GetUsagesString(PRBool ignoreOcsp,
01083                                   PRUint32   *_verified,
01084                                   nsAString &_usages)
01085 {
01086   nsNSSShutDownPreventionLock locker;
01087   if (isAlreadyShutDown())
01088     return NS_ERROR_NOT_AVAILABLE;
01089 
01090   nsresult rv;
01091   const int max_usages = 13;
01092   PRUnichar *tmpUsages[max_usages];
01093   const char *suffix = "_p";
01094   PRUint32 tmpCount;
01095   nsUsageArrayHelper uah(mCert);
01096   rv = uah.GetUsagesArray(suffix, ignoreOcsp, max_usages, _verified, &tmpCount, tmpUsages);
01097   NS_ENSURE_SUCCESS(rv,rv);
01098   _usages.Truncate();
01099   for (PRUint32 i=0; i<tmpCount; i++) {
01100     if (i>0) _usages.AppendLiteral(",");
01101     _usages.Append(tmpUsages[i]);
01102     nsMemory::Free(tmpUsages[i]);
01103   }
01104   return NS_OK;
01105 }
01106 
01107 #if defined(DEBUG_javi) || defined(DEBUG_jgmyers)
01108 void
01109 DumpASN1Object(nsIASN1Object *object, unsigned int level)
01110 {
01111   nsAutoString dispNameU, dispValU;
01112   unsigned int i;
01113   nsCOMPtr<nsIMutableArray> asn1Objects;
01114   nsCOMPtr<nsISupports> isupports;
01115   nsCOMPtr<nsIASN1Object> currObject;
01116   PRBool processObjects;
01117   PRUint32 numObjects;
01118 
01119   for (i=0; i<level; i++)
01120     printf ("  ");
01121 
01122   object->GetDisplayName(dispNameU);
01123   nsCOMPtr<nsIASN1Sequence> sequence(do_QueryInterface(object));
01124   if (sequence) {
01125     printf ("%s ", NS_ConvertUCS2toUTF8(dispNameU).get());
01126     sequence->GetIsValidContainer(&processObjects);
01127     if (processObjects) {
01128       printf("\n");
01129       sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
01130       asn1Objects->GetLength(&numObjects);
01131       for (i=0; i<numObjects;i++) {
01132         asn1Objects->QueryElementAt(i, NS_GET_IID(nsISupports), getter_AddRefs(currObject));
01133         DumpASN1Object(currObject, level+1);    
01134       }
01135     } else { 
01136       object->GetDisplayValue(dispValU);
01137       printf("= %s\n", NS_ConvertUCS2toUTF8(dispValU).get()); 
01138     }
01139   } else { 
01140     object->GetDisplayValue(dispValU);
01141     printf("%s = %s\n",NS_ConvertUCS2toUTF8(dispNameU).get(), 
01142                        NS_ConvertUCS2toUTF8(dispValU).get()); 
01143   }
01144 }
01145 #endif
01146 
01147 /* readonly attribute nsIASN1Object ASN1Structure; */
01148 NS_IMETHODIMP 
01149 nsNSSCertificate::GetASN1Structure(nsIASN1Object * *aASN1Structure)
01150 {
01151   nsNSSShutDownPreventionLock locker;
01152   nsresult rv = NS_OK;
01153   NS_ENSURE_ARG_POINTER(aASN1Structure);
01154   if (mASN1Structure == nsnull) {
01155     // First create the recursive structure os ASN1Objects
01156     // which tells us the layout of the cert.
01157     rv = CreateASN1Struct();
01158     if (NS_FAILED(rv)) {
01159       return rv;
01160     }
01161 #ifdef DEBUG_javi
01162     DumpASN1Object(mASN1Structure, 0);
01163 #endif
01164   }
01165   *aASN1Structure = mASN1Structure;
01166   NS_IF_ADDREF(*aASN1Structure);
01167   return rv;
01168 }
01169 
01170 NS_IMETHODIMP
01171 nsNSSCertificate::Equals(nsIX509Cert *other, PRBool *result)
01172 {
01173   nsNSSShutDownPreventionLock locker;
01174   if (isAlreadyShutDown())
01175     return NS_ERROR_NOT_AVAILABLE;
01176 
01177   NS_ENSURE_ARG(other);
01178   NS_ENSURE_ARG(result);
01179 
01180   nsNSSCertificate *other2 = NS_STATIC_CAST(nsNSSCertificate*, other);
01181   if (!other2)
01182     return NS_ERROR_FAILURE;
01183   
01184   *result = (mCert == other2->mCert);
01185   return NS_OK;
01186 }
01187 
01188 NS_IMETHODIMP
01189 nsNSSCertificate::SaveSMimeProfile()
01190 {
01191   nsNSSShutDownPreventionLock locker;
01192   if (isAlreadyShutDown())
01193     return NS_ERROR_NOT_AVAILABLE;
01194 
01195   if (SECSuccess != CERT_SaveSMimeProfile(mCert, nsnull, nsnull))
01196     return NS_ERROR_FAILURE;
01197   else
01198     return NS_OK;
01199 }
01200 
01201 
01202 char* nsNSSCertificate::defaultServerNickname(CERTCertificate* cert)
01203 {
01204   nsNSSShutDownPreventionLock locker;
01205   char* nickname = nsnull;
01206   int count;
01207   PRBool conflict;
01208   char* servername = nsnull;
01209   
01210   servername = CERT_GetCommonName(&cert->subject);
01211   if (servername == NULL) {
01212     return nsnull;
01213   }
01214    
01215   count = 1;
01216   while (1) {
01217     if (count == 1) {
01218       nickname = PR_smprintf("%s", servername);
01219     }
01220     else {
01221       nickname = PR_smprintf("%s #%d", servername, count);
01222     }
01223     if (nickname == NULL) {
01224       break;
01225     }
01226 
01227     conflict = SEC_CertNicknameConflict(nickname, &cert->derSubject,
01228                                         cert->dbhandle);
01229     if (conflict == PR_SUCCESS) {
01230       break;
01231     }
01232     PR_Free(nickname);
01233     count++;
01234   }
01235   PR_FREEIF(servername);
01236   return nickname;
01237 }
01238 
01239 #ifndef INET6_ADDRSTRLEN
01240 #define INET6_ADDRSTRLEN 46
01241 #endif
01242 
01243 // returns TRUE if SAN was used to produce names
01244 // return FALSE if nothing was produced
01245 // names => a single name or a list of names
01246 // nameCount => the number of names returned
01247 static PRBool
01248 GetSubjectAltNames(CERTCertificate *nssCert,
01249                    nsAString &allNames,
01250                    PRUint32 &nameCount)
01251 {
01252   allNames.Truncate();
01253   nameCount = 0;
01254 
01255   PRArenaPool *san_arena = nsnull;
01256   SECItem altNameExtension = {siBuffer, NULL, 0 };
01257   CERTGeneralName *sanNameList = nsnull;
01258 
01259   nsresult rv;
01260   rv = CERT_FindCertExtension(nssCert, SEC_OID_X509_SUBJECT_ALT_NAME,
01261                               &altNameExtension);
01262   if (rv != SECSuccess)
01263     return PR_FALSE;
01264 
01265   san_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01266   if (!san_arena)
01267     return PR_FALSE;
01268 
01269   sanNameList = CERT_DecodeAltNameExtension(san_arena, &altNameExtension);
01270   if (!sanNameList)
01271     return PR_FALSE;
01272 
01273   SECITEM_FreeItem(&altNameExtension, PR_FALSE);
01274 
01275   CERTGeneralName *current = sanNameList;
01276   do {
01277     nsAutoString name;
01278     switch (current->type) {
01279       case certDNSName:
01280         name.AssignASCII((char*)current->name.other.data, current->name.other.len);
01281         if (!allNames.IsEmpty()) {
01282           allNames.Append(NS_LITERAL_STRING(" , "));
01283         }
01284         ++nameCount;
01285         allNames.Append(name);
01286         break;
01287 
01288       case certIPAddress:
01289         {
01290           char buf[INET6_ADDRSTRLEN];
01291           PRNetAddr addr;
01292           if (current->name.other.len == 4) {
01293             addr.inet.family = PR_AF_INET;
01294             memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len);
01295             PR_NetAddrToString(&addr, buf, sizeof(buf));
01296             name.AssignASCII(buf);
01297           } else if (current->name.other.len == 16) {
01298             addr.ipv6.family = PR_AF_INET6;
01299             memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len);
01300             PR_NetAddrToString(&addr, buf, sizeof(buf));
01301             name.AssignASCII(buf);
01302           } else {
01303             /* invalid IP address */
01304           }
01305           if (!name.IsEmpty()) {
01306             if (!allNames.IsEmpty()) {
01307               allNames.Append(NS_LITERAL_STRING(" , "));
01308             }
01309             ++nameCount;
01310             allNames.Append(name);
01311           }
01312           break;
01313         }
01314 
01315       default: // all other types of names are ignored
01316         break;
01317     }
01318     current = CERT_GetNextGeneralName(current);
01319   } while (current != sanNameList); // double linked
01320 
01321   PORT_FreeArena(san_arena, PR_FALSE);
01322   return PR_TRUE;
01323 }
01324 
01325 NS_IMETHODIMP
01326 nsNSSCertificate::GetValidNames(PRUnichar **aNames, PRUint32 *aCount)
01327 {
01328   NS_ENSURE_ARG_POINTER(aNames);
01329   NS_ENSURE_ARG_POINTER(aCount);
01330 
01331   nsNSSShutDownPreventionLock locker;
01332   if (isAlreadyShutDown())
01333     return NS_ERROR_NOT_AVAILABLE;
01334 
01335   if (!mCert)
01336     return NS_ERROR_NOT_AVAILABLE;
01337 
01338   nsString names;
01339   PRUint32 nameCount = 0;
01340   PRBool useSAN = PR_FALSE;
01341   useSAN = GetSubjectAltNames(mCert, names, nameCount);
01342 
01343   if (!useSAN) {
01344     char *certName = nsnull;
01345     // currently CERT_FindNSStringExtension is not being exported by NSS.
01346     // If it gets exported, enable the following line.
01347     //   certName = CERT_FindNSStringExtension(mCert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
01348     // However, it has been discussed to treat the extension as obsolete and ignore it.
01349     if (!certName)
01350       certName = CERT_GetCommonName(&mCert->subject);
01351     if (certName) {
01352       ++nameCount;
01353       names.AssignASCII(certName);
01354       PORT_Free(certName);
01355     }
01356   }
01357 
01358   *aNames = ToNewUnicode(names);
01359   *aCount = nameCount;
01360   return NS_OK;
01361 }