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