security/manager/ssl/src/nsCMS.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsCMS.h"
     8 #include "CertVerifier.h"
     9 #include "pkix/pkixtypes.h"
    10 #include "nsISupports.h"
    11 #include "nsNSSHelper.h"
    12 #include "nsNSSCertificate.h"
    13 #include "smime.h"
    14 #include "cms.h"
    15 #include "nsICMSMessageErrors.h"
    16 #include "nsIArray.h"
    17 #include "nsArrayUtils.h"
    18 #include "nsCertVerificationThread.h"
    20 #include "prlog.h"
    22 using namespace mozilla;
    23 using namespace mozilla::psm;
    25 #ifdef PR_LOGGING
    26 extern PRLogModuleInfo* gPIPNSSLog;
    27 #endif
    29 using namespace mozilla;
    31 NS_IMPL_ISUPPORTS(nsCMSMessage, nsICMSMessage, nsICMSMessage2)
    33 nsCMSMessage::nsCMSMessage()
    34 {
    35   m_cmsMsg = nullptr;
    36 }
    37 nsCMSMessage::nsCMSMessage(NSSCMSMessage *aCMSMsg)
    38 {
    39   m_cmsMsg = aCMSMsg;
    40 }
    42 nsCMSMessage::~nsCMSMessage()
    43 {
    44   nsNSSShutDownPreventionLock locker;
    45   if (isAlreadyShutDown()) {
    46     return;
    47   }
    48   destructorSafeDestroyNSSReference();
    49   shutdown(calledFromObject);
    50 }
    52 void nsCMSMessage::virtualDestroyNSSReference()
    53 {
    54   destructorSafeDestroyNSSReference();
    55 }
    57 void nsCMSMessage::destructorSafeDestroyNSSReference()
    58 {
    59   if (m_cmsMsg) {
    60     NSS_CMSMessage_Destroy(m_cmsMsg);
    61   }
    62 }
    64 NS_IMETHODIMP nsCMSMessage::VerifySignature()
    65 {
    66   return CommonVerifySignature(nullptr, 0);
    67 }
    69 NSSCMSSignerInfo* nsCMSMessage::GetTopLevelSignerInfo()
    70 {
    71   nsNSSShutDownPreventionLock locker;
    72   if (isAlreadyShutDown())
    73     return nullptr;
    75   if (!m_cmsMsg)
    76     return nullptr;
    78   if (!NSS_CMSMessage_IsSigned(m_cmsMsg))
    79     return nullptr;
    81   NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0);
    82   if (!cinfo)
    83     return nullptr;
    85   NSSCMSSignedData *sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo);
    86   if (!sigd)
    87     return nullptr;
    89   PR_ASSERT(NSS_CMSSignedData_SignerInfoCount(sigd) > 0);
    90   return NSS_CMSSignedData_GetSignerInfo(sigd, 0);
    91 }
    93 NS_IMETHODIMP nsCMSMessage::GetSignerEmailAddress(char * * aEmail)
    94 {
    95   nsNSSShutDownPreventionLock locker;
    96   if (isAlreadyShutDown())
    97     return NS_ERROR_NOT_AVAILABLE;
    99   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerEmailAddress\n"));
   100   NS_ENSURE_ARG(aEmail);
   102   NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
   103   if (!si)
   104     return NS_ERROR_FAILURE;
   106   *aEmail = NSS_CMSSignerInfo_GetSignerEmailAddress(si);
   107   return NS_OK;
   108 }
   110 NS_IMETHODIMP nsCMSMessage::GetSignerCommonName(char ** aName)
   111 {
   112   nsNSSShutDownPreventionLock locker;
   113   if (isAlreadyShutDown())
   114     return NS_ERROR_NOT_AVAILABLE;
   116   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCommonName\n"));
   117   NS_ENSURE_ARG(aName);
   119   NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
   120   if (!si)
   121     return NS_ERROR_FAILURE;
   123   *aName = NSS_CMSSignerInfo_GetSignerCommonName(si);
   124   return NS_OK;
   125 }
   127 NS_IMETHODIMP nsCMSMessage::ContentIsEncrypted(bool *isEncrypted)
   128 {
   129   nsNSSShutDownPreventionLock locker;
   130   if (isAlreadyShutDown())
   131     return NS_ERROR_NOT_AVAILABLE;
   133   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::ContentIsEncrypted\n"));
   134   NS_ENSURE_ARG(isEncrypted);
   136   if (!m_cmsMsg)
   137     return NS_ERROR_FAILURE;
   139   *isEncrypted = NSS_CMSMessage_IsEncrypted(m_cmsMsg);
   141   return NS_OK;
   142 }
   144 NS_IMETHODIMP nsCMSMessage::ContentIsSigned(bool *isSigned)
   145 {
   146   nsNSSShutDownPreventionLock locker;
   147   if (isAlreadyShutDown())
   148     return NS_ERROR_NOT_AVAILABLE;
   150   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::ContentIsSigned\n"));
   151   NS_ENSURE_ARG(isSigned);
   153   if (!m_cmsMsg)
   154     return NS_ERROR_FAILURE;
   156   *isSigned = NSS_CMSMessage_IsSigned(m_cmsMsg);
   158   return NS_OK;
   159 }
   161 NS_IMETHODIMP nsCMSMessage::GetSignerCert(nsIX509Cert **scert)
   162 {
   163   nsNSSShutDownPreventionLock locker;
   164   if (isAlreadyShutDown())
   165     return NS_ERROR_NOT_AVAILABLE;
   167   NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
   168   if (!si)
   169     return NS_ERROR_FAILURE;
   171   if (si->cert) {
   172     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCert got signer cert\n"));
   174     *scert = nsNSSCertificate::Create(si->cert);
   175     if (*scert) {
   176       (*scert)->AddRef();
   177     }
   178   }
   179   else {
   180     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCert no signer cert, do we have a cert list? %s\n",
   181       (si->certList ? "yes" : "no") ));
   183     *scert = nullptr;
   184   }
   186   return NS_OK;
   187 }
   189 NS_IMETHODIMP nsCMSMessage::GetEncryptionCert(nsIX509Cert **ecert)
   190 {
   191   nsNSSShutDownPreventionLock locker;
   192   if (isAlreadyShutDown())
   193     return NS_ERROR_NOT_AVAILABLE;
   195     return NS_ERROR_NOT_IMPLEMENTED;
   196 }
   198 NS_IMETHODIMP nsCMSMessage::VerifyDetachedSignature(unsigned char* aDigestData, uint32_t aDigestDataLen)
   199 {
   200   if (!aDigestData || !aDigestDataLen)
   201     return NS_ERROR_FAILURE;
   203   return CommonVerifySignature(aDigestData, aDigestDataLen);
   204 }
   206 nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, uint32_t aDigestDataLen)
   207 {
   208   nsNSSShutDownPreventionLock locker;
   209   if (isAlreadyShutDown())
   210     return NS_ERROR_NOT_AVAILABLE;
   212   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature, content level count %d\n", NSS_CMSMessage_ContentLevelCount(m_cmsMsg)));
   213   NSSCMSContentInfo *cinfo = nullptr;
   214   NSSCMSSignedData *sigd = nullptr;
   215   NSSCMSSignerInfo *si;
   216   int32_t nsigners;
   217   RefPtr<SharedCertVerifier> certVerifier;
   218   nsresult rv = NS_ERROR_FAILURE;
   220   if (!NSS_CMSMessage_IsSigned(m_cmsMsg)) {
   221     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - not signed\n"));
   222     return NS_ERROR_CMS_VERIFY_NOT_SIGNED;
   223   } 
   225   cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0);
   226   if (cinfo) {
   227     // I don't like this hard cast. We should check in some way, that we really have this type.
   228     sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo);
   229   }
   231   if (!sigd) {
   232     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - no content info\n"));
   233     rv = NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO;
   234     goto loser;
   235   }
   237   if (aDigestData && aDigestDataLen)
   238   {
   239     SECItem digest;
   240     digest.data = aDigestData;
   241     digest.len = aDigestDataLen;
   243     if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) {
   244       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad digest\n"));
   245       rv = NS_ERROR_CMS_VERIFY_BAD_DIGEST;
   246       goto loser;
   247     }
   248   }
   250   // Import certs. Note that import failure is not a signature verification failure. //
   251   if (NSS_CMSSignedData_ImportCerts(sigd, CERT_GetDefaultCertDB(), certUsageEmailRecipient, true) != SECSuccess) {
   252     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not import certs\n"));
   253   }
   255   nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
   256   PR_ASSERT(nsigners > 0);
   257   NS_ENSURE_TRUE(nsigners > 0, NS_ERROR_UNEXPECTED);
   258   si = NSS_CMSSignedData_GetSignerInfo(sigd, 0);
   260   // See bug 324474. We want to make sure the signing cert is 
   261   // still valid at the current time.
   263   certVerifier = GetDefaultCertVerifier();
   264   NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
   266   {
   267     SECStatus srv = certVerifier->VerifyCert(si->cert,
   268                                              certificateUsageEmailSigner,
   269                                              PR_Now(), nullptr /*XXX pinarg*/,
   270                                              nullptr /*hostname*/);
   271     if (srv != SECSuccess) {
   272       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   273              ("nsCMSMessage::CommonVerifySignature - signing cert not trusted now\n"));
   274       rv = NS_ERROR_CMS_VERIFY_UNTRUSTED;
   275       goto loser;
   276     }
   277   }
   279   // We verify the first signer info,  only //
   280   if (NSS_CMSSignedData_VerifySignerInfo(sigd, 0, CERT_GetDefaultCertDB(), certUsageEmailSigner) != SECSuccess) {
   281     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to verify signature\n"));
   283     if (NSSCMSVS_SigningCertNotFound == si->verificationStatus) {
   284       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not found\n"));
   285       rv = NS_ERROR_CMS_VERIFY_NOCERT;
   286     }
   287     else if(NSSCMSVS_SigningCertNotTrusted == si->verificationStatus) {
   288       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted at signing time\n"));
   289       rv = NS_ERROR_CMS_VERIFY_UNTRUSTED;
   290     }
   291     else if(NSSCMSVS_Unverified == si->verificationStatus) {
   292       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not verify\n"));
   293       rv = NS_ERROR_CMS_VERIFY_ERROR_UNVERIFIED;
   294     }
   295     else if(NSSCMSVS_ProcessingError == si->verificationStatus) {
   296       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - processing error\n"));
   297       rv = NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
   298     }
   299     else if(NSSCMSVS_BadSignature == si->verificationStatus) {
   300       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad signature\n"));
   301       rv = NS_ERROR_CMS_VERIFY_BAD_SIGNATURE;
   302     }
   303     else if(NSSCMSVS_DigestMismatch == si->verificationStatus) {
   304       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - digest mismatch\n"));
   305       rv = NS_ERROR_CMS_VERIFY_DIGEST_MISMATCH;
   306     }
   307     else if(NSSCMSVS_SignatureAlgorithmUnknown == si->verificationStatus) {
   308       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo unknown\n"));
   309       rv = NS_ERROR_CMS_VERIFY_UNKNOWN_ALGO;
   310     }
   311     else if(NSSCMSVS_SignatureAlgorithmUnsupported == si->verificationStatus) {
   312       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo not supported\n"));
   313       rv = NS_ERROR_CMS_VERIFY_UNSUPPORTED_ALGO;
   314     }
   315     else if(NSSCMSVS_MalformedSignature == si->verificationStatus) {
   316       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - malformed signature\n"));
   317       rv = NS_ERROR_CMS_VERIFY_MALFORMED_SIGNATURE;
   318     }
   320     goto loser;
   321   }
   323   // Save the profile. Note that save import failure is not a signature verification failure. //
   324   if (NSS_SMIMESignerInfo_SaveSMIMEProfile(si) != SECSuccess) {
   325     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to save smime profile\n"));
   326   }
   328   rv = NS_OK;
   329 loser:
   330   return rv;
   331 }
   333 NS_IMETHODIMP nsCMSMessage::AsyncVerifySignature(
   334                               nsISMimeVerificationListener *aListener)
   335 {
   336   return CommonAsyncVerifySignature(aListener, nullptr, 0);
   337 }
   339 NS_IMETHODIMP nsCMSMessage::AsyncVerifyDetachedSignature(
   340                               nsISMimeVerificationListener *aListener,
   341                               unsigned char* aDigestData, uint32_t aDigestDataLen)
   342 {
   343   if (!aDigestData || !aDigestDataLen)
   344     return NS_ERROR_FAILURE;
   346   return CommonAsyncVerifySignature(aListener, aDigestData, aDigestDataLen);
   347 }
   349 nsresult nsCMSMessage::CommonAsyncVerifySignature(nsISMimeVerificationListener *aListener,
   350                                                   unsigned char* aDigestData, uint32_t aDigestDataLen)
   351 {
   352   nsSMimeVerificationJob *job = new nsSMimeVerificationJob;
   354   if (aDigestData)
   355   {
   356     job->digest_data = new unsigned char[aDigestDataLen];
   357     memcpy(job->digest_data, aDigestData, aDigestDataLen);
   358   }
   359   else
   360   {
   361     job->digest_data = nullptr;
   362   }
   364   job->digest_len = aDigestDataLen;
   365   job->mMessage = this;
   366   job->mListener = aListener;
   368   nsresult rv = nsCertVerificationThread::addJob(job);
   369   if (NS_FAILED(rv))
   370     delete job;
   372   return rv;
   373 }
   375 class nsZeroTerminatedCertArray : public nsNSSShutDownObject
   376 {
   377 public:
   378   nsZeroTerminatedCertArray()
   379   :mCerts(nullptr), mPoolp(nullptr), mSize(0)
   380   {
   381   }
   383   ~nsZeroTerminatedCertArray()
   384   {
   385     nsNSSShutDownPreventionLock locker;
   386     if (isAlreadyShutDown()) {
   387       return;
   388     }
   389     destructorSafeDestroyNSSReference();
   390     shutdown(calledFromObject);
   391   }
   393   void virtualDestroyNSSReference()
   394   {
   395     destructorSafeDestroyNSSReference();
   396   }
   398   void destructorSafeDestroyNSSReference()
   399   {
   400     if (mCerts)
   401     {
   402       for (uint32_t i=0; i < mSize; i++) {
   403         if (mCerts[i]) {
   404           CERT_DestroyCertificate(mCerts[i]);
   405         }
   406       }
   407     }
   409     if (mPoolp)
   410       PORT_FreeArena(mPoolp, false);
   411   }
   413   bool allocate(uint32_t count)
   414   {
   415     // only allow allocation once
   416     if (mPoolp)
   417       return false;
   419     mSize = count;
   421     if (!mSize)
   422       return false;
   424     mPoolp = PORT_NewArena(1024);
   425     if (!mPoolp)
   426       return false;
   428     mCerts = (CERTCertificate**)PORT_ArenaZAlloc(
   429       mPoolp, (count+1)*sizeof(CERTCertificate*));
   431     if (!mCerts)
   432       return false;
   434     // null array, including zero termination
   435     for (uint32_t i = 0; i < count+1; i++) {
   436       mCerts[i] = nullptr;
   437     }
   439     return true;
   440   }
   442   void set(uint32_t i, CERTCertificate *c)
   443   {
   444     nsNSSShutDownPreventionLock locker;
   445     if (isAlreadyShutDown())
   446       return;
   448     if (i >= mSize)
   449       return;
   451     if (mCerts[i]) {
   452       CERT_DestroyCertificate(mCerts[i]);
   453     }
   455     mCerts[i] = CERT_DupCertificate(c);
   456   }
   458   CERTCertificate *get(uint32_t i)
   459   {
   460     nsNSSShutDownPreventionLock locker;
   461     if (isAlreadyShutDown())
   462       return nullptr;
   464     if (i >= mSize)
   465       return nullptr;
   467     return CERT_DupCertificate(mCerts[i]);
   468   }
   470   CERTCertificate **getRawArray()
   471   {
   472     nsNSSShutDownPreventionLock locker;
   473     if (isAlreadyShutDown())
   474       return nullptr;
   476     return mCerts;
   477   }
   479 private:
   480   CERTCertificate **mCerts;
   481   PLArenaPool *mPoolp;
   482   uint32_t mSize;
   483 };
   485 NS_IMETHODIMP nsCMSMessage::CreateEncrypted(nsIArray * aRecipientCerts)
   486 {
   487   nsNSSShutDownPreventionLock locker;
   488   if (isAlreadyShutDown())
   489     return NS_ERROR_NOT_AVAILABLE;
   491   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted\n"));
   492   NSSCMSContentInfo *cinfo;
   493   NSSCMSEnvelopedData *envd;
   494   NSSCMSRecipientInfo *recipientInfo;
   495   nsZeroTerminatedCertArray recipientCerts;
   496   SECOidTag bulkAlgTag;
   497   int keySize;
   498   uint32_t i;
   499   nsCOMPtr<nsIX509Cert2> nssRecipientCert;
   500   nsresult rv = NS_ERROR_FAILURE;
   502   // Check the recipient certificates //
   503   uint32_t recipientCertCount;
   504   aRecipientCerts->GetLength(&recipientCertCount);
   505   PR_ASSERT(recipientCertCount > 0);
   507   if (!recipientCerts.allocate(recipientCertCount)) {
   508     goto loser;
   509   }
   511   for (i=0; i<recipientCertCount; i++) {
   512     nsCOMPtr<nsIX509Cert> x509cert = do_QueryElementAt(aRecipientCerts, i);
   514     nssRecipientCert = do_QueryInterface(x509cert);
   516     if (!nssRecipientCert)
   517       return NS_ERROR_FAILURE;
   519     mozilla::pkix::ScopedCERTCertificate c(nssRecipientCert->GetCert());
   520     recipientCerts.set(i, c.get());
   521   }
   523   // Find a bulk key algorithm //
   524   if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientCerts.getRawArray(), &bulkAlgTag,
   525                                             &keySize) != SECSuccess) {
   526     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't find bulk alg for recipients\n"));
   527     rv = NS_ERROR_CMS_ENCRYPT_NO_BULK_ALG;
   528     goto loser;
   529   }
   531   m_cmsMsg = NSS_CMSMessage_Create(nullptr);
   532   if (!m_cmsMsg) {
   533     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create new cms message\n"));
   534     rv = NS_ERROR_OUT_OF_MEMORY;
   535     goto loser;
   536   }
   538   if ((envd = NSS_CMSEnvelopedData_Create(m_cmsMsg, bulkAlgTag, keySize)) == nullptr) {
   539     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create enveloped data\n"));
   540     goto loser;
   541   }
   543   cinfo = NSS_CMSMessage_GetContentInfo(m_cmsMsg);
   544   if (NSS_CMSContentInfo_SetContent_EnvelopedData(m_cmsMsg, cinfo, envd) != SECSuccess) {
   545     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create content enveloped data\n"));
   546     goto loser;
   547   }
   549   cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
   550   if (NSS_CMSContentInfo_SetContent_Data(m_cmsMsg, cinfo, nullptr, false) != SECSuccess) {
   551     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't set content data\n"));
   552     goto loser;
   553   }
   555   // Create and attach recipient information //
   556   for (i=0; i < recipientCertCount; i++) {
   557     mozilla::pkix::ScopedCERTCertificate rc(recipientCerts.get(i));
   558     if ((recipientInfo = NSS_CMSRecipientInfo_Create(m_cmsMsg, rc.get())) == nullptr) {
   559       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create recipient info\n"));
   560       goto loser;
   561     }
   562     if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientInfo) != SECSuccess) {
   563       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't add recipient info\n"));
   564       goto loser;
   565     }
   566   }
   568   return NS_OK;
   569 loser:
   570   if (m_cmsMsg) {
   571     NSS_CMSMessage_Destroy(m_cmsMsg);
   572     m_cmsMsg = nullptr;
   573   }
   575   return rv;
   576 }
   578 NS_IMETHODIMP nsCMSMessage::CreateSigned(nsIX509Cert* aSigningCert, nsIX509Cert* aEncryptCert, unsigned char* aDigestData, uint32_t aDigestDataLen)
   579 {
   580   nsNSSShutDownPreventionLock locker;
   581   if (isAlreadyShutDown())
   582     return NS_ERROR_NOT_AVAILABLE;
   584   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned\n"));
   585   NSSCMSContentInfo *cinfo;
   586   NSSCMSSignedData *sigd;
   587   NSSCMSSignerInfo *signerinfo;
   588   mozilla::pkix::ScopedCERTCertificate scert;
   589   mozilla::pkix::ScopedCERTCertificate ecert;
   590   nsCOMPtr<nsIX509Cert2> aSigningCert2 = do_QueryInterface(aSigningCert);
   591   nsresult rv = NS_ERROR_FAILURE;
   593   /* Get the certs */
   594   if (aSigningCert2) {
   595     scert = aSigningCert2->GetCert();
   596   }
   597   if (!scert) {
   598     return NS_ERROR_FAILURE;
   599   }
   601   if (aEncryptCert) {
   602     nsCOMPtr<nsIX509Cert2> aEncryptCert2 = do_QueryInterface(aEncryptCert);
   603     if (aEncryptCert2) {
   604       ecert = aEncryptCert2->GetCert();
   605     }
   606   }
   608   /*
   609    * create the message object
   610    */
   611   m_cmsMsg = NSS_CMSMessage_Create(nullptr); /* create a message on its own pool */
   612   if (!m_cmsMsg) {
   613     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create new message\n"));
   614     rv = NS_ERROR_OUT_OF_MEMORY;
   615     goto loser;
   616   }
   618   /*
   619    * build chain of objects: message->signedData->data
   620    */
   621   if ((sigd = NSS_CMSSignedData_Create(m_cmsMsg)) == nullptr) {
   622     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signed data\n"));
   623     goto loser;
   624   }
   625   cinfo = NSS_CMSMessage_GetContentInfo(m_cmsMsg);
   626   if (NSS_CMSContentInfo_SetContent_SignedData(m_cmsMsg, cinfo, sigd) 
   627           != SECSuccess) {
   628     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set content signed data\n"));
   629     goto loser;
   630   }
   632   cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
   634   /* we're always passing data in and detaching optionally */
   635   if (NSS_CMSContentInfo_SetContent_Data(m_cmsMsg, cinfo, nullptr, true) 
   636           != SECSuccess) {
   637     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set content data\n"));
   638     goto loser;
   639   }
   641   /* 
   642    * create & attach signer information
   643    */
   644   if ((signerinfo = NSS_CMSSignerInfo_Create(m_cmsMsg, scert.get(), SEC_OID_SHA1)) 
   645           == nullptr) {
   646     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signer info\n"));
   647     goto loser;
   648   }
   650   /* we want the cert chain included for this one */
   651   if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, 
   652                                        certUsageEmailSigner) 
   653           != SECSuccess) {
   654     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't include signer cert chain\n"));
   655     goto loser;
   656   }
   658   if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) 
   659 	      != SECSuccess) {
   660     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add signing time\n"));
   661     goto loser;
   662   }
   664   if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
   665     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime caps\n"));
   666     goto loser;
   667   }
   669   if (ecert) {
   670     if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ecert.get(),
   671 	                                      CERT_GetDefaultCertDB())
   672 	  != SECSuccess) {
   673       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime enc key prefs\n"));
   674       goto loser;
   675     }
   677     if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ecert.get(),
   678 	                                        CERT_GetDefaultCertDB())
   679 	  != SECSuccess) {
   680       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add MS smime enc key prefs\n"));
   681       goto loser;
   682     }
   684     // If signing and encryption cert are identical, don't add it twice.
   685     bool addEncryptionCert =
   686       (ecert && (!scert || !CERT_CompareCerts(ecert.get(), scert.get())));
   688     if (addEncryptionCert &&
   689         NSS_CMSSignedData_AddCertificate(sigd, ecert.get()) != SECSuccess) {
   690       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add own encryption certificate\n"));
   691       goto loser;
   692     }
   693   }
   695   if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
   696     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add signer info\n"));
   697     goto loser;
   698   }
   700   // Finally, add the pre-computed digest if passed in
   701   if (aDigestData) {
   702     SECItem digest;
   704     digest.data = aDigestData;
   705     digest.len = aDigestDataLen;
   707     if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) {
   708       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set digest value\n"));
   709       goto loser;
   710     }
   711   }
   713   return NS_OK;
   714 loser:
   715   if (m_cmsMsg) {
   716     NSS_CMSMessage_Destroy(m_cmsMsg);
   717     m_cmsMsg = nullptr;
   718   }
   719   return rv;
   720 }
   722 NS_IMPL_ISUPPORTS(nsCMSDecoder, nsICMSDecoder)
   724 nsCMSDecoder::nsCMSDecoder()
   725 : m_dcx(nullptr)
   726 {
   727 }
   729 nsCMSDecoder::~nsCMSDecoder()
   730 {
   731   nsNSSShutDownPreventionLock locker;
   732   if (isAlreadyShutDown()) {
   733     return;
   734   }
   735   destructorSafeDestroyNSSReference();
   736   shutdown(calledFromObject);
   737 }
   739 void nsCMSDecoder::virtualDestroyNSSReference()
   740 {
   741   destructorSafeDestroyNSSReference();
   742 }
   744 void nsCMSDecoder::destructorSafeDestroyNSSReference()
   745 {
   746   if (m_dcx) {
   747     NSS_CMSDecoder_Cancel(m_dcx);
   748     m_dcx = nullptr;
   749   }
   750 }
   752 /* void start (in NSSCMSContentCallback cb, in voidPtr arg); */
   753 NS_IMETHODIMP nsCMSDecoder::Start(NSSCMSContentCallback cb, void * arg)
   754 {
   755   nsNSSShutDownPreventionLock locker;
   756   if (isAlreadyShutDown())
   757     return NS_ERROR_NOT_AVAILABLE;
   759   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Start\n"));
   760   m_ctx = new PipUIContext();
   762   m_dcx = NSS_CMSDecoder_Start(0, cb, arg, 0, m_ctx, 0, 0);
   763   if (!m_dcx) {
   764     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Start - can't start decoder\n"));
   765     return NS_ERROR_FAILURE;
   766   }
   767   return NS_OK;
   768 }
   770 /* void update (in string bug, in long len); */
   771 NS_IMETHODIMP nsCMSDecoder::Update(const char *buf, int32_t len)
   772 {
   773   nsNSSShutDownPreventionLock locker;
   774   if (isAlreadyShutDown())
   775     return NS_ERROR_NOT_AVAILABLE;
   777   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Update\n"));
   778   NSS_CMSDecoder_Update(m_dcx, (char *)buf, len);
   779   return NS_OK;
   780 }
   782 /* void finish (); */
   783 NS_IMETHODIMP nsCMSDecoder::Finish(nsICMSMessage ** aCMSMsg)
   784 {
   785   nsNSSShutDownPreventionLock locker;
   786   if (isAlreadyShutDown())
   787     return NS_ERROR_NOT_AVAILABLE;
   789   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Finish\n"));
   790   NSSCMSMessage *cmsMsg;
   791   cmsMsg = NSS_CMSDecoder_Finish(m_dcx);
   792   m_dcx = nullptr;
   793   if (cmsMsg) {
   794     nsCMSMessage *obj = new nsCMSMessage(cmsMsg);
   795     // The NSS object cmsMsg still carries a reference to the context
   796     // we gave it on construction.
   797     // Make sure the context will live long enough.
   798     obj->referenceContext(m_ctx);
   799     *aCMSMsg = obj;
   800     NS_ADDREF(*aCMSMsg);
   801   }
   802   return NS_OK;
   803 }
   805 NS_IMPL_ISUPPORTS(nsCMSEncoder, nsICMSEncoder)
   807 nsCMSEncoder::nsCMSEncoder()
   808 : m_ecx(nullptr)
   809 {
   810 }
   812 nsCMSEncoder::~nsCMSEncoder()
   813 {
   814   nsNSSShutDownPreventionLock locker;
   815   if (isAlreadyShutDown()) {
   816     return;
   817   }
   818   destructorSafeDestroyNSSReference();
   819   shutdown(calledFromObject);
   820 }
   822 void nsCMSEncoder::virtualDestroyNSSReference()
   823 {
   824   destructorSafeDestroyNSSReference();
   825 }
   827 void nsCMSEncoder::destructorSafeDestroyNSSReference()
   828 {
   829   if (m_ecx)
   830     NSS_CMSEncoder_Cancel(m_ecx);
   831 }
   833 /* void start (); */
   834 NS_IMETHODIMP nsCMSEncoder::Start(nsICMSMessage *aMsg, NSSCMSContentCallback cb, void * arg)
   835 {
   836   nsNSSShutDownPreventionLock locker;
   837   if (isAlreadyShutDown())
   838     return NS_ERROR_NOT_AVAILABLE;
   840   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Start\n"));
   841   nsCMSMessage *cmsMsg = static_cast<nsCMSMessage*>(aMsg);
   842   m_ctx = new PipUIContext();
   844   m_ecx = NSS_CMSEncoder_Start(cmsMsg->getCMS(), cb, arg, 0, 0, 0, m_ctx, 0, 0, 0, 0);
   845   if (!m_ecx) {
   846     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Start - can't start encoder\n"));
   847     return NS_ERROR_FAILURE;
   848   }
   849   return NS_OK;
   850 }
   852 /* void update (in string aBuf, in long aLen); */
   853 NS_IMETHODIMP nsCMSEncoder::Update(const char *aBuf, int32_t aLen)
   854 {
   855   nsNSSShutDownPreventionLock locker;
   856   if (isAlreadyShutDown())
   857     return NS_ERROR_NOT_AVAILABLE;
   859   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Update\n"));
   860   if (!m_ecx || NSS_CMSEncoder_Update(m_ecx, aBuf, aLen) != SECSuccess) {
   861     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Update - can't update encoder\n"));
   862     return NS_ERROR_FAILURE;
   863   }
   864   return NS_OK;
   865 }
   867 /* void finish (); */
   868 NS_IMETHODIMP nsCMSEncoder::Finish()
   869 {
   870   nsNSSShutDownPreventionLock locker;
   871   if (isAlreadyShutDown())
   872     return NS_ERROR_NOT_AVAILABLE;
   874   nsresult rv = NS_OK;
   875   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Finish\n"));
   876   if (!m_ecx || NSS_CMSEncoder_Finish(m_ecx) != SECSuccess) {
   877     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Finish - can't finish encoder\n"));
   878     rv = NS_ERROR_FAILURE;
   879   }
   880   m_ecx = nullptr;
   881   return rv;
   882 }
   884 /* void encode (in nsICMSMessage aMsg); */
   885 NS_IMETHODIMP nsCMSEncoder::Encode(nsICMSMessage *aMsg)
   886 {
   887   nsNSSShutDownPreventionLock locker;
   888   if (isAlreadyShutDown())
   889     return NS_ERROR_NOT_AVAILABLE;
   891   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Encode\n"));
   892   return NS_ERROR_NOT_IMPLEMENTED;
   893 }

mercurial