security/manager/ssl/src/nsCMS.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:3332901ca748
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/. */
5
6 #include "nsCMS.h"
7
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"
19
20 #include "prlog.h"
21
22 using namespace mozilla;
23 using namespace mozilla::psm;
24
25 #ifdef PR_LOGGING
26 extern PRLogModuleInfo* gPIPNSSLog;
27 #endif
28
29 using namespace mozilla;
30
31 NS_IMPL_ISUPPORTS(nsCMSMessage, nsICMSMessage, nsICMSMessage2)
32
33 nsCMSMessage::nsCMSMessage()
34 {
35 m_cmsMsg = nullptr;
36 }
37 nsCMSMessage::nsCMSMessage(NSSCMSMessage *aCMSMsg)
38 {
39 m_cmsMsg = aCMSMsg;
40 }
41
42 nsCMSMessage::~nsCMSMessage()
43 {
44 nsNSSShutDownPreventionLock locker;
45 if (isAlreadyShutDown()) {
46 return;
47 }
48 destructorSafeDestroyNSSReference();
49 shutdown(calledFromObject);
50 }
51
52 void nsCMSMessage::virtualDestroyNSSReference()
53 {
54 destructorSafeDestroyNSSReference();
55 }
56
57 void nsCMSMessage::destructorSafeDestroyNSSReference()
58 {
59 if (m_cmsMsg) {
60 NSS_CMSMessage_Destroy(m_cmsMsg);
61 }
62 }
63
64 NS_IMETHODIMP nsCMSMessage::VerifySignature()
65 {
66 return CommonVerifySignature(nullptr, 0);
67 }
68
69 NSSCMSSignerInfo* nsCMSMessage::GetTopLevelSignerInfo()
70 {
71 nsNSSShutDownPreventionLock locker;
72 if (isAlreadyShutDown())
73 return nullptr;
74
75 if (!m_cmsMsg)
76 return nullptr;
77
78 if (!NSS_CMSMessage_IsSigned(m_cmsMsg))
79 return nullptr;
80
81 NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0);
82 if (!cinfo)
83 return nullptr;
84
85 NSSCMSSignedData *sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo);
86 if (!sigd)
87 return nullptr;
88
89 PR_ASSERT(NSS_CMSSignedData_SignerInfoCount(sigd) > 0);
90 return NSS_CMSSignedData_GetSignerInfo(sigd, 0);
91 }
92
93 NS_IMETHODIMP nsCMSMessage::GetSignerEmailAddress(char * * aEmail)
94 {
95 nsNSSShutDownPreventionLock locker;
96 if (isAlreadyShutDown())
97 return NS_ERROR_NOT_AVAILABLE;
98
99 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerEmailAddress\n"));
100 NS_ENSURE_ARG(aEmail);
101
102 NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
103 if (!si)
104 return NS_ERROR_FAILURE;
105
106 *aEmail = NSS_CMSSignerInfo_GetSignerEmailAddress(si);
107 return NS_OK;
108 }
109
110 NS_IMETHODIMP nsCMSMessage::GetSignerCommonName(char ** aName)
111 {
112 nsNSSShutDownPreventionLock locker;
113 if (isAlreadyShutDown())
114 return NS_ERROR_NOT_AVAILABLE;
115
116 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCommonName\n"));
117 NS_ENSURE_ARG(aName);
118
119 NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
120 if (!si)
121 return NS_ERROR_FAILURE;
122
123 *aName = NSS_CMSSignerInfo_GetSignerCommonName(si);
124 return NS_OK;
125 }
126
127 NS_IMETHODIMP nsCMSMessage::ContentIsEncrypted(bool *isEncrypted)
128 {
129 nsNSSShutDownPreventionLock locker;
130 if (isAlreadyShutDown())
131 return NS_ERROR_NOT_AVAILABLE;
132
133 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::ContentIsEncrypted\n"));
134 NS_ENSURE_ARG(isEncrypted);
135
136 if (!m_cmsMsg)
137 return NS_ERROR_FAILURE;
138
139 *isEncrypted = NSS_CMSMessage_IsEncrypted(m_cmsMsg);
140
141 return NS_OK;
142 }
143
144 NS_IMETHODIMP nsCMSMessage::ContentIsSigned(bool *isSigned)
145 {
146 nsNSSShutDownPreventionLock locker;
147 if (isAlreadyShutDown())
148 return NS_ERROR_NOT_AVAILABLE;
149
150 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::ContentIsSigned\n"));
151 NS_ENSURE_ARG(isSigned);
152
153 if (!m_cmsMsg)
154 return NS_ERROR_FAILURE;
155
156 *isSigned = NSS_CMSMessage_IsSigned(m_cmsMsg);
157
158 return NS_OK;
159 }
160
161 NS_IMETHODIMP nsCMSMessage::GetSignerCert(nsIX509Cert **scert)
162 {
163 nsNSSShutDownPreventionLock locker;
164 if (isAlreadyShutDown())
165 return NS_ERROR_NOT_AVAILABLE;
166
167 NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
168 if (!si)
169 return NS_ERROR_FAILURE;
170
171 if (si->cert) {
172 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCert got signer cert\n"));
173
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") ));
182
183 *scert = nullptr;
184 }
185
186 return NS_OK;
187 }
188
189 NS_IMETHODIMP nsCMSMessage::GetEncryptionCert(nsIX509Cert **ecert)
190 {
191 nsNSSShutDownPreventionLock locker;
192 if (isAlreadyShutDown())
193 return NS_ERROR_NOT_AVAILABLE;
194
195 return NS_ERROR_NOT_IMPLEMENTED;
196 }
197
198 NS_IMETHODIMP nsCMSMessage::VerifyDetachedSignature(unsigned char* aDigestData, uint32_t aDigestDataLen)
199 {
200 if (!aDigestData || !aDigestDataLen)
201 return NS_ERROR_FAILURE;
202
203 return CommonVerifySignature(aDigestData, aDigestDataLen);
204 }
205
206 nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, uint32_t aDigestDataLen)
207 {
208 nsNSSShutDownPreventionLock locker;
209 if (isAlreadyShutDown())
210 return NS_ERROR_NOT_AVAILABLE;
211
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;
219
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 }
224
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 }
230
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 }
236
237 if (aDigestData && aDigestDataLen)
238 {
239 SECItem digest;
240 digest.data = aDigestData;
241 digest.len = aDigestDataLen;
242
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 }
249
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 }
254
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);
259
260 // See bug 324474. We want to make sure the signing cert is
261 // still valid at the current time.
262
263 certVerifier = GetDefaultCertVerifier();
264 NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
265
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 }
278
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"));
282
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 }
319
320 goto loser;
321 }
322
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 }
327
328 rv = NS_OK;
329 loser:
330 return rv;
331 }
332
333 NS_IMETHODIMP nsCMSMessage::AsyncVerifySignature(
334 nsISMimeVerificationListener *aListener)
335 {
336 return CommonAsyncVerifySignature(aListener, nullptr, 0);
337 }
338
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;
345
346 return CommonAsyncVerifySignature(aListener, aDigestData, aDigestDataLen);
347 }
348
349 nsresult nsCMSMessage::CommonAsyncVerifySignature(nsISMimeVerificationListener *aListener,
350 unsigned char* aDigestData, uint32_t aDigestDataLen)
351 {
352 nsSMimeVerificationJob *job = new nsSMimeVerificationJob;
353
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 }
363
364 job->digest_len = aDigestDataLen;
365 job->mMessage = this;
366 job->mListener = aListener;
367
368 nsresult rv = nsCertVerificationThread::addJob(job);
369 if (NS_FAILED(rv))
370 delete job;
371
372 return rv;
373 }
374
375 class nsZeroTerminatedCertArray : public nsNSSShutDownObject
376 {
377 public:
378 nsZeroTerminatedCertArray()
379 :mCerts(nullptr), mPoolp(nullptr), mSize(0)
380 {
381 }
382
383 ~nsZeroTerminatedCertArray()
384 {
385 nsNSSShutDownPreventionLock locker;
386 if (isAlreadyShutDown()) {
387 return;
388 }
389 destructorSafeDestroyNSSReference();
390 shutdown(calledFromObject);
391 }
392
393 void virtualDestroyNSSReference()
394 {
395 destructorSafeDestroyNSSReference();
396 }
397
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 }
408
409 if (mPoolp)
410 PORT_FreeArena(mPoolp, false);
411 }
412
413 bool allocate(uint32_t count)
414 {
415 // only allow allocation once
416 if (mPoolp)
417 return false;
418
419 mSize = count;
420
421 if (!mSize)
422 return false;
423
424 mPoolp = PORT_NewArena(1024);
425 if (!mPoolp)
426 return false;
427
428 mCerts = (CERTCertificate**)PORT_ArenaZAlloc(
429 mPoolp, (count+1)*sizeof(CERTCertificate*));
430
431 if (!mCerts)
432 return false;
433
434 // null array, including zero termination
435 for (uint32_t i = 0; i < count+1; i++) {
436 mCerts[i] = nullptr;
437 }
438
439 return true;
440 }
441
442 void set(uint32_t i, CERTCertificate *c)
443 {
444 nsNSSShutDownPreventionLock locker;
445 if (isAlreadyShutDown())
446 return;
447
448 if (i >= mSize)
449 return;
450
451 if (mCerts[i]) {
452 CERT_DestroyCertificate(mCerts[i]);
453 }
454
455 mCerts[i] = CERT_DupCertificate(c);
456 }
457
458 CERTCertificate *get(uint32_t i)
459 {
460 nsNSSShutDownPreventionLock locker;
461 if (isAlreadyShutDown())
462 return nullptr;
463
464 if (i >= mSize)
465 return nullptr;
466
467 return CERT_DupCertificate(mCerts[i]);
468 }
469
470 CERTCertificate **getRawArray()
471 {
472 nsNSSShutDownPreventionLock locker;
473 if (isAlreadyShutDown())
474 return nullptr;
475
476 return mCerts;
477 }
478
479 private:
480 CERTCertificate **mCerts;
481 PLArenaPool *mPoolp;
482 uint32_t mSize;
483 };
484
485 NS_IMETHODIMP nsCMSMessage::CreateEncrypted(nsIArray * aRecipientCerts)
486 {
487 nsNSSShutDownPreventionLock locker;
488 if (isAlreadyShutDown())
489 return NS_ERROR_NOT_AVAILABLE;
490
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;
501
502 // Check the recipient certificates //
503 uint32_t recipientCertCount;
504 aRecipientCerts->GetLength(&recipientCertCount);
505 PR_ASSERT(recipientCertCount > 0);
506
507 if (!recipientCerts.allocate(recipientCertCount)) {
508 goto loser;
509 }
510
511 for (i=0; i<recipientCertCount; i++) {
512 nsCOMPtr<nsIX509Cert> x509cert = do_QueryElementAt(aRecipientCerts, i);
513
514 nssRecipientCert = do_QueryInterface(x509cert);
515
516 if (!nssRecipientCert)
517 return NS_ERROR_FAILURE;
518
519 mozilla::pkix::ScopedCERTCertificate c(nssRecipientCert->GetCert());
520 recipientCerts.set(i, c.get());
521 }
522
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 }
530
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 }
537
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 }
542
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 }
548
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 }
554
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 }
567
568 return NS_OK;
569 loser:
570 if (m_cmsMsg) {
571 NSS_CMSMessage_Destroy(m_cmsMsg);
572 m_cmsMsg = nullptr;
573 }
574
575 return rv;
576 }
577
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;
583
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;
592
593 /* Get the certs */
594 if (aSigningCert2) {
595 scert = aSigningCert2->GetCert();
596 }
597 if (!scert) {
598 return NS_ERROR_FAILURE;
599 }
600
601 if (aEncryptCert) {
602 nsCOMPtr<nsIX509Cert2> aEncryptCert2 = do_QueryInterface(aEncryptCert);
603 if (aEncryptCert2) {
604 ecert = aEncryptCert2->GetCert();
605 }
606 }
607
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 }
617
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 }
631
632 cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
633
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 }
640
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 }
649
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 }
657
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 }
663
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 }
668
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 }
676
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 }
683
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())));
687
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 }
694
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 }
699
700 // Finally, add the pre-computed digest if passed in
701 if (aDigestData) {
702 SECItem digest;
703
704 digest.data = aDigestData;
705 digest.len = aDigestDataLen;
706
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 }
712
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 }
721
722 NS_IMPL_ISUPPORTS(nsCMSDecoder, nsICMSDecoder)
723
724 nsCMSDecoder::nsCMSDecoder()
725 : m_dcx(nullptr)
726 {
727 }
728
729 nsCMSDecoder::~nsCMSDecoder()
730 {
731 nsNSSShutDownPreventionLock locker;
732 if (isAlreadyShutDown()) {
733 return;
734 }
735 destructorSafeDestroyNSSReference();
736 shutdown(calledFromObject);
737 }
738
739 void nsCMSDecoder::virtualDestroyNSSReference()
740 {
741 destructorSafeDestroyNSSReference();
742 }
743
744 void nsCMSDecoder::destructorSafeDestroyNSSReference()
745 {
746 if (m_dcx) {
747 NSS_CMSDecoder_Cancel(m_dcx);
748 m_dcx = nullptr;
749 }
750 }
751
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;
758
759 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Start\n"));
760 m_ctx = new PipUIContext();
761
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 }
769
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;
776
777 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Update\n"));
778 NSS_CMSDecoder_Update(m_dcx, (char *)buf, len);
779 return NS_OK;
780 }
781
782 /* void finish (); */
783 NS_IMETHODIMP nsCMSDecoder::Finish(nsICMSMessage ** aCMSMsg)
784 {
785 nsNSSShutDownPreventionLock locker;
786 if (isAlreadyShutDown())
787 return NS_ERROR_NOT_AVAILABLE;
788
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 }
804
805 NS_IMPL_ISUPPORTS(nsCMSEncoder, nsICMSEncoder)
806
807 nsCMSEncoder::nsCMSEncoder()
808 : m_ecx(nullptr)
809 {
810 }
811
812 nsCMSEncoder::~nsCMSEncoder()
813 {
814 nsNSSShutDownPreventionLock locker;
815 if (isAlreadyShutDown()) {
816 return;
817 }
818 destructorSafeDestroyNSSReference();
819 shutdown(calledFromObject);
820 }
821
822 void nsCMSEncoder::virtualDestroyNSSReference()
823 {
824 destructorSafeDestroyNSSReference();
825 }
826
827 void nsCMSEncoder::destructorSafeDestroyNSSReference()
828 {
829 if (m_ecx)
830 NSS_CMSEncoder_Cancel(m_ecx);
831 }
832
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;
839
840 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Start\n"));
841 nsCMSMessage *cmsMsg = static_cast<nsCMSMessage*>(aMsg);
842 m_ctx = new PipUIContext();
843
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 }
851
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;
858
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 }
866
867 /* void finish (); */
868 NS_IMETHODIMP nsCMSEncoder::Finish()
869 {
870 nsNSSShutDownPreventionLock locker;
871 if (isAlreadyShutDown())
872 return NS_ERROR_NOT_AVAILABLE;
873
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 }
883
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;
890
891 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Encode\n"));
892 return NS_ERROR_NOT_IMPLEMENTED;
893 }

mercurial