1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/ssl/src/nsCMS.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,893 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsCMS.h" 1.10 + 1.11 +#include "CertVerifier.h" 1.12 +#include "pkix/pkixtypes.h" 1.13 +#include "nsISupports.h" 1.14 +#include "nsNSSHelper.h" 1.15 +#include "nsNSSCertificate.h" 1.16 +#include "smime.h" 1.17 +#include "cms.h" 1.18 +#include "nsICMSMessageErrors.h" 1.19 +#include "nsIArray.h" 1.20 +#include "nsArrayUtils.h" 1.21 +#include "nsCertVerificationThread.h" 1.22 + 1.23 +#include "prlog.h" 1.24 + 1.25 +using namespace mozilla; 1.26 +using namespace mozilla::psm; 1.27 + 1.28 +#ifdef PR_LOGGING 1.29 +extern PRLogModuleInfo* gPIPNSSLog; 1.30 +#endif 1.31 + 1.32 +using namespace mozilla; 1.33 + 1.34 +NS_IMPL_ISUPPORTS(nsCMSMessage, nsICMSMessage, nsICMSMessage2) 1.35 + 1.36 +nsCMSMessage::nsCMSMessage() 1.37 +{ 1.38 + m_cmsMsg = nullptr; 1.39 +} 1.40 +nsCMSMessage::nsCMSMessage(NSSCMSMessage *aCMSMsg) 1.41 +{ 1.42 + m_cmsMsg = aCMSMsg; 1.43 +} 1.44 + 1.45 +nsCMSMessage::~nsCMSMessage() 1.46 +{ 1.47 + nsNSSShutDownPreventionLock locker; 1.48 + if (isAlreadyShutDown()) { 1.49 + return; 1.50 + } 1.51 + destructorSafeDestroyNSSReference(); 1.52 + shutdown(calledFromObject); 1.53 +} 1.54 + 1.55 +void nsCMSMessage::virtualDestroyNSSReference() 1.56 +{ 1.57 + destructorSafeDestroyNSSReference(); 1.58 +} 1.59 + 1.60 +void nsCMSMessage::destructorSafeDestroyNSSReference() 1.61 +{ 1.62 + if (m_cmsMsg) { 1.63 + NSS_CMSMessage_Destroy(m_cmsMsg); 1.64 + } 1.65 +} 1.66 + 1.67 +NS_IMETHODIMP nsCMSMessage::VerifySignature() 1.68 +{ 1.69 + return CommonVerifySignature(nullptr, 0); 1.70 +} 1.71 + 1.72 +NSSCMSSignerInfo* nsCMSMessage::GetTopLevelSignerInfo() 1.73 +{ 1.74 + nsNSSShutDownPreventionLock locker; 1.75 + if (isAlreadyShutDown()) 1.76 + return nullptr; 1.77 + 1.78 + if (!m_cmsMsg) 1.79 + return nullptr; 1.80 + 1.81 + if (!NSS_CMSMessage_IsSigned(m_cmsMsg)) 1.82 + return nullptr; 1.83 + 1.84 + NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0); 1.85 + if (!cinfo) 1.86 + return nullptr; 1.87 + 1.88 + NSSCMSSignedData *sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo); 1.89 + if (!sigd) 1.90 + return nullptr; 1.91 + 1.92 + PR_ASSERT(NSS_CMSSignedData_SignerInfoCount(sigd) > 0); 1.93 + return NSS_CMSSignedData_GetSignerInfo(sigd, 0); 1.94 +} 1.95 + 1.96 +NS_IMETHODIMP nsCMSMessage::GetSignerEmailAddress(char * * aEmail) 1.97 +{ 1.98 + nsNSSShutDownPreventionLock locker; 1.99 + if (isAlreadyShutDown()) 1.100 + return NS_ERROR_NOT_AVAILABLE; 1.101 + 1.102 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerEmailAddress\n")); 1.103 + NS_ENSURE_ARG(aEmail); 1.104 + 1.105 + NSSCMSSignerInfo *si = GetTopLevelSignerInfo(); 1.106 + if (!si) 1.107 + return NS_ERROR_FAILURE; 1.108 + 1.109 + *aEmail = NSS_CMSSignerInfo_GetSignerEmailAddress(si); 1.110 + return NS_OK; 1.111 +} 1.112 + 1.113 +NS_IMETHODIMP nsCMSMessage::GetSignerCommonName(char ** aName) 1.114 +{ 1.115 + nsNSSShutDownPreventionLock locker; 1.116 + if (isAlreadyShutDown()) 1.117 + return NS_ERROR_NOT_AVAILABLE; 1.118 + 1.119 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCommonName\n")); 1.120 + NS_ENSURE_ARG(aName); 1.121 + 1.122 + NSSCMSSignerInfo *si = GetTopLevelSignerInfo(); 1.123 + if (!si) 1.124 + return NS_ERROR_FAILURE; 1.125 + 1.126 + *aName = NSS_CMSSignerInfo_GetSignerCommonName(si); 1.127 + return NS_OK; 1.128 +} 1.129 + 1.130 +NS_IMETHODIMP nsCMSMessage::ContentIsEncrypted(bool *isEncrypted) 1.131 +{ 1.132 + nsNSSShutDownPreventionLock locker; 1.133 + if (isAlreadyShutDown()) 1.134 + return NS_ERROR_NOT_AVAILABLE; 1.135 + 1.136 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::ContentIsEncrypted\n")); 1.137 + NS_ENSURE_ARG(isEncrypted); 1.138 + 1.139 + if (!m_cmsMsg) 1.140 + return NS_ERROR_FAILURE; 1.141 + 1.142 + *isEncrypted = NSS_CMSMessage_IsEncrypted(m_cmsMsg); 1.143 + 1.144 + return NS_OK; 1.145 +} 1.146 + 1.147 +NS_IMETHODIMP nsCMSMessage::ContentIsSigned(bool *isSigned) 1.148 +{ 1.149 + nsNSSShutDownPreventionLock locker; 1.150 + if (isAlreadyShutDown()) 1.151 + return NS_ERROR_NOT_AVAILABLE; 1.152 + 1.153 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::ContentIsSigned\n")); 1.154 + NS_ENSURE_ARG(isSigned); 1.155 + 1.156 + if (!m_cmsMsg) 1.157 + return NS_ERROR_FAILURE; 1.158 + 1.159 + *isSigned = NSS_CMSMessage_IsSigned(m_cmsMsg); 1.160 + 1.161 + return NS_OK; 1.162 +} 1.163 + 1.164 +NS_IMETHODIMP nsCMSMessage::GetSignerCert(nsIX509Cert **scert) 1.165 +{ 1.166 + nsNSSShutDownPreventionLock locker; 1.167 + if (isAlreadyShutDown()) 1.168 + return NS_ERROR_NOT_AVAILABLE; 1.169 + 1.170 + NSSCMSSignerInfo *si = GetTopLevelSignerInfo(); 1.171 + if (!si) 1.172 + return NS_ERROR_FAILURE; 1.173 + 1.174 + if (si->cert) { 1.175 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCert got signer cert\n")); 1.176 + 1.177 + *scert = nsNSSCertificate::Create(si->cert); 1.178 + if (*scert) { 1.179 + (*scert)->AddRef(); 1.180 + } 1.181 + } 1.182 + else { 1.183 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCert no signer cert, do we have a cert list? %s\n", 1.184 + (si->certList ? "yes" : "no") )); 1.185 + 1.186 + *scert = nullptr; 1.187 + } 1.188 + 1.189 + return NS_OK; 1.190 +} 1.191 + 1.192 +NS_IMETHODIMP nsCMSMessage::GetEncryptionCert(nsIX509Cert **ecert) 1.193 +{ 1.194 + nsNSSShutDownPreventionLock locker; 1.195 + if (isAlreadyShutDown()) 1.196 + return NS_ERROR_NOT_AVAILABLE; 1.197 + 1.198 + return NS_ERROR_NOT_IMPLEMENTED; 1.199 +} 1.200 + 1.201 +NS_IMETHODIMP nsCMSMessage::VerifyDetachedSignature(unsigned char* aDigestData, uint32_t aDigestDataLen) 1.202 +{ 1.203 + if (!aDigestData || !aDigestDataLen) 1.204 + return NS_ERROR_FAILURE; 1.205 + 1.206 + return CommonVerifySignature(aDigestData, aDigestDataLen); 1.207 +} 1.208 + 1.209 +nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, uint32_t aDigestDataLen) 1.210 +{ 1.211 + nsNSSShutDownPreventionLock locker; 1.212 + if (isAlreadyShutDown()) 1.213 + return NS_ERROR_NOT_AVAILABLE; 1.214 + 1.215 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature, content level count %d\n", NSS_CMSMessage_ContentLevelCount(m_cmsMsg))); 1.216 + NSSCMSContentInfo *cinfo = nullptr; 1.217 + NSSCMSSignedData *sigd = nullptr; 1.218 + NSSCMSSignerInfo *si; 1.219 + int32_t nsigners; 1.220 + RefPtr<SharedCertVerifier> certVerifier; 1.221 + nsresult rv = NS_ERROR_FAILURE; 1.222 + 1.223 + if (!NSS_CMSMessage_IsSigned(m_cmsMsg)) { 1.224 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - not signed\n")); 1.225 + return NS_ERROR_CMS_VERIFY_NOT_SIGNED; 1.226 + } 1.227 + 1.228 + cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0); 1.229 + if (cinfo) { 1.230 + // I don't like this hard cast. We should check in some way, that we really have this type. 1.231 + sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo); 1.232 + } 1.233 + 1.234 + if (!sigd) { 1.235 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - no content info\n")); 1.236 + rv = NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; 1.237 + goto loser; 1.238 + } 1.239 + 1.240 + if (aDigestData && aDigestDataLen) 1.241 + { 1.242 + SECItem digest; 1.243 + digest.data = aDigestData; 1.244 + digest.len = aDigestDataLen; 1.245 + 1.246 + if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) { 1.247 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad digest\n")); 1.248 + rv = NS_ERROR_CMS_VERIFY_BAD_DIGEST; 1.249 + goto loser; 1.250 + } 1.251 + } 1.252 + 1.253 + // Import certs. Note that import failure is not a signature verification failure. // 1.254 + if (NSS_CMSSignedData_ImportCerts(sigd, CERT_GetDefaultCertDB(), certUsageEmailRecipient, true) != SECSuccess) { 1.255 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not import certs\n")); 1.256 + } 1.257 + 1.258 + nsigners = NSS_CMSSignedData_SignerInfoCount(sigd); 1.259 + PR_ASSERT(nsigners > 0); 1.260 + NS_ENSURE_TRUE(nsigners > 0, NS_ERROR_UNEXPECTED); 1.261 + si = NSS_CMSSignedData_GetSignerInfo(sigd, 0); 1.262 + 1.263 + // See bug 324474. We want to make sure the signing cert is 1.264 + // still valid at the current time. 1.265 + 1.266 + certVerifier = GetDefaultCertVerifier(); 1.267 + NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); 1.268 + 1.269 + { 1.270 + SECStatus srv = certVerifier->VerifyCert(si->cert, 1.271 + certificateUsageEmailSigner, 1.272 + PR_Now(), nullptr /*XXX pinarg*/, 1.273 + nullptr /*hostname*/); 1.274 + if (srv != SECSuccess) { 1.275 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, 1.276 + ("nsCMSMessage::CommonVerifySignature - signing cert not trusted now\n")); 1.277 + rv = NS_ERROR_CMS_VERIFY_UNTRUSTED; 1.278 + goto loser; 1.279 + } 1.280 + } 1.281 + 1.282 + // We verify the first signer info, only // 1.283 + if (NSS_CMSSignedData_VerifySignerInfo(sigd, 0, CERT_GetDefaultCertDB(), certUsageEmailSigner) != SECSuccess) { 1.284 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to verify signature\n")); 1.285 + 1.286 + if (NSSCMSVS_SigningCertNotFound == si->verificationStatus) { 1.287 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not found\n")); 1.288 + rv = NS_ERROR_CMS_VERIFY_NOCERT; 1.289 + } 1.290 + else if(NSSCMSVS_SigningCertNotTrusted == si->verificationStatus) { 1.291 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted at signing time\n")); 1.292 + rv = NS_ERROR_CMS_VERIFY_UNTRUSTED; 1.293 + } 1.294 + else if(NSSCMSVS_Unverified == si->verificationStatus) { 1.295 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not verify\n")); 1.296 + rv = NS_ERROR_CMS_VERIFY_ERROR_UNVERIFIED; 1.297 + } 1.298 + else if(NSSCMSVS_ProcessingError == si->verificationStatus) { 1.299 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - processing error\n")); 1.300 + rv = NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; 1.301 + } 1.302 + else if(NSSCMSVS_BadSignature == si->verificationStatus) { 1.303 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad signature\n")); 1.304 + rv = NS_ERROR_CMS_VERIFY_BAD_SIGNATURE; 1.305 + } 1.306 + else if(NSSCMSVS_DigestMismatch == si->verificationStatus) { 1.307 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - digest mismatch\n")); 1.308 + rv = NS_ERROR_CMS_VERIFY_DIGEST_MISMATCH; 1.309 + } 1.310 + else if(NSSCMSVS_SignatureAlgorithmUnknown == si->verificationStatus) { 1.311 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo unknown\n")); 1.312 + rv = NS_ERROR_CMS_VERIFY_UNKNOWN_ALGO; 1.313 + } 1.314 + else if(NSSCMSVS_SignatureAlgorithmUnsupported == si->verificationStatus) { 1.315 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo not supported\n")); 1.316 + rv = NS_ERROR_CMS_VERIFY_UNSUPPORTED_ALGO; 1.317 + } 1.318 + else if(NSSCMSVS_MalformedSignature == si->verificationStatus) { 1.319 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - malformed signature\n")); 1.320 + rv = NS_ERROR_CMS_VERIFY_MALFORMED_SIGNATURE; 1.321 + } 1.322 + 1.323 + goto loser; 1.324 + } 1.325 + 1.326 + // Save the profile. Note that save import failure is not a signature verification failure. // 1.327 + if (NSS_SMIMESignerInfo_SaveSMIMEProfile(si) != SECSuccess) { 1.328 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to save smime profile\n")); 1.329 + } 1.330 + 1.331 + rv = NS_OK; 1.332 +loser: 1.333 + return rv; 1.334 +} 1.335 + 1.336 +NS_IMETHODIMP nsCMSMessage::AsyncVerifySignature( 1.337 + nsISMimeVerificationListener *aListener) 1.338 +{ 1.339 + return CommonAsyncVerifySignature(aListener, nullptr, 0); 1.340 +} 1.341 + 1.342 +NS_IMETHODIMP nsCMSMessage::AsyncVerifyDetachedSignature( 1.343 + nsISMimeVerificationListener *aListener, 1.344 + unsigned char* aDigestData, uint32_t aDigestDataLen) 1.345 +{ 1.346 + if (!aDigestData || !aDigestDataLen) 1.347 + return NS_ERROR_FAILURE; 1.348 + 1.349 + return CommonAsyncVerifySignature(aListener, aDigestData, aDigestDataLen); 1.350 +} 1.351 + 1.352 +nsresult nsCMSMessage::CommonAsyncVerifySignature(nsISMimeVerificationListener *aListener, 1.353 + unsigned char* aDigestData, uint32_t aDigestDataLen) 1.354 +{ 1.355 + nsSMimeVerificationJob *job = new nsSMimeVerificationJob; 1.356 + 1.357 + if (aDigestData) 1.358 + { 1.359 + job->digest_data = new unsigned char[aDigestDataLen]; 1.360 + memcpy(job->digest_data, aDigestData, aDigestDataLen); 1.361 + } 1.362 + else 1.363 + { 1.364 + job->digest_data = nullptr; 1.365 + } 1.366 + 1.367 + job->digest_len = aDigestDataLen; 1.368 + job->mMessage = this; 1.369 + job->mListener = aListener; 1.370 + 1.371 + nsresult rv = nsCertVerificationThread::addJob(job); 1.372 + if (NS_FAILED(rv)) 1.373 + delete job; 1.374 + 1.375 + return rv; 1.376 +} 1.377 + 1.378 +class nsZeroTerminatedCertArray : public nsNSSShutDownObject 1.379 +{ 1.380 +public: 1.381 + nsZeroTerminatedCertArray() 1.382 + :mCerts(nullptr), mPoolp(nullptr), mSize(0) 1.383 + { 1.384 + } 1.385 + 1.386 + ~nsZeroTerminatedCertArray() 1.387 + { 1.388 + nsNSSShutDownPreventionLock locker; 1.389 + if (isAlreadyShutDown()) { 1.390 + return; 1.391 + } 1.392 + destructorSafeDestroyNSSReference(); 1.393 + shutdown(calledFromObject); 1.394 + } 1.395 + 1.396 + void virtualDestroyNSSReference() 1.397 + { 1.398 + destructorSafeDestroyNSSReference(); 1.399 + } 1.400 + 1.401 + void destructorSafeDestroyNSSReference() 1.402 + { 1.403 + if (mCerts) 1.404 + { 1.405 + for (uint32_t i=0; i < mSize; i++) { 1.406 + if (mCerts[i]) { 1.407 + CERT_DestroyCertificate(mCerts[i]); 1.408 + } 1.409 + } 1.410 + } 1.411 + 1.412 + if (mPoolp) 1.413 + PORT_FreeArena(mPoolp, false); 1.414 + } 1.415 + 1.416 + bool allocate(uint32_t count) 1.417 + { 1.418 + // only allow allocation once 1.419 + if (mPoolp) 1.420 + return false; 1.421 + 1.422 + mSize = count; 1.423 + 1.424 + if (!mSize) 1.425 + return false; 1.426 + 1.427 + mPoolp = PORT_NewArena(1024); 1.428 + if (!mPoolp) 1.429 + return false; 1.430 + 1.431 + mCerts = (CERTCertificate**)PORT_ArenaZAlloc( 1.432 + mPoolp, (count+1)*sizeof(CERTCertificate*)); 1.433 + 1.434 + if (!mCerts) 1.435 + return false; 1.436 + 1.437 + // null array, including zero termination 1.438 + for (uint32_t i = 0; i < count+1; i++) { 1.439 + mCerts[i] = nullptr; 1.440 + } 1.441 + 1.442 + return true; 1.443 + } 1.444 + 1.445 + void set(uint32_t i, CERTCertificate *c) 1.446 + { 1.447 + nsNSSShutDownPreventionLock locker; 1.448 + if (isAlreadyShutDown()) 1.449 + return; 1.450 + 1.451 + if (i >= mSize) 1.452 + return; 1.453 + 1.454 + if (mCerts[i]) { 1.455 + CERT_DestroyCertificate(mCerts[i]); 1.456 + } 1.457 + 1.458 + mCerts[i] = CERT_DupCertificate(c); 1.459 + } 1.460 + 1.461 + CERTCertificate *get(uint32_t i) 1.462 + { 1.463 + nsNSSShutDownPreventionLock locker; 1.464 + if (isAlreadyShutDown()) 1.465 + return nullptr; 1.466 + 1.467 + if (i >= mSize) 1.468 + return nullptr; 1.469 + 1.470 + return CERT_DupCertificate(mCerts[i]); 1.471 + } 1.472 + 1.473 + CERTCertificate **getRawArray() 1.474 + { 1.475 + nsNSSShutDownPreventionLock locker; 1.476 + if (isAlreadyShutDown()) 1.477 + return nullptr; 1.478 + 1.479 + return mCerts; 1.480 + } 1.481 + 1.482 +private: 1.483 + CERTCertificate **mCerts; 1.484 + PLArenaPool *mPoolp; 1.485 + uint32_t mSize; 1.486 +}; 1.487 + 1.488 +NS_IMETHODIMP nsCMSMessage::CreateEncrypted(nsIArray * aRecipientCerts) 1.489 +{ 1.490 + nsNSSShutDownPreventionLock locker; 1.491 + if (isAlreadyShutDown()) 1.492 + return NS_ERROR_NOT_AVAILABLE; 1.493 + 1.494 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted\n")); 1.495 + NSSCMSContentInfo *cinfo; 1.496 + NSSCMSEnvelopedData *envd; 1.497 + NSSCMSRecipientInfo *recipientInfo; 1.498 + nsZeroTerminatedCertArray recipientCerts; 1.499 + SECOidTag bulkAlgTag; 1.500 + int keySize; 1.501 + uint32_t i; 1.502 + nsCOMPtr<nsIX509Cert2> nssRecipientCert; 1.503 + nsresult rv = NS_ERROR_FAILURE; 1.504 + 1.505 + // Check the recipient certificates // 1.506 + uint32_t recipientCertCount; 1.507 + aRecipientCerts->GetLength(&recipientCertCount); 1.508 + PR_ASSERT(recipientCertCount > 0); 1.509 + 1.510 + if (!recipientCerts.allocate(recipientCertCount)) { 1.511 + goto loser; 1.512 + } 1.513 + 1.514 + for (i=0; i<recipientCertCount; i++) { 1.515 + nsCOMPtr<nsIX509Cert> x509cert = do_QueryElementAt(aRecipientCerts, i); 1.516 + 1.517 + nssRecipientCert = do_QueryInterface(x509cert); 1.518 + 1.519 + if (!nssRecipientCert) 1.520 + return NS_ERROR_FAILURE; 1.521 + 1.522 + mozilla::pkix::ScopedCERTCertificate c(nssRecipientCert->GetCert()); 1.523 + recipientCerts.set(i, c.get()); 1.524 + } 1.525 + 1.526 + // Find a bulk key algorithm // 1.527 + if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientCerts.getRawArray(), &bulkAlgTag, 1.528 + &keySize) != SECSuccess) { 1.529 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't find bulk alg for recipients\n")); 1.530 + rv = NS_ERROR_CMS_ENCRYPT_NO_BULK_ALG; 1.531 + goto loser; 1.532 + } 1.533 + 1.534 + m_cmsMsg = NSS_CMSMessage_Create(nullptr); 1.535 + if (!m_cmsMsg) { 1.536 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create new cms message\n")); 1.537 + rv = NS_ERROR_OUT_OF_MEMORY; 1.538 + goto loser; 1.539 + } 1.540 + 1.541 + if ((envd = NSS_CMSEnvelopedData_Create(m_cmsMsg, bulkAlgTag, keySize)) == nullptr) { 1.542 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create enveloped data\n")); 1.543 + goto loser; 1.544 + } 1.545 + 1.546 + cinfo = NSS_CMSMessage_GetContentInfo(m_cmsMsg); 1.547 + if (NSS_CMSContentInfo_SetContent_EnvelopedData(m_cmsMsg, cinfo, envd) != SECSuccess) { 1.548 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create content enveloped data\n")); 1.549 + goto loser; 1.550 + } 1.551 + 1.552 + cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd); 1.553 + if (NSS_CMSContentInfo_SetContent_Data(m_cmsMsg, cinfo, nullptr, false) != SECSuccess) { 1.554 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't set content data\n")); 1.555 + goto loser; 1.556 + } 1.557 + 1.558 + // Create and attach recipient information // 1.559 + for (i=0; i < recipientCertCount; i++) { 1.560 + mozilla::pkix::ScopedCERTCertificate rc(recipientCerts.get(i)); 1.561 + if ((recipientInfo = NSS_CMSRecipientInfo_Create(m_cmsMsg, rc.get())) == nullptr) { 1.562 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create recipient info\n")); 1.563 + goto loser; 1.564 + } 1.565 + if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientInfo) != SECSuccess) { 1.566 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't add recipient info\n")); 1.567 + goto loser; 1.568 + } 1.569 + } 1.570 + 1.571 + return NS_OK; 1.572 +loser: 1.573 + if (m_cmsMsg) { 1.574 + NSS_CMSMessage_Destroy(m_cmsMsg); 1.575 + m_cmsMsg = nullptr; 1.576 + } 1.577 + 1.578 + return rv; 1.579 +} 1.580 + 1.581 +NS_IMETHODIMP nsCMSMessage::CreateSigned(nsIX509Cert* aSigningCert, nsIX509Cert* aEncryptCert, unsigned char* aDigestData, uint32_t aDigestDataLen) 1.582 +{ 1.583 + nsNSSShutDownPreventionLock locker; 1.584 + if (isAlreadyShutDown()) 1.585 + return NS_ERROR_NOT_AVAILABLE; 1.586 + 1.587 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned\n")); 1.588 + NSSCMSContentInfo *cinfo; 1.589 + NSSCMSSignedData *sigd; 1.590 + NSSCMSSignerInfo *signerinfo; 1.591 + mozilla::pkix::ScopedCERTCertificate scert; 1.592 + mozilla::pkix::ScopedCERTCertificate ecert; 1.593 + nsCOMPtr<nsIX509Cert2> aSigningCert2 = do_QueryInterface(aSigningCert); 1.594 + nsresult rv = NS_ERROR_FAILURE; 1.595 + 1.596 + /* Get the certs */ 1.597 + if (aSigningCert2) { 1.598 + scert = aSigningCert2->GetCert(); 1.599 + } 1.600 + if (!scert) { 1.601 + return NS_ERROR_FAILURE; 1.602 + } 1.603 + 1.604 + if (aEncryptCert) { 1.605 + nsCOMPtr<nsIX509Cert2> aEncryptCert2 = do_QueryInterface(aEncryptCert); 1.606 + if (aEncryptCert2) { 1.607 + ecert = aEncryptCert2->GetCert(); 1.608 + } 1.609 + } 1.610 + 1.611 + /* 1.612 + * create the message object 1.613 + */ 1.614 + m_cmsMsg = NSS_CMSMessage_Create(nullptr); /* create a message on its own pool */ 1.615 + if (!m_cmsMsg) { 1.616 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create new message\n")); 1.617 + rv = NS_ERROR_OUT_OF_MEMORY; 1.618 + goto loser; 1.619 + } 1.620 + 1.621 + /* 1.622 + * build chain of objects: message->signedData->data 1.623 + */ 1.624 + if ((sigd = NSS_CMSSignedData_Create(m_cmsMsg)) == nullptr) { 1.625 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signed data\n")); 1.626 + goto loser; 1.627 + } 1.628 + cinfo = NSS_CMSMessage_GetContentInfo(m_cmsMsg); 1.629 + if (NSS_CMSContentInfo_SetContent_SignedData(m_cmsMsg, cinfo, sigd) 1.630 + != SECSuccess) { 1.631 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set content signed data\n")); 1.632 + goto loser; 1.633 + } 1.634 + 1.635 + cinfo = NSS_CMSSignedData_GetContentInfo(sigd); 1.636 + 1.637 + /* we're always passing data in and detaching optionally */ 1.638 + if (NSS_CMSContentInfo_SetContent_Data(m_cmsMsg, cinfo, nullptr, true) 1.639 + != SECSuccess) { 1.640 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set content data\n")); 1.641 + goto loser; 1.642 + } 1.643 + 1.644 + /* 1.645 + * create & attach signer information 1.646 + */ 1.647 + if ((signerinfo = NSS_CMSSignerInfo_Create(m_cmsMsg, scert.get(), SEC_OID_SHA1)) 1.648 + == nullptr) { 1.649 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signer info\n")); 1.650 + goto loser; 1.651 + } 1.652 + 1.653 + /* we want the cert chain included for this one */ 1.654 + if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, 1.655 + certUsageEmailSigner) 1.656 + != SECSuccess) { 1.657 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't include signer cert chain\n")); 1.658 + goto loser; 1.659 + } 1.660 + 1.661 + if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) 1.662 + != SECSuccess) { 1.663 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add signing time\n")); 1.664 + goto loser; 1.665 + } 1.666 + 1.667 + if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) { 1.668 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime caps\n")); 1.669 + goto loser; 1.670 + } 1.671 + 1.672 + if (ecert) { 1.673 + if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ecert.get(), 1.674 + CERT_GetDefaultCertDB()) 1.675 + != SECSuccess) { 1.676 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime enc key prefs\n")); 1.677 + goto loser; 1.678 + } 1.679 + 1.680 + if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ecert.get(), 1.681 + CERT_GetDefaultCertDB()) 1.682 + != SECSuccess) { 1.683 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add MS smime enc key prefs\n")); 1.684 + goto loser; 1.685 + } 1.686 + 1.687 + // If signing and encryption cert are identical, don't add it twice. 1.688 + bool addEncryptionCert = 1.689 + (ecert && (!scert || !CERT_CompareCerts(ecert.get(), scert.get()))); 1.690 + 1.691 + if (addEncryptionCert && 1.692 + NSS_CMSSignedData_AddCertificate(sigd, ecert.get()) != SECSuccess) { 1.693 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add own encryption certificate\n")); 1.694 + goto loser; 1.695 + } 1.696 + } 1.697 + 1.698 + if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) { 1.699 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add signer info\n")); 1.700 + goto loser; 1.701 + } 1.702 + 1.703 + // Finally, add the pre-computed digest if passed in 1.704 + if (aDigestData) { 1.705 + SECItem digest; 1.706 + 1.707 + digest.data = aDigestData; 1.708 + digest.len = aDigestDataLen; 1.709 + 1.710 + if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) { 1.711 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set digest value\n")); 1.712 + goto loser; 1.713 + } 1.714 + } 1.715 + 1.716 + return NS_OK; 1.717 +loser: 1.718 + if (m_cmsMsg) { 1.719 + NSS_CMSMessage_Destroy(m_cmsMsg); 1.720 + m_cmsMsg = nullptr; 1.721 + } 1.722 + return rv; 1.723 +} 1.724 + 1.725 +NS_IMPL_ISUPPORTS(nsCMSDecoder, nsICMSDecoder) 1.726 + 1.727 +nsCMSDecoder::nsCMSDecoder() 1.728 +: m_dcx(nullptr) 1.729 +{ 1.730 +} 1.731 + 1.732 +nsCMSDecoder::~nsCMSDecoder() 1.733 +{ 1.734 + nsNSSShutDownPreventionLock locker; 1.735 + if (isAlreadyShutDown()) { 1.736 + return; 1.737 + } 1.738 + destructorSafeDestroyNSSReference(); 1.739 + shutdown(calledFromObject); 1.740 +} 1.741 + 1.742 +void nsCMSDecoder::virtualDestroyNSSReference() 1.743 +{ 1.744 + destructorSafeDestroyNSSReference(); 1.745 +} 1.746 + 1.747 +void nsCMSDecoder::destructorSafeDestroyNSSReference() 1.748 +{ 1.749 + if (m_dcx) { 1.750 + NSS_CMSDecoder_Cancel(m_dcx); 1.751 + m_dcx = nullptr; 1.752 + } 1.753 +} 1.754 + 1.755 +/* void start (in NSSCMSContentCallback cb, in voidPtr arg); */ 1.756 +NS_IMETHODIMP nsCMSDecoder::Start(NSSCMSContentCallback cb, void * arg) 1.757 +{ 1.758 + nsNSSShutDownPreventionLock locker; 1.759 + if (isAlreadyShutDown()) 1.760 + return NS_ERROR_NOT_AVAILABLE; 1.761 + 1.762 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Start\n")); 1.763 + m_ctx = new PipUIContext(); 1.764 + 1.765 + m_dcx = NSS_CMSDecoder_Start(0, cb, arg, 0, m_ctx, 0, 0); 1.766 + if (!m_dcx) { 1.767 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Start - can't start decoder\n")); 1.768 + return NS_ERROR_FAILURE; 1.769 + } 1.770 + return NS_OK; 1.771 +} 1.772 + 1.773 +/* void update (in string bug, in long len); */ 1.774 +NS_IMETHODIMP nsCMSDecoder::Update(const char *buf, int32_t len) 1.775 +{ 1.776 + nsNSSShutDownPreventionLock locker; 1.777 + if (isAlreadyShutDown()) 1.778 + return NS_ERROR_NOT_AVAILABLE; 1.779 + 1.780 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Update\n")); 1.781 + NSS_CMSDecoder_Update(m_dcx, (char *)buf, len); 1.782 + return NS_OK; 1.783 +} 1.784 + 1.785 +/* void finish (); */ 1.786 +NS_IMETHODIMP nsCMSDecoder::Finish(nsICMSMessage ** aCMSMsg) 1.787 +{ 1.788 + nsNSSShutDownPreventionLock locker; 1.789 + if (isAlreadyShutDown()) 1.790 + return NS_ERROR_NOT_AVAILABLE; 1.791 + 1.792 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Finish\n")); 1.793 + NSSCMSMessage *cmsMsg; 1.794 + cmsMsg = NSS_CMSDecoder_Finish(m_dcx); 1.795 + m_dcx = nullptr; 1.796 + if (cmsMsg) { 1.797 + nsCMSMessage *obj = new nsCMSMessage(cmsMsg); 1.798 + // The NSS object cmsMsg still carries a reference to the context 1.799 + // we gave it on construction. 1.800 + // Make sure the context will live long enough. 1.801 + obj->referenceContext(m_ctx); 1.802 + *aCMSMsg = obj; 1.803 + NS_ADDREF(*aCMSMsg); 1.804 + } 1.805 + return NS_OK; 1.806 +} 1.807 + 1.808 +NS_IMPL_ISUPPORTS(nsCMSEncoder, nsICMSEncoder) 1.809 + 1.810 +nsCMSEncoder::nsCMSEncoder() 1.811 +: m_ecx(nullptr) 1.812 +{ 1.813 +} 1.814 + 1.815 +nsCMSEncoder::~nsCMSEncoder() 1.816 +{ 1.817 + nsNSSShutDownPreventionLock locker; 1.818 + if (isAlreadyShutDown()) { 1.819 + return; 1.820 + } 1.821 + destructorSafeDestroyNSSReference(); 1.822 + shutdown(calledFromObject); 1.823 +} 1.824 + 1.825 +void nsCMSEncoder::virtualDestroyNSSReference() 1.826 +{ 1.827 + destructorSafeDestroyNSSReference(); 1.828 +} 1.829 + 1.830 +void nsCMSEncoder::destructorSafeDestroyNSSReference() 1.831 +{ 1.832 + if (m_ecx) 1.833 + NSS_CMSEncoder_Cancel(m_ecx); 1.834 +} 1.835 + 1.836 +/* void start (); */ 1.837 +NS_IMETHODIMP nsCMSEncoder::Start(nsICMSMessage *aMsg, NSSCMSContentCallback cb, void * arg) 1.838 +{ 1.839 + nsNSSShutDownPreventionLock locker; 1.840 + if (isAlreadyShutDown()) 1.841 + return NS_ERROR_NOT_AVAILABLE; 1.842 + 1.843 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Start\n")); 1.844 + nsCMSMessage *cmsMsg = static_cast<nsCMSMessage*>(aMsg); 1.845 + m_ctx = new PipUIContext(); 1.846 + 1.847 + m_ecx = NSS_CMSEncoder_Start(cmsMsg->getCMS(), cb, arg, 0, 0, 0, m_ctx, 0, 0, 0, 0); 1.848 + if (!m_ecx) { 1.849 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Start - can't start encoder\n")); 1.850 + return NS_ERROR_FAILURE; 1.851 + } 1.852 + return NS_OK; 1.853 +} 1.854 + 1.855 +/* void update (in string aBuf, in long aLen); */ 1.856 +NS_IMETHODIMP nsCMSEncoder::Update(const char *aBuf, int32_t aLen) 1.857 +{ 1.858 + nsNSSShutDownPreventionLock locker; 1.859 + if (isAlreadyShutDown()) 1.860 + return NS_ERROR_NOT_AVAILABLE; 1.861 + 1.862 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Update\n")); 1.863 + if (!m_ecx || NSS_CMSEncoder_Update(m_ecx, aBuf, aLen) != SECSuccess) { 1.864 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Update - can't update encoder\n")); 1.865 + return NS_ERROR_FAILURE; 1.866 + } 1.867 + return NS_OK; 1.868 +} 1.869 + 1.870 +/* void finish (); */ 1.871 +NS_IMETHODIMP nsCMSEncoder::Finish() 1.872 +{ 1.873 + nsNSSShutDownPreventionLock locker; 1.874 + if (isAlreadyShutDown()) 1.875 + return NS_ERROR_NOT_AVAILABLE; 1.876 + 1.877 + nsresult rv = NS_OK; 1.878 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Finish\n")); 1.879 + if (!m_ecx || NSS_CMSEncoder_Finish(m_ecx) != SECSuccess) { 1.880 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Finish - can't finish encoder\n")); 1.881 + rv = NS_ERROR_FAILURE; 1.882 + } 1.883 + m_ecx = nullptr; 1.884 + return rv; 1.885 +} 1.886 + 1.887 +/* void encode (in nsICMSMessage aMsg); */ 1.888 +NS_IMETHODIMP nsCMSEncoder::Encode(nsICMSMessage *aMsg) 1.889 +{ 1.890 + nsNSSShutDownPreventionLock locker; 1.891 + if (isAlreadyShutDown()) 1.892 + return NS_ERROR_NOT_AVAILABLE; 1.893 + 1.894 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Encode\n")); 1.895 + return NS_ERROR_NOT_IMPLEMENTED; 1.896 +}