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

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

mercurial