Back to index

lightning-sunbird  0.9+nobinonly
nsCMS.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): David Drinan <ddrinan@netscape.com>
00023  *   Kai Engert <kengert@redhat.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsISupports.h"
00040 #include "nsCMS.h"
00041 #include "nsNSSHelper.h"
00042 #include "nsNSSCertificate.h"
00043 #include "smime.h"
00044 #include "cms.h"
00045 #include "nsICMSMessageErrors.h"
00046 #include "nsArray.h"
00047 #include "nsCertVerificationThread.h"
00048 
00049 #include "prlog.h"
00050 #ifdef PR_LOGGING
00051 extern PRLogModuleInfo* gPIPNSSLog;
00052 #endif
00053 
00054 #include "nsNSSCleaner.h"
00055 
00056 NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
00057 
00058 NS_IMPL_THREADSAFE_ISUPPORTS2(nsCMSMessage, nsICMSMessage, 
00059                                             nsICMSMessage2)
00060 
00061 nsCMSMessage::nsCMSMessage()
00062 {
00063   m_cmsMsg = nsnull;
00064 }
00065 nsCMSMessage::nsCMSMessage(NSSCMSMessage *aCMSMsg)
00066 {
00067   m_cmsMsg = aCMSMsg;
00068 }
00069 
00070 nsCMSMessage::~nsCMSMessage()
00071 {
00072   nsNSSShutDownPreventionLock locker;
00073   if (isAlreadyShutDown())
00074     return;
00075 
00076   destructorSafeDestroyNSSReference();
00077   shutdown(calledFromObject);
00078 }
00079 
00080 void nsCMSMessage::virtualDestroyNSSReference()
00081 {
00082   destructorSafeDestroyNSSReference();
00083 }
00084 
00085 void nsCMSMessage::destructorSafeDestroyNSSReference()
00086 {
00087   if (isAlreadyShutDown())
00088     return;
00089 
00090   if (m_cmsMsg) {
00091     NSS_CMSMessage_Destroy(m_cmsMsg);
00092   }
00093 }
00094 
00095 NS_IMETHODIMP nsCMSMessage::VerifySignature()
00096 {
00097   return CommonVerifySignature(nsnull, 0);
00098 }
00099 
00100 NSSCMSSignerInfo* nsCMSMessage::GetTopLevelSignerInfo()
00101 {
00102   nsNSSShutDownPreventionLock locker;
00103   if (isAlreadyShutDown())
00104     return nsnull;
00105 
00106   if (!m_cmsMsg)
00107     return nsnull;
00108 
00109   if (!NSS_CMSMessage_IsSigned(m_cmsMsg))
00110     return nsnull;
00111 
00112   NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0);
00113   if (!cinfo)
00114     return nsnull;
00115 
00116   NSSCMSSignedData *sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo);
00117   if (!sigd)
00118     return nsnull;
00119 
00120   PR_ASSERT(NSS_CMSSignedData_SignerInfoCount(sigd) > 0);
00121   return NSS_CMSSignedData_GetSignerInfo(sigd, 0);
00122 }
00123 
00124 NS_IMETHODIMP nsCMSMessage::GetSignerEmailAddress(char * * aEmail)
00125 {
00126   nsNSSShutDownPreventionLock locker;
00127   if (isAlreadyShutDown())
00128     return NS_ERROR_NOT_AVAILABLE;
00129 
00130   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerEmailAddress\n"));
00131   NS_ENSURE_ARG(aEmail);
00132 
00133   NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
00134   if (!si)
00135     return NS_ERROR_FAILURE;
00136 
00137   *aEmail = NSS_CMSSignerInfo_GetSignerEmailAddress(si);
00138   return NS_OK;
00139 }
00140 
00141 NS_IMETHODIMP nsCMSMessage::GetSignerCommonName(char ** aName)
00142 {
00143   nsNSSShutDownPreventionLock locker;
00144   if (isAlreadyShutDown())
00145     return NS_ERROR_NOT_AVAILABLE;
00146 
00147   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCommonName\n"));
00148   NS_ENSURE_ARG(aName);
00149 
00150   NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
00151   if (!si)
00152     return NS_ERROR_FAILURE;
00153 
00154   *aName = NSS_CMSSignerInfo_GetSignerCommonName(si);
00155   return NS_OK;
00156 }
00157 
00158 NS_IMETHODIMP nsCMSMessage::ContentIsEncrypted(PRBool *isEncrypted)
00159 {
00160   nsNSSShutDownPreventionLock locker;
00161   if (isAlreadyShutDown())
00162     return NS_ERROR_NOT_AVAILABLE;
00163 
00164   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::ContentIsEncrypted\n"));
00165   NS_ENSURE_ARG(isEncrypted);
00166 
00167   if (!m_cmsMsg)
00168     return NS_ERROR_FAILURE;
00169 
00170   *isEncrypted = NSS_CMSMessage_IsEncrypted(m_cmsMsg);
00171 
00172   return NS_OK;
00173 }
00174 
00175 NS_IMETHODIMP nsCMSMessage::ContentIsSigned(PRBool *isSigned)
00176 {
00177   nsNSSShutDownPreventionLock locker;
00178   if (isAlreadyShutDown())
00179     return NS_ERROR_NOT_AVAILABLE;
00180 
00181   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::ContentIsSigned\n"));
00182   NS_ENSURE_ARG(isSigned);
00183 
00184   if (!m_cmsMsg)
00185     return NS_ERROR_FAILURE;
00186 
00187   *isSigned = NSS_CMSMessage_IsSigned(m_cmsMsg);
00188 
00189   return NS_OK;
00190 }
00191 
00192 NS_IMETHODIMP nsCMSMessage::GetSignerCert(nsIX509Cert **scert)
00193 {
00194   nsNSSShutDownPreventionLock locker;
00195   if (isAlreadyShutDown())
00196     return NS_ERROR_NOT_AVAILABLE;
00197 
00198   NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
00199   if (!si)
00200     return NS_ERROR_FAILURE;
00201 
00202   if (si->cert) {
00203     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCert got signer cert\n"));
00204 
00205     *scert = new nsNSSCertificate(si->cert);
00206     if (*scert) {
00207       (*scert)->AddRef();
00208     }
00209   }
00210   else {
00211     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCert no signer cert, do we have a cert list? %s\n",
00212       (si->certList != nsnull ? "yes" : "no") ));
00213 
00214     *scert = nsnull;
00215   }
00216   
00217   return NS_OK;
00218 }
00219 
00220 NS_IMETHODIMP nsCMSMessage::GetEncryptionCert(nsIX509Cert **ecert)
00221 {
00222   nsNSSShutDownPreventionLock locker;
00223   if (isAlreadyShutDown())
00224     return NS_ERROR_NOT_AVAILABLE;
00225 
00226     return NS_ERROR_NOT_IMPLEMENTED;
00227 }
00228 
00229 NS_IMETHODIMP nsCMSMessage::VerifyDetachedSignature(unsigned char* aDigestData, PRUint32 aDigestDataLen)
00230 {
00231   if (!aDigestData || !aDigestDataLen)
00232     return NS_ERROR_FAILURE;
00233 
00234   return CommonVerifySignature(aDigestData, aDigestDataLen);
00235 }
00236 
00237 nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, PRUint32 aDigestDataLen)
00238 {
00239   nsNSSShutDownPreventionLock locker;
00240   if (isAlreadyShutDown())
00241     return NS_ERROR_NOT_AVAILABLE;
00242 
00243   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature, content level count %d\n", NSS_CMSMessage_ContentLevelCount(m_cmsMsg)));
00244   NSSCMSContentInfo *cinfo = nsnull;
00245   NSSCMSSignedData *sigd = nsnull;
00246   NSSCMSSignerInfo *si;
00247   PRInt32 nsigners;
00248   nsresult rv = NS_ERROR_FAILURE;
00249 
00250   if (NSS_CMSMessage_IsSigned(m_cmsMsg) == PR_FALSE) {
00251     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - not signed\n"));
00252     return NS_ERROR_CMS_VERIFY_NOT_SIGNED;
00253   } 
00254 
00255   cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0);
00256   if (cinfo) {
00257     // I don't like this hard cast. We should check in some way, that we really have this type.
00258     sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo);
00259   }
00260   
00261   if (!sigd) {
00262     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - no content info\n"));
00263     rv = NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO;
00264     goto loser;
00265   }
00266 
00267   if (aDigestData && aDigestDataLen)
00268   {
00269     SECItem digest;
00270     digest.data = aDigestData;
00271     digest.len = aDigestDataLen;
00272 
00273     if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) {
00274       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad digest\n"));
00275       rv = NS_ERROR_CMS_VERIFY_BAD_DIGEST;
00276       goto loser;
00277     }
00278   }
00279 
00280   // Import certs. Note that import failure is not a signature verification failure. //
00281   if (NSS_CMSSignedData_ImportCerts(sigd, CERT_GetDefaultCertDB(), certUsageEmailRecipient, PR_TRUE) != SECSuccess) {
00282     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not import certs\n"));
00283   }
00284 
00285   nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
00286   PR_ASSERT(nsigners > 0);
00287   si = NSS_CMSSignedData_GetSignerInfo(sigd, 0);
00288 
00289 
00290   // See bug 324474. We want to make sure the signing cert is 
00291   // still valid at the current time.
00292   if (CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), si->cert, PR_TRUE, 
00293                                 certificateUsageEmailSigner,
00294                                 si->cmsg->pwfn_arg, NULL) != SECSuccess) {
00295     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted now\n"));
00296     rv = NS_ERROR_CMS_VERIFY_UNTRUSTED;
00297     goto loser;
00298   }
00299 
00300   // We verify the first signer info,  only //
00301   if (NSS_CMSSignedData_VerifySignerInfo(sigd, 0, CERT_GetDefaultCertDB(), certUsageEmailSigner) != SECSuccess) {
00302     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to verify signature\n"));
00303 
00304     if (NSSCMSVS_SigningCertNotFound == si->verificationStatus) {
00305       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not found\n"));
00306       rv = NS_ERROR_CMS_VERIFY_NOCERT;
00307     }
00308     else if(NSSCMSVS_SigningCertNotTrusted == si->verificationStatus) {
00309       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted at signing time\n"));
00310       rv = NS_ERROR_CMS_VERIFY_UNTRUSTED;
00311     }
00312     else if(NSSCMSVS_Unverified == si->verificationStatus) {
00313       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not verify\n"));
00314       rv = NS_ERROR_CMS_VERIFY_ERROR_UNVERIFIED;
00315     }
00316     else if(NSSCMSVS_ProcessingError == si->verificationStatus) {
00317       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - processing error\n"));
00318       rv = NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
00319     }
00320     else if(NSSCMSVS_BadSignature == si->verificationStatus) {
00321       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad signature\n"));
00322       rv = NS_ERROR_CMS_VERIFY_BAD_SIGNATURE;
00323     }
00324     else if(NSSCMSVS_DigestMismatch == si->verificationStatus) {
00325       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - digest mismatch\n"));
00326       rv = NS_ERROR_CMS_VERIFY_DIGEST_MISMATCH;
00327     }
00328     else if(NSSCMSVS_SignatureAlgorithmUnknown == si->verificationStatus) {
00329       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo unknown\n"));
00330       rv = NS_ERROR_CMS_VERIFY_UNKNOWN_ALGO;
00331     }
00332     else if(NSSCMSVS_SignatureAlgorithmUnsupported == si->verificationStatus) {
00333       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo not supported\n"));
00334       rv = NS_ERROR_CMS_VERIFY_UNSUPPORTED_ALGO;
00335     }
00336     else if(NSSCMSVS_MalformedSignature == si->verificationStatus) {
00337       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - malformed signature\n"));
00338       rv = NS_ERROR_CMS_VERIFY_MALFORMED_SIGNATURE;
00339     }
00340 
00341     goto loser;
00342   }
00343 
00344   // Save the profile. Note that save import failure is not a signature verification failure. //
00345   if (NSS_SMIMESignerInfo_SaveSMIMEProfile(si) != SECSuccess) {
00346     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to save smime profile\n"));
00347   }
00348 
00349   rv = NS_OK;
00350 loser:
00351   return rv;
00352 }
00353 
00354 NS_IMETHODIMP nsCMSMessage::AsyncVerifySignature(
00355                               nsISMimeVerificationListener *aListener)
00356 {
00357   return CommonAsyncVerifySignature(aListener, nsnull, 0);
00358 }
00359 
00360 NS_IMETHODIMP nsCMSMessage::AsyncVerifyDetachedSignature(
00361                               nsISMimeVerificationListener *aListener,
00362                               unsigned char* aDigestData, PRUint32 aDigestDataLen)
00363 {
00364   if (!aDigestData || !aDigestDataLen)
00365     return NS_ERROR_FAILURE;
00366 
00367   return CommonAsyncVerifySignature(aListener, aDigestData, aDigestDataLen);
00368 }
00369 
00370 nsresult nsCMSMessage::CommonAsyncVerifySignature(nsISMimeVerificationListener *aListener,
00371                                                   unsigned char* aDigestData, PRUint32 aDigestDataLen)
00372 {
00373   nsSMimeVerificationJob *job = new nsSMimeVerificationJob;
00374   if (!job)
00375     return NS_ERROR_OUT_OF_MEMORY;
00376   
00377   if (aDigestData)
00378   {
00379     job->digest_data = new unsigned char[aDigestDataLen];
00380     if (!job->digest_data)
00381     {
00382       delete job;
00383       return NS_ERROR_OUT_OF_MEMORY;
00384     }
00385     
00386     memcpy(job->digest_data, aDigestData, aDigestDataLen);
00387   }
00388   else
00389   {
00390     job->digest_data = nsnull;
00391   }
00392   
00393   job->digest_len = aDigestDataLen;
00394   job->mMessage = this;
00395   job->mListener = aListener;
00396 
00397   nsresult rv = nsCertVerificationThread::addJob(job);
00398   if (NS_FAILED(rv))
00399     delete job;
00400 
00401   return rv;
00402 }
00403 
00404 class nsZeroTerminatedCertArray : public nsNSSShutDownObject
00405 {
00406 public:
00407   nsZeroTerminatedCertArray()
00408   :mCerts(nsnull), mPoolp(nsnull), mSize(0)
00409   {
00410   }
00411   
00412   ~nsZeroTerminatedCertArray()
00413   {
00414     nsNSSShutDownPreventionLock locker;
00415     if (isAlreadyShutDown())
00416       return;
00417 
00418     destructorSafeDestroyNSSReference();
00419     shutdown(calledFromObject);
00420   }
00421 
00422   void virtualDestroyNSSReference()
00423   {
00424     destructorSafeDestroyNSSReference();
00425   }
00426 
00427   void destructorSafeDestroyNSSReference()
00428   {
00429     if (isAlreadyShutDown())
00430       return;
00431 
00432     if (mCerts)
00433     {
00434       for (PRUint32 i=0; i < mSize; i++) {
00435         if (mCerts[i]) {
00436           CERT_DestroyCertificate(mCerts[i]);
00437         }
00438       }
00439     }
00440 
00441     if (mPoolp)
00442       PORT_FreeArena(mPoolp, PR_FALSE);
00443   }
00444 
00445   PRBool allocate(PRUint32 count)
00446   {
00447     // only allow allocation once
00448     if (mPoolp)
00449       return PR_FALSE;
00450   
00451     mSize = count;
00452 
00453     if (!mSize)
00454       return PR_FALSE;
00455   
00456     mPoolp = PORT_NewArena(1024);
00457     if (!mPoolp)
00458       return PR_FALSE;
00459 
00460     mCerts = (CERTCertificate**)PORT_ArenaZAlloc(
00461       mPoolp, (count+1)*sizeof(CERTCertificate*));
00462 
00463     if (!mCerts)
00464       return PR_FALSE;
00465 
00466     // null array, including zero termination
00467     for (PRUint32 i = 0; i < count+1; i++) {
00468       mCerts[i] = nsnull;
00469     }
00470 
00471     return PR_TRUE;
00472   }
00473   
00474   void set(PRUint32 i, CERTCertificate *c)
00475   {
00476     nsNSSShutDownPreventionLock locker;
00477     if (isAlreadyShutDown())
00478       return;
00479 
00480     if (i >= mSize)
00481       return;
00482     
00483     if (mCerts[i]) {
00484       CERT_DestroyCertificate(mCerts[i]);
00485     }
00486     
00487     mCerts[i] = CERT_DupCertificate(c);
00488   }
00489   
00490   CERTCertificate *get(PRUint32 i)
00491   {
00492     nsNSSShutDownPreventionLock locker;
00493     if (isAlreadyShutDown())
00494       return nsnull;
00495 
00496     if (i >= mSize)
00497       return nsnull;
00498     
00499     return CERT_DupCertificate(mCerts[i]);
00500   }
00501 
00502   CERTCertificate **getRawArray()
00503   {
00504     nsNSSShutDownPreventionLock locker;
00505     if (isAlreadyShutDown())
00506       return nsnull;
00507 
00508     return mCerts;
00509   }
00510 
00511 private:
00512   CERTCertificate **mCerts;
00513   PLArenaPool *mPoolp;
00514   PRUint32 mSize;
00515 };
00516 
00517 NS_IMETHODIMP nsCMSMessage::CreateEncrypted(nsIArray * aRecipientCerts)
00518 {
00519   nsNSSShutDownPreventionLock locker;
00520   if (isAlreadyShutDown())
00521     return NS_ERROR_NOT_AVAILABLE;
00522 
00523   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted\n"));
00524   NSSCMSContentInfo *cinfo;
00525   NSSCMSEnvelopedData *envd;
00526   NSSCMSRecipientInfo *recipientInfo;
00527   nsZeroTerminatedCertArray recipientCerts;
00528   SECOidTag bulkAlgTag;
00529   int keySize;
00530   PRUint32 i;
00531   nsNSSCertificate *nssRecipientCert;
00532   nsresult rv = NS_ERROR_FAILURE;
00533 
00534   // Check the recipient certificates //
00535   PRUint32 recipientCertCount;
00536   aRecipientCerts->GetLength(&recipientCertCount);
00537   PR_ASSERT(recipientCertCount > 0);
00538 
00539   if (!recipientCerts.allocate(recipientCertCount)) {
00540     goto loser;
00541   }
00542 
00543   for (i=0; i<recipientCertCount; i++) {
00544     nsCOMPtr<nsIX509Cert> x509cert = do_QueryElementAt(aRecipientCerts, i);
00545 
00546     nssRecipientCert = 
00547       NS_STATIC_CAST(nsNSSCertificate*, 
00548                      NS_STATIC_CAST(nsIX509Cert*, x509cert));
00549 
00550     if (!nssRecipientCert)
00551       return NS_ERROR_FAILURE;
00552 
00553     CERTCertificate *c = nssRecipientCert->GetCert();
00554     CERTCertificateCleaner rcCleaner(c);
00555     recipientCerts.set(i, c);
00556   }
00557   
00558   // Find a bulk key algorithm //
00559   if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientCerts.getRawArray(), &bulkAlgTag,
00560                                             &keySize) != SECSuccess) {
00561     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't find bulk alg for recipients\n"));
00562     rv = NS_ERROR_CMS_ENCRYPT_NO_BULK_ALG;
00563     goto loser;
00564   }
00565 
00566   m_cmsMsg = NSS_CMSMessage_Create(NULL);
00567   if (m_cmsMsg == nsnull) {
00568     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create new cms message\n"));
00569     rv = NS_ERROR_OUT_OF_MEMORY;
00570     goto loser;
00571   }
00572 
00573   if ((envd = NSS_CMSEnvelopedData_Create(m_cmsMsg, bulkAlgTag, keySize)) == nsnull) {
00574     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create enveloped data\n"));
00575     goto loser;
00576   }
00577 
00578   cinfo = NSS_CMSMessage_GetContentInfo(m_cmsMsg);
00579   if (NSS_CMSContentInfo_SetContent_EnvelopedData(m_cmsMsg, cinfo, envd) != SECSuccess) {
00580     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create content enveloped data\n"));
00581     goto loser;
00582   }
00583 
00584   cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
00585   if (NSS_CMSContentInfo_SetContent_Data(m_cmsMsg, cinfo, nsnull, PR_FALSE) != SECSuccess) {
00586     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't set content data\n"));
00587     goto loser;
00588   }
00589 
00590   // Create and attach recipient information //
00591   for (i=0; i < recipientCertCount; i++) {
00592     CERTCertificate *rc = recipientCerts.get(i);
00593     CERTCertificateCleaner rcCleaner(rc);
00594     if ((recipientInfo = NSS_CMSRecipientInfo_Create(m_cmsMsg, rc)) == nsnull) {
00595       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create recipient info\n"));
00596       goto loser;
00597     }
00598     if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientInfo) != SECSuccess) {
00599       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't add recipient info\n"));
00600       goto loser;
00601     }
00602   }
00603 
00604   return NS_OK;
00605 loser:
00606   if (m_cmsMsg) {
00607     NSS_CMSMessage_Destroy(m_cmsMsg);
00608     m_cmsMsg = nsnull;
00609   }
00610 
00611   return rv;
00612 }
00613 
00614 NS_IMETHODIMP nsCMSMessage::CreateSigned(nsIX509Cert* aSigningCert, nsIX509Cert* aEncryptCert, unsigned char* aDigestData, PRUint32 aDigestDataLen)
00615 {
00616   nsNSSShutDownPreventionLock locker;
00617   if (isAlreadyShutDown())
00618     return NS_ERROR_NOT_AVAILABLE;
00619 
00620   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned\n"));
00621   NSSCMSContentInfo *cinfo;
00622   NSSCMSSignedData *sigd;
00623   NSSCMSSignerInfo *signerinfo;
00624   CERTCertificate *scert = nsnull, *ecert = nsnull;
00625   nsresult rv = NS_ERROR_FAILURE;
00626 
00627   /* Get the certs */
00628   scert = NS_STATIC_CAST(nsNSSCertificate*, aSigningCert)->GetCert();
00629   if (!scert) {
00630     return NS_ERROR_FAILURE;
00631   }
00632 
00633   if (aEncryptCert) {
00634     ecert = NS_STATIC_CAST(nsNSSCertificate*, aEncryptCert)->GetCert();
00635   }
00636 
00637   CERTCertificateCleaner ecertCleaner(ecert);
00638   CERTCertificateCleaner scertCleaner(scert);
00639 
00640   /*
00641    * create the message object
00642    */
00643   m_cmsMsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
00644   if (m_cmsMsg == NULL) {
00645     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create new message\n"));
00646     rv = NS_ERROR_OUT_OF_MEMORY;
00647     goto loser;
00648   }
00649 
00650   /*
00651    * build chain of objects: message->signedData->data
00652    */
00653   if ((sigd = NSS_CMSSignedData_Create(m_cmsMsg)) == NULL) {
00654     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signed data\n"));
00655     goto loser;
00656   }
00657   cinfo = NSS_CMSMessage_GetContentInfo(m_cmsMsg);
00658   if (NSS_CMSContentInfo_SetContent_SignedData(m_cmsMsg, cinfo, sigd) 
00659           != SECSuccess) {
00660     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set content signed data\n"));
00661     goto loser;
00662   }
00663 
00664   cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
00665 
00666   /* we're always passing data in and detaching optionally */
00667   if (NSS_CMSContentInfo_SetContent_Data(m_cmsMsg, cinfo, nsnull, PR_TRUE) 
00668           != SECSuccess) {
00669     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set content data\n"));
00670     goto loser;
00671   }
00672 
00673   /* 
00674    * create & attach signer information
00675    */
00676   if ((signerinfo = NSS_CMSSignerInfo_Create(m_cmsMsg, scert, SEC_OID_SHA1)) 
00677           == NULL) {
00678     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signer info\n"));
00679     goto loser;
00680   }
00681 
00682   /* we want the cert chain included for this one */
00683   if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, 
00684                                        certUsageEmailSigner) 
00685           != SECSuccess) {
00686     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't include signer cert chain\n"));
00687     goto loser;
00688   }
00689 
00690   if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) 
00691              != SECSuccess) {
00692     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add signing time\n"));
00693     goto loser;
00694   }
00695 
00696   if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
00697     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime caps\n"));
00698     goto loser;
00699   }
00700 
00701   if (ecert) {
00702     if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ecert, 
00703                                            CERT_GetDefaultCertDB())
00704          != SECSuccess) {
00705       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime enc key prefs\n"));
00706       goto loser;
00707     }
00708 
00709     if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ecert, 
00710                                            CERT_GetDefaultCertDB())
00711          != SECSuccess) {
00712       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add MS smime enc key prefs\n"));
00713       goto loser;
00714     }
00715 
00716     if (NSS_CMSSignedData_AddCertificate(sigd, ecert) != SECSuccess) {
00717       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add own encryption certificate\n"));
00718       goto loser;
00719     }
00720   }
00721 
00722   if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
00723     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add signer info\n"));
00724     goto loser;
00725   }
00726 
00727   // Finally, add the pre-computed digest if passed in
00728   if (aDigestData) {
00729     SECItem digest;
00730 
00731     digest.data = aDigestData;
00732     digest.len = aDigestDataLen;
00733 
00734     if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) {
00735       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set digest value\n"));
00736       goto loser;
00737     }
00738   }
00739 
00740   return NS_OK;
00741 loser:
00742   if (m_cmsMsg) {
00743     NSS_CMSMessage_Destroy(m_cmsMsg);
00744     m_cmsMsg = nsnull;
00745   }
00746   return rv;
00747 }
00748 
00749 NS_IMPL_THREADSAFE_ISUPPORTS1(nsCMSDecoder, nsICMSDecoder)
00750 
00751 nsCMSDecoder::nsCMSDecoder()
00752 : m_dcx(nsnull)
00753 {
00754 }
00755 
00756 nsCMSDecoder::~nsCMSDecoder()
00757 {
00758   nsNSSShutDownPreventionLock locker;
00759   if (isAlreadyShutDown())
00760     return;
00761 
00762   destructorSafeDestroyNSSReference();
00763   shutdown(calledFromObject);
00764 }
00765 
00766 void nsCMSDecoder::virtualDestroyNSSReference()
00767 {
00768   destructorSafeDestroyNSSReference();
00769 }
00770 
00771 void nsCMSDecoder::destructorSafeDestroyNSSReference()
00772 {
00773   if (isAlreadyShutDown())
00774     return;
00775 
00776   if (m_dcx) {
00777     NSS_CMSDecoder_Cancel(m_dcx);
00778     m_dcx = nsnull;
00779   }
00780 }
00781 
00782 /* void start (in NSSCMSContentCallback cb, in voidPtr arg); */
00783 NS_IMETHODIMP nsCMSDecoder::Start(NSSCMSContentCallback cb, void * arg)
00784 {
00785   nsNSSShutDownPreventionLock locker;
00786   if (isAlreadyShutDown())
00787     return NS_ERROR_NOT_AVAILABLE;
00788 
00789   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Start\n"));
00790   m_ctx = new PipUIContext();
00791 
00792   m_dcx = NSS_CMSDecoder_Start(0, cb, arg, 0, m_ctx, 0, 0);
00793   if (!m_dcx) {
00794     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Start - can't start decoder\n"));
00795     return NS_ERROR_FAILURE;
00796   }
00797   return NS_OK;
00798 }
00799 
00800 /* void update (in string bug, in long len); */
00801 NS_IMETHODIMP nsCMSDecoder::Update(const char *buf, PRInt32 len)
00802 {
00803   nsNSSShutDownPreventionLock locker;
00804   if (isAlreadyShutDown())
00805     return NS_ERROR_NOT_AVAILABLE;
00806 
00807   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Update\n"));
00808   NSS_CMSDecoder_Update(m_dcx, (char *)buf, len);
00809   return NS_OK;
00810 }
00811 
00812 /* void finish (); */
00813 NS_IMETHODIMP nsCMSDecoder::Finish(nsICMSMessage ** aCMSMsg)
00814 {
00815   nsNSSShutDownPreventionLock locker;
00816   if (isAlreadyShutDown())
00817     return NS_ERROR_NOT_AVAILABLE;
00818 
00819   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Finish\n"));
00820   NSSCMSMessage *cmsMsg;
00821   cmsMsg = NSS_CMSDecoder_Finish(m_dcx);
00822   m_dcx = nsnull;
00823   if (cmsMsg) {
00824     nsCMSMessage *obj = new nsCMSMessage(cmsMsg);
00825     // The NSS object cmsMsg still carries a reference to the context
00826     // we gave it on construction.
00827     // Make sure the context will live long enough.
00828     obj->referenceContext(m_ctx);
00829     *aCMSMsg = obj;
00830     NS_ADDREF(*aCMSMsg);
00831   }
00832   return NS_OK;
00833 }
00834 
00835 NS_IMPL_THREADSAFE_ISUPPORTS1(nsCMSEncoder, nsICMSEncoder)
00836 
00837 nsCMSEncoder::nsCMSEncoder()
00838 : m_ecx(nsnull)
00839 {
00840 }
00841 
00842 nsCMSEncoder::~nsCMSEncoder()
00843 {
00844   nsNSSShutDownPreventionLock locker;
00845   if (isAlreadyShutDown())
00846     return;
00847 
00848   destructorSafeDestroyNSSReference();
00849   shutdown(calledFromObject);
00850 }
00851 
00852 void nsCMSEncoder::virtualDestroyNSSReference()
00853 {
00854   destructorSafeDestroyNSSReference();
00855 }
00856 
00857 void nsCMSEncoder::destructorSafeDestroyNSSReference()
00858 {
00859   nsNSSShutDownPreventionLock locker;
00860   if (isAlreadyShutDown())
00861     return;
00862 
00863   if (m_ecx)
00864     NSS_CMSEncoder_Cancel(m_ecx);
00865 }
00866 
00867 /* void start (); */
00868 NS_IMETHODIMP nsCMSEncoder::Start(nsICMSMessage *aMsg, NSSCMSContentCallback cb, void * arg)
00869 {
00870   nsNSSShutDownPreventionLock locker;
00871   if (isAlreadyShutDown())
00872     return NS_ERROR_NOT_AVAILABLE;
00873 
00874   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Start\n"));
00875   nsCMSMessage *cmsMsg = NS_STATIC_CAST(nsCMSMessage*, aMsg);
00876   m_ctx = new PipUIContext();
00877 
00878   m_ecx = NSS_CMSEncoder_Start(cmsMsg->getCMS(), cb, arg, 0, 0, 0, m_ctx, 0, 0, 0, 0);
00879   if (m_ecx == nsnull) {
00880     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Start - can't start encoder\n"));
00881     return NS_ERROR_FAILURE;
00882   }
00883   return NS_OK;
00884 }
00885 
00886 /* void update (in string aBuf, in long aLen); */
00887 NS_IMETHODIMP nsCMSEncoder::Update(const char *aBuf, PRInt32 aLen)
00888 {
00889   nsNSSShutDownPreventionLock locker;
00890   if (isAlreadyShutDown())
00891     return NS_ERROR_NOT_AVAILABLE;
00892 
00893   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Update\n"));
00894   if (!m_ecx || NSS_CMSEncoder_Update(m_ecx, aBuf, aLen) != SECSuccess) {
00895     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Update - can't update encoder\n"));
00896     return NS_ERROR_FAILURE;
00897   }
00898   return NS_OK;
00899 }
00900 
00901 /* void finish (); */
00902 NS_IMETHODIMP nsCMSEncoder::Finish()
00903 {
00904   nsNSSShutDownPreventionLock locker;
00905   if (isAlreadyShutDown())
00906     return NS_ERROR_NOT_AVAILABLE;
00907 
00908   nsresult rv = NS_OK;
00909   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Finish\n"));
00910   if (!m_ecx || NSS_CMSEncoder_Finish(m_ecx) != SECSuccess) {
00911     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Finish - can't finish encoder\n"));
00912     rv = NS_ERROR_FAILURE;
00913   }
00914   m_ecx = nsnull;
00915   return rv;
00916 }
00917 
00918 /* void encode (in nsICMSMessage aMsg); */
00919 NS_IMETHODIMP nsCMSEncoder::Encode(nsICMSMessage *aMsg)
00920 {
00921   nsNSSShutDownPreventionLock locker;
00922   if (isAlreadyShutDown())
00923     return NS_ERROR_NOT_AVAILABLE;
00924 
00925   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Encode\n"));
00926   return NS_ERROR_NOT_IMPLEMENTED;
00927 }