security/manager/ssl/src/nsCertTree.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:d04285da3983
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "nsCertTree.h"
6
7 #include "pkix/pkixtypes.h"
8 #include "nsNSSComponent.h" // for PIPNSS string bundle calls.
9 #include "nsITreeColumns.h"
10 #include "nsIX509Cert.h"
11 #include "nsIX509CertValidity.h"
12 #include "nsIX509CertDB.h"
13 #include "nsXPIDLString.h"
14 #include "nsReadableUtils.h"
15 #include "nsUnicharUtils.h"
16 #include "nsNSSCertificate.h"
17 #include "nsNSSCertHelper.h"
18 #include "nsINSSCertCache.h"
19 #include "nsIMutableArray.h"
20 #include "nsArrayUtils.h"
21 #include "nsISupportsPrimitives.h"
22 #include "nsXPCOMCID.h"
23 #include "nsTHashtable.h"
24 #include "nsHashKeys.h"
25
26 #include "prlog.h"
27
28 using namespace mozilla;
29
30 #ifdef PR_LOGGING
31 extern PRLogModuleInfo* gPIPNSSLog;
32 #endif
33
34 static NS_DEFINE_CID(kCertOverrideCID, NS_CERTOVERRIDE_CID);
35
36 // treeArrayElStr
37 //
38 // structure used to hold map of tree. Each thread (an organization
39 // field from a cert) has an element in the array. The numChildren field
40 // stores the number of certs corresponding to that thread.
41 struct treeArrayElStr {
42 nsString orgName; /* heading for thread */
43 bool open; /* toggle open state for thread */
44 int32_t certIndex; /* index into cert array for 1st cert */
45 int32_t numChildren; /* number of chidren (certs) for thread */
46 };
47
48 CompareCacheHashEntryPtr::CompareCacheHashEntryPtr()
49 {
50 entry = new CompareCacheHashEntry;
51 }
52
53 CompareCacheHashEntryPtr::~CompareCacheHashEntryPtr()
54 {
55 delete entry;
56 }
57
58 CompareCacheHashEntry::CompareCacheHashEntry()
59 :key(nullptr)
60 {
61 for (int i = 0; i < max_criterions; ++i) {
62 mCritInit[i] = false;
63 }
64 }
65
66 static bool
67 CompareCacheMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
68 const void *key)
69 {
70 const CompareCacheHashEntryPtr *entryPtr = static_cast<const CompareCacheHashEntryPtr*>(hdr);
71 return entryPtr->entry->key == key;
72 }
73
74 static bool
75 CompareCacheInitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
76 const void *key)
77 {
78 new (hdr) CompareCacheHashEntryPtr();
79 CompareCacheHashEntryPtr *entryPtr = static_cast<CompareCacheHashEntryPtr*>(hdr);
80 if (!entryPtr->entry) {
81 return false;
82 }
83 entryPtr->entry->key = (void*)key;
84 return true;
85 }
86
87 static void
88 CompareCacheClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
89 {
90 CompareCacheHashEntryPtr *entryPtr = static_cast<CompareCacheHashEntryPtr*>(hdr);
91 entryPtr->~CompareCacheHashEntryPtr();
92 }
93
94 static const PLDHashTableOps gMapOps = {
95 PL_DHashAllocTable,
96 PL_DHashFreeTable,
97 PL_DHashVoidPtrKeyStub,
98 CompareCacheMatchEntry,
99 PL_DHashMoveEntryStub,
100 CompareCacheClearEntry,
101 PL_DHashFinalizeStub,
102 CompareCacheInitEntry
103 };
104
105 NS_IMPL_ISUPPORTS0(nsCertAddonInfo)
106 NS_IMPL_ISUPPORTS(nsCertTreeDispInfo, nsICertTreeItem)
107
108 nsCertTreeDispInfo::nsCertTreeDispInfo()
109 :mAddonInfo(nullptr)
110 ,mTypeOfEntry(direct_db)
111 ,mPort(-1)
112 ,mOverrideBits(nsCertOverride::ob_None)
113 ,mIsTemporary(true)
114 {
115 }
116
117 nsCertTreeDispInfo::nsCertTreeDispInfo(nsCertTreeDispInfo &other)
118 {
119 mAddonInfo = other.mAddonInfo;
120 mTypeOfEntry = other.mTypeOfEntry;
121 mAsciiHost = other.mAsciiHost;
122 mPort = other.mPort;
123 mOverrideBits = other.mOverrideBits;
124 mIsTemporary = other.mIsTemporary;
125 mCert = other.mCert;
126 }
127
128 nsCertTreeDispInfo::~nsCertTreeDispInfo()
129 {
130 }
131
132 NS_IMETHODIMP
133 nsCertTreeDispInfo::GetCert(nsIX509Cert **_cert)
134 {
135 NS_ENSURE_ARG(_cert);
136 if (mCert) {
137 // we may already have the cert for temporary overrides
138 *_cert = mCert;
139 NS_IF_ADDREF(*_cert);
140 return NS_OK;
141 }
142 if (mAddonInfo) {
143 *_cert = mAddonInfo->mCert.get();
144 NS_IF_ADDREF(*_cert);
145 }
146 else {
147 *_cert = nullptr;
148 }
149 return NS_OK;
150 }
151
152 NS_IMETHODIMP
153 nsCertTreeDispInfo::GetHostPort(nsAString &aHostPort)
154 {
155 nsAutoCString hostPort;
156 nsCertOverrideService::GetHostWithPort(mAsciiHost, mPort, hostPort);
157 aHostPort = NS_ConvertUTF8toUTF16(hostPort);
158 return NS_OK;
159 }
160
161 NS_IMPL_ISUPPORTS(nsCertTree, nsICertTree, nsITreeView)
162
163 nsCertTree::nsCertTree() : mTreeArray(nullptr)
164 {
165 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
166
167 mCompareCache.ops = nullptr;
168 mNSSComponent = do_GetService(kNSSComponentCID);
169 mOverrideService = do_GetService("@mozilla.org/security/certoverride;1");
170 // Might be a different service if someone is overriding the contract
171 nsCOMPtr<nsICertOverrideService> origCertOverride =
172 do_GetService(kCertOverrideCID);
173 mOriginalOverrideService =
174 static_cast<nsCertOverrideService*>(origCertOverride.get());
175 mCellText = nullptr;
176 }
177
178 void nsCertTree::ClearCompareHash()
179 {
180 if (mCompareCache.ops) {
181 PL_DHashTableFinish(&mCompareCache);
182 mCompareCache.ops = nullptr;
183 }
184 }
185
186 nsresult nsCertTree::InitCompareHash()
187 {
188 ClearCompareHash();
189 if (!PL_DHashTableInit(&mCompareCache, &gMapOps, nullptr,
190 sizeof(CompareCacheHashEntryPtr), 128, fallible_t())) {
191 mCompareCache.ops = nullptr;
192 return NS_ERROR_OUT_OF_MEMORY;
193 }
194 return NS_OK;
195 }
196
197 nsCertTree::~nsCertTree()
198 {
199 ClearCompareHash();
200 delete [] mTreeArray;
201 }
202
203 void
204 nsCertTree::FreeCertArray()
205 {
206 mDispInfo.Clear();
207 }
208
209 CompareCacheHashEntry *
210 nsCertTree::getCacheEntry(void *cache, void *aCert)
211 {
212 PLDHashTable &aCompareCache = *reinterpret_cast<PLDHashTable*>(cache);
213 CompareCacheHashEntryPtr *entryPtr =
214 static_cast<CompareCacheHashEntryPtr*>
215 (PL_DHashTableOperate(&aCompareCache, aCert, PL_DHASH_ADD));
216 return entryPtr ? entryPtr->entry : nullptr;
217 }
218
219 void nsCertTree::RemoveCacheEntry(void *key)
220 {
221 PL_DHashTableOperate(&mCompareCache, key, PL_DHASH_REMOVE);
222 }
223
224 // CountOrganizations
225 //
226 // Count the number of different organizations encountered in the cert
227 // list.
228 int32_t
229 nsCertTree::CountOrganizations()
230 {
231 uint32_t i, certCount;
232 certCount = mDispInfo.Length();
233 if (certCount == 0) return 0;
234 nsCOMPtr<nsIX509Cert> orgCert = nullptr;
235 nsCertAddonInfo *addonInfo = mDispInfo.ElementAt(0)->mAddonInfo;
236 if (addonInfo) {
237 orgCert = addonInfo->mCert;
238 }
239 nsCOMPtr<nsIX509Cert> nextCert = nullptr;
240 int32_t orgCount = 1;
241 for (i=1; i<certCount; i++) {
242 nextCert = nullptr;
243 addonInfo = mDispInfo.SafeElementAt(i, nullptr)->mAddonInfo;
244 if (addonInfo) {
245 nextCert = addonInfo->mCert;
246 }
247 // XXX we assume issuer org is always criterion 1
248 if (CmpBy(&mCompareCache, orgCert, nextCert, sort_IssuerOrg, sort_None, sort_None) != 0) {
249 orgCert = nextCert;
250 orgCount++;
251 }
252 }
253 return orgCount;
254 }
255
256 // GetThreadDescAtIndex
257 //
258 // If the row at index is an organization thread, return the collection
259 // associated with that thread. Otherwise, return null.
260 treeArrayEl *
261 nsCertTree::GetThreadDescAtIndex(int32_t index)
262 {
263 int i, idx=0;
264 if (index < 0) return nullptr;
265 for (i=0; i<mNumOrgs; i++) {
266 if (index == idx) {
267 return &mTreeArray[i];
268 }
269 if (mTreeArray[i].open) {
270 idx += mTreeArray[i].numChildren;
271 }
272 idx++;
273 if (idx > index) break;
274 }
275 return nullptr;
276 }
277
278 // GetCertAtIndex
279 //
280 // If the row at index is a cert, return that cert. Otherwise, return null.
281 already_AddRefed<nsIX509Cert>
282 nsCertTree::GetCertAtIndex(int32_t index, int32_t *outAbsoluteCertOffset)
283 {
284 RefPtr<nsCertTreeDispInfo> certdi(
285 GetDispInfoAtIndex(index, outAbsoluteCertOffset));
286 if (!certdi)
287 return nullptr;
288
289 nsCOMPtr<nsIX509Cert> ret;
290 if (certdi->mCert) {
291 ret = certdi->mCert;
292 } else if (certdi->mAddonInfo) {
293 ret = certdi->mAddonInfo->mCert;
294 }
295 return ret.forget();
296 }
297
298 // If the row at index is a cert, return that cert. Otherwise, return null.
299 TemporaryRef<nsCertTreeDispInfo>
300 nsCertTree::GetDispInfoAtIndex(int32_t index,
301 int32_t *outAbsoluteCertOffset)
302 {
303 int i, idx = 0, cIndex = 0, nc;
304 if (index < 0) return nullptr;
305 // Loop over the threads
306 for (i=0; i<mNumOrgs; i++) {
307 if (index == idx) return nullptr; // index is for thread
308 idx++; // get past the thread
309 nc = (mTreeArray[i].open) ? mTreeArray[i].numChildren : 0;
310 if (index < idx + nc) { // cert is within range of this thread
311 int32_t certIndex = cIndex + index - idx;
312 if (outAbsoluteCertOffset)
313 *outAbsoluteCertOffset = certIndex;
314 RefPtr<nsCertTreeDispInfo> certdi(mDispInfo.SafeElementAt(certIndex,
315 nullptr));
316 if (certdi) {
317 return certdi.forget();
318 }
319 break;
320 }
321 if (mTreeArray[i].open)
322 idx += mTreeArray[i].numChildren;
323 cIndex += mTreeArray[i].numChildren;
324 if (idx > index) break;
325 }
326 return nullptr;
327 }
328
329 nsCertTree::nsCertCompareFunc
330 nsCertTree::GetCompareFuncFromCertType(uint32_t aType)
331 {
332 switch (aType) {
333 case nsIX509Cert2::ANY_CERT:
334 case nsIX509Cert::USER_CERT:
335 return CmpUserCert;
336 case nsIX509Cert::CA_CERT:
337 return CmpCACert;
338 case nsIX509Cert::EMAIL_CERT:
339 return CmpEmailCert;
340 case nsIX509Cert::SERVER_CERT:
341 default:
342 return CmpWebSiteCert;
343 }
344 }
345
346 struct nsCertAndArrayAndPositionAndCounterAndTracker
347 {
348 RefPtr<nsCertAddonInfo> certai;
349 nsTArray< RefPtr<nsCertTreeDispInfo> > *array;
350 int position;
351 int counter;
352 nsTHashtable<nsCStringHashKey> *tracker;
353 };
354
355 // Used to enumerate host:port overrides that match a stored
356 // certificate, creates and adds a display-info-object to the
357 // provided array. Increments insert position and entry counter.
358 // We remove the given key from the tracker, which is used to
359 // track entries that have not yet been handled.
360 // The created display-info references the cert, so make a note
361 // of that by incrementing the cert usage counter.
362 static void
363 MatchingCertOverridesCallback(const nsCertOverride &aSettings,
364 void *aUserData)
365 {
366 nsCertAndArrayAndPositionAndCounterAndTracker *cap =
367 (nsCertAndArrayAndPositionAndCounterAndTracker*)aUserData;
368 if (!cap)
369 return;
370
371 nsCertTreeDispInfo *certdi = new nsCertTreeDispInfo;
372 if (certdi) {
373 if (cap->certai)
374 cap->certai->mUsageCount++;
375 certdi->mAddonInfo = cap->certai;
376 certdi->mTypeOfEntry = nsCertTreeDispInfo::host_port_override;
377 certdi->mAsciiHost = aSettings.mAsciiHost;
378 certdi->mPort = aSettings.mPort;
379 certdi->mOverrideBits = aSettings.mOverrideBits;
380 certdi->mIsTemporary = aSettings.mIsTemporary;
381 certdi->mCert = aSettings.mCert;
382 cap->array->InsertElementAt(cap->position, certdi);
383 cap->position++;
384 cap->counter++;
385 }
386
387 // this entry is now associated to a displayed cert, remove
388 // it from the list of remaining entries
389 nsAutoCString hostPort;
390 nsCertOverrideService::GetHostWithPort(aSettings.mAsciiHost, aSettings.mPort, hostPort);
391 cap->tracker->RemoveEntry(hostPort);
392 }
393
394 // Used to collect a list of the (unique) host:port keys
395 // for all stored overrides.
396 static void
397 CollectAllHostPortOverridesCallback(const nsCertOverride &aSettings,
398 void *aUserData)
399 {
400 nsTHashtable<nsCStringHashKey> *collectorTable =
401 (nsTHashtable<nsCStringHashKey> *)aUserData;
402 if (!collectorTable)
403 return;
404
405 nsAutoCString hostPort;
406 nsCertOverrideService::GetHostWithPort(aSettings.mAsciiHost, aSettings.mPort, hostPort);
407 collectorTable->PutEntry(hostPort);
408 }
409
410 struct nsArrayAndPositionAndCounterAndTracker
411 {
412 nsTArray< RefPtr<nsCertTreeDispInfo> > *array;
413 int position;
414 int counter;
415 nsTHashtable<nsCStringHashKey> *tracker;
416 };
417
418 // Used when enumerating the stored host:port overrides where
419 // no associated certificate was found in the NSS database.
420 static void
421 AddRemaningHostPortOverridesCallback(const nsCertOverride &aSettings,
422 void *aUserData)
423 {
424 nsArrayAndPositionAndCounterAndTracker *cap =
425 (nsArrayAndPositionAndCounterAndTracker*)aUserData;
426 if (!cap)
427 return;
428
429 nsAutoCString hostPort;
430 nsCertOverrideService::GetHostWithPort(aSettings.mAsciiHost, aSettings.mPort, hostPort);
431 if (!cap->tracker->GetEntry(hostPort))
432 return;
433
434 // This entry is not associated to any stored cert,
435 // so we still need to display it.
436
437 nsCertTreeDispInfo *certdi = new nsCertTreeDispInfo;
438 if (certdi) {
439 certdi->mAddonInfo = nullptr;
440 certdi->mTypeOfEntry = nsCertTreeDispInfo::host_port_override;
441 certdi->mAsciiHost = aSettings.mAsciiHost;
442 certdi->mPort = aSettings.mPort;
443 certdi->mOverrideBits = aSettings.mOverrideBits;
444 certdi->mIsTemporary = aSettings.mIsTemporary;
445 certdi->mCert = aSettings.mCert;
446 cap->array->InsertElementAt(cap->position, certdi);
447 cap->position++;
448 cap->counter++;
449 }
450 }
451
452 nsresult
453 nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList,
454 uint32_t aWantedType,
455 nsCertCompareFunc aCertCmpFn,
456 void *aCertCmpFnArg)
457 {
458 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("GetCertsByTypeFromCertList"));
459 if (!aCertList)
460 return NS_ERROR_FAILURE;
461
462 if (!mOriginalOverrideService)
463 return NS_ERROR_FAILURE;
464
465 nsTHashtable<nsCStringHashKey> allHostPortOverrideKeys;
466
467 if (aWantedType == nsIX509Cert::SERVER_CERT) {
468 mOriginalOverrideService->
469 EnumerateCertOverrides(nullptr,
470 CollectAllHostPortOverridesCallback,
471 &allHostPortOverrideKeys);
472 }
473
474 CERTCertListNode *node;
475 int count = 0;
476 for (node = CERT_LIST_HEAD(aCertList);
477 !CERT_LIST_END(node, aCertList);
478 node = CERT_LIST_NEXT(node)) {
479
480 bool wantThisCert = (aWantedType == nsIX509Cert2::ANY_CERT);
481 bool wantThisCertIfNoOverrides = false;
482 bool wantThisCertIfHaveOverrides = false;
483 bool addOverrides = false;
484
485 if (!wantThisCert) {
486 uint32_t thisCertType = getCertType(node->cert);
487
488 // The output from getCertType is a "guess", which can be wrong.
489 // The guess is based on stored trust flags, but for the host:port
490 // overrides, we are storing certs without any trust flags associated.
491 // So we must check whether the cert really belongs to the
492 // server, email or unknown tab. We will lookup the cert in the override
493 // list to come to the decision. Unfortunately, the lookup in the
494 // override list is quite expensive. Therefore we are using this
495 // lengthy if/else statement to minimize
496 // the number of override-list-lookups.
497
498 if (aWantedType == nsIX509Cert::SERVER_CERT
499 && thisCertType == nsIX509Cert::UNKNOWN_CERT) {
500 // This unknown cert was stored without trust
501 // Are there host:port based overrides stored?
502 // If yes, display them.
503 addOverrides = true;
504 }
505 else
506 if (aWantedType == nsIX509Cert::UNKNOWN_CERT
507 && thisCertType == nsIX509Cert::UNKNOWN_CERT) {
508 // This unknown cert was stored without trust.
509 // If there are associated overrides, do not show as unknown.
510 // If there are no associated overrides, display as unknown.
511 wantThisCertIfNoOverrides = true;
512 }
513 else
514 if (aWantedType == nsIX509Cert::SERVER_CERT
515 && thisCertType == nsIX509Cert::SERVER_CERT) {
516 // This server cert is explicitly marked as a web site peer,
517 // with or without trust, but editable, so show it
518 wantThisCert = true;
519 // Are there host:port based overrides stored?
520 // If yes, display them.
521 addOverrides = true;
522 }
523 else
524 if (aWantedType == nsIX509Cert::SERVER_CERT
525 && thisCertType == nsIX509Cert::EMAIL_CERT) {
526 // This cert might have been categorized as an email cert
527 // because it carries an email address. But is it really one?
528 // Our cert categorization is uncertain when it comes to
529 // distinguish between email certs and web site certs.
530 // So, let's see if we have an override for that cert
531 // and if there is, conclude it's really a web site cert.
532 addOverrides = true;
533 }
534 else
535 if (aWantedType == nsIX509Cert::EMAIL_CERT
536 && thisCertType == nsIX509Cert::EMAIL_CERT) {
537 // This cert might have been categorized as an email cert
538 // because it carries an email address. But is it really one?
539 // Our cert categorization is uncertain when it comes to
540 // distinguish between email certs and web site certs.
541 // So, let's see if we have an override for that cert
542 // and if there is, conclude it's really a web site cert.
543 wantThisCertIfNoOverrides = true;
544 }
545 else
546 if (thisCertType == aWantedType) {
547 wantThisCert = true;
548 }
549 }
550
551 nsCOMPtr<nsIX509Cert> pipCert = nsNSSCertificate::Create(node->cert);
552 if (!pipCert)
553 return NS_ERROR_OUT_OF_MEMORY;
554
555 if (wantThisCertIfNoOverrides || wantThisCertIfHaveOverrides) {
556 uint32_t ocount = 0;
557 nsresult rv =
558 mOverrideService->IsCertUsedForOverrides(pipCert,
559 true, // we want temporaries
560 true, // we want permanents
561 &ocount);
562 if (wantThisCertIfNoOverrides) {
563 if (NS_FAILED(rv) || ocount == 0) {
564 // no overrides for this cert
565 wantThisCert = true;
566 }
567 }
568
569 if (wantThisCertIfHaveOverrides) {
570 if (NS_SUCCEEDED(rv) && ocount > 0) {
571 // there are overrides for this cert
572 wantThisCert = true;
573 }
574 }
575 }
576
577 RefPtr<nsCertAddonInfo> certai(new nsCertAddonInfo);
578 certai->mCert = pipCert;
579 certai->mUsageCount = 0;
580
581 if (wantThisCert || addOverrides) {
582 int InsertPosition = 0;
583 for (; InsertPosition < count; ++InsertPosition) {
584 nsCOMPtr<nsIX509Cert> cert = nullptr;
585 RefPtr<nsCertTreeDispInfo> elem(
586 mDispInfo.SafeElementAt(InsertPosition, nullptr));
587 if (elem && elem->mAddonInfo) {
588 cert = elem->mAddonInfo->mCert;
589 }
590 if ((*aCertCmpFn)(aCertCmpFnArg, pipCert, cert) < 0) {
591 break;
592 }
593 }
594 if (wantThisCert) {
595 nsCertTreeDispInfo *certdi = new nsCertTreeDispInfo;
596 certdi->mAddonInfo = certai;
597 certai->mUsageCount++;
598 certdi->mTypeOfEntry = nsCertTreeDispInfo::direct_db;
599 // not necessary: certdi->mAsciiHost.Clear(); certdi->mPort = -1;
600 certdi->mOverrideBits = nsCertOverride::ob_None;
601 certdi->mIsTemporary = false;
602 mDispInfo.InsertElementAt(InsertPosition, certdi);
603 ++count;
604 ++InsertPosition;
605 }
606 if (addOverrides) {
607 nsCertAndArrayAndPositionAndCounterAndTracker cap;
608 cap.certai = certai;
609 cap.array = &mDispInfo;
610 cap.position = InsertPosition;
611 cap.counter = 0;
612 cap.tracker = &allHostPortOverrideKeys;
613
614 mOriginalOverrideService->
615 EnumerateCertOverrides(pipCert, MatchingCertOverridesCallback, &cap);
616 count += cap.counter;
617 }
618 }
619 }
620
621 if (aWantedType == nsIX509Cert::SERVER_CERT) {
622 nsArrayAndPositionAndCounterAndTracker cap;
623 cap.array = &mDispInfo;
624 cap.position = 0;
625 cap.counter = 0;
626 cap.tracker = &allHostPortOverrideKeys;
627 mOriginalOverrideService->
628 EnumerateCertOverrides(nullptr, AddRemaningHostPortOverridesCallback, &cap);
629 }
630
631 return NS_OK;
632 }
633
634 nsresult
635 nsCertTree::GetCertsByType(uint32_t aType,
636 nsCertCompareFunc aCertCmpFn,
637 void *aCertCmpFnArg)
638 {
639 nsNSSShutDownPreventionLock locker;
640 nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
641 mozilla::pkix::ScopedCERTCertList certList(
642 PK11_ListCerts(PK11CertListUnique, cxt));
643 return GetCertsByTypeFromCertList(certList.get(), aType, aCertCmpFn,
644 aCertCmpFnArg);
645 }
646
647 nsresult
648 nsCertTree::GetCertsByTypeFromCache(nsINSSCertCache *aCache,
649 uint32_t aType,
650 nsCertCompareFunc aCertCmpFn,
651 void *aCertCmpFnArg)
652 {
653 NS_ENSURE_ARG_POINTER(aCache);
654 CERTCertList *certList = reinterpret_cast<CERTCertList*>(aCache->GetCachedCerts());
655 if (!certList)
656 return NS_ERROR_FAILURE;
657 return GetCertsByTypeFromCertList(certList, aType, aCertCmpFn, aCertCmpFnArg);
658 }
659
660 // LoadCerts
661 //
662 // Load all of the certificates in the DB for this type. Sort them
663 // by token, organization, then common name.
664 NS_IMETHODIMP
665 nsCertTree::LoadCertsFromCache(nsINSSCertCache *aCache, uint32_t aType)
666 {
667 if (mTreeArray) {
668 FreeCertArray();
669 delete [] mTreeArray;
670 mTreeArray = nullptr;
671 mNumRows = 0;
672 }
673 nsresult rv = InitCompareHash();
674 if (NS_FAILED(rv)) return rv;
675
676 rv = GetCertsByTypeFromCache(aCache, aType,
677 GetCompareFuncFromCertType(aType), &mCompareCache);
678 if (NS_FAILED(rv)) return rv;
679 return UpdateUIContents();
680 }
681
682 NS_IMETHODIMP
683 nsCertTree::LoadCerts(uint32_t aType)
684 {
685 if (mTreeArray) {
686 FreeCertArray();
687 delete [] mTreeArray;
688 mTreeArray = nullptr;
689 mNumRows = 0;
690 }
691 nsresult rv = InitCompareHash();
692 if (NS_FAILED(rv)) return rv;
693
694 rv = GetCertsByType(aType,
695 GetCompareFuncFromCertType(aType), &mCompareCache);
696 if (NS_FAILED(rv)) return rv;
697 return UpdateUIContents();
698 }
699
700 nsresult
701 nsCertTree::UpdateUIContents()
702 {
703 uint32_t count = mDispInfo.Length();
704 mNumOrgs = CountOrganizations();
705 mTreeArray = new treeArrayEl[mNumOrgs];
706
707 mCellText = do_CreateInstance(NS_ARRAY_CONTRACTID);
708
709 if (count) {
710 uint32_t j = 0;
711 nsCOMPtr<nsIX509Cert> orgCert = nullptr;
712 nsCertAddonInfo *addonInfo = mDispInfo.ElementAt(j)->mAddonInfo;
713 if (addonInfo) {
714 orgCert = addonInfo->mCert;
715 }
716 for (int32_t i=0; i<mNumOrgs; i++) {
717 nsString &orgNameRef = mTreeArray[i].orgName;
718 if (!orgCert) {
719 mNSSComponent->GetPIPNSSBundleString("CertOrgUnknown", orgNameRef);
720 }
721 else {
722 orgCert->GetIssuerOrganization(orgNameRef);
723 if (orgNameRef.IsEmpty())
724 orgCert->GetCommonName(orgNameRef);
725 }
726 mTreeArray[i].open = true;
727 mTreeArray[i].certIndex = j;
728 mTreeArray[i].numChildren = 1;
729 if (++j >= count) break;
730 nsCOMPtr<nsIX509Cert> nextCert = nullptr;
731 nsCertAddonInfo *addonInfo = mDispInfo.SafeElementAt(j, nullptr)->mAddonInfo;
732 if (addonInfo) {
733 nextCert = addonInfo->mCert;
734 }
735 while (0 == CmpBy(&mCompareCache, orgCert, nextCert, sort_IssuerOrg, sort_None, sort_None)) {
736 mTreeArray[i].numChildren++;
737 if (++j >= count) break;
738 nextCert = nullptr;
739 addonInfo = mDispInfo.SafeElementAt(j, nullptr)->mAddonInfo;
740 if (addonInfo) {
741 nextCert = addonInfo->mCert;
742 }
743 }
744 orgCert = nextCert;
745 }
746 }
747 if (mTree) {
748 mTree->BeginUpdateBatch();
749 mTree->RowCountChanged(0, -mNumRows);
750 }
751 mNumRows = count + mNumOrgs;
752 if (mTree)
753 mTree->EndUpdateBatch();
754 return NS_OK;
755 }
756
757 NS_IMETHODIMP
758 nsCertTree::DeleteEntryObject(uint32_t index)
759 {
760 if (!mTreeArray) {
761 return NS_ERROR_FAILURE;
762 }
763
764 nsCOMPtr<nsIX509CertDB> certdb =
765 do_GetService("@mozilla.org/security/x509certdb;1");
766 if (!certdb) {
767 return NS_ERROR_FAILURE;
768 }
769
770 int i;
771 uint32_t idx = 0, cIndex = 0, nc;
772 // Loop over the threads
773 for (i=0; i<mNumOrgs; i++) {
774 if (index == idx)
775 return NS_OK; // index is for thread
776 idx++; // get past the thread
777 nc = (mTreeArray[i].open) ? mTreeArray[i].numChildren : 0;
778 if (index < idx + nc) { // cert is within range of this thread
779 int32_t certIndex = cIndex + index - idx;
780
781 bool canRemoveEntry = false;
782 RefPtr<nsCertTreeDispInfo> certdi(mDispInfo.SafeElementAt(certIndex,
783 nullptr));
784
785 // We will remove the element from the visual tree.
786 // Only if we have a certdi, then we can check for additional actions.
787 nsCOMPtr<nsIX509Cert> cert = nullptr;
788 if (certdi) {
789 if (certdi->mAddonInfo) {
790 cert = certdi->mAddonInfo->mCert;
791 }
792 nsCertAddonInfo *addonInfo = certdi->mAddonInfo ? certdi->mAddonInfo : nullptr;
793 if (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override) {
794 mOverrideService->ClearValidityOverride(certdi->mAsciiHost, certdi->mPort);
795 if (addonInfo) {
796 addonInfo->mUsageCount--;
797 if (addonInfo->mUsageCount == 0) {
798 // The certificate stored in the database is no longer
799 // referenced by any other object displayed.
800 // That means we no longer need to keep it around
801 // and really can remove it.
802 canRemoveEntry = true;
803 }
804 }
805 }
806 else {
807 if (addonInfo && addonInfo->mUsageCount > 1) {
808 // user is trying to delete a perm trusted cert,
809 // although there are still overrides stored,
810 // so, we keep the cert, but remove the trust
811
812 mozilla::pkix::ScopedCERTCertificate nsscert;
813
814 nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(cert);
815 if (cert2) {
816 nsscert = cert2->GetCert();
817 }
818
819 if (nsscert) {
820 CERTCertTrust trust;
821 memset((void*)&trust, 0, sizeof(trust));
822
823 SECStatus srv = CERT_DecodeTrustString(&trust, ""); // no override
824 if (srv == SECSuccess) {
825 CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nsscert.get(),
826 &trust);
827 }
828 }
829 }
830 else {
831 canRemoveEntry = true;
832 }
833 }
834 }
835
836 mDispInfo.RemoveElementAt(certIndex);
837
838 if (canRemoveEntry) {
839 RemoveCacheEntry(cert);
840 certdb->DeleteCertificate(cert);
841 }
842
843 delete [] mTreeArray;
844 mTreeArray = nullptr;
845 return UpdateUIContents();
846 }
847 if (mTreeArray[i].open)
848 idx += mTreeArray[i].numChildren;
849 cIndex += mTreeArray[i].numChildren;
850 if (idx > index)
851 break;
852 }
853 return NS_ERROR_FAILURE;
854 }
855
856 //////////////////////////////////////////////////////////////////////////////
857 //
858 // Begin nsITreeView methods
859 //
860 /////////////////////////////////////////////////////////////////////////////
861
862 /* nsIX509Cert getCert(in unsigned long index); */
863 NS_IMETHODIMP
864 nsCertTree::GetCert(uint32_t aIndex, nsIX509Cert **_cert)
865 {
866 NS_ENSURE_ARG(_cert);
867 *_cert = GetCertAtIndex(aIndex).take();
868 return NS_OK;
869 }
870
871 NS_IMETHODIMP
872 nsCertTree::GetTreeItem(uint32_t aIndex, nsICertTreeItem **_treeitem)
873 {
874 NS_ENSURE_ARG(_treeitem);
875
876 RefPtr<nsCertTreeDispInfo> certdi(GetDispInfoAtIndex(aIndex));
877 if (!certdi)
878 return NS_ERROR_FAILURE;
879
880 *_treeitem = certdi;
881 NS_IF_ADDREF(*_treeitem);
882 return NS_OK;
883 }
884
885 NS_IMETHODIMP
886 nsCertTree::IsHostPortOverride(uint32_t aIndex, bool *_retval)
887 {
888 NS_ENSURE_ARG(_retval);
889
890 RefPtr<nsCertTreeDispInfo> certdi(GetDispInfoAtIndex(aIndex));
891 if (!certdi)
892 return NS_ERROR_FAILURE;
893
894 *_retval = (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override);
895 return NS_OK;
896 }
897
898 /* readonly attribute long rowCount; */
899 NS_IMETHODIMP
900 nsCertTree::GetRowCount(int32_t *aRowCount)
901 {
902 if (!mTreeArray)
903 return NS_ERROR_NOT_INITIALIZED;
904 uint32_t count = 0;
905 for (int32_t i=0; i<mNumOrgs; i++) {
906 if (mTreeArray[i].open) {
907 count += mTreeArray[i].numChildren;
908 }
909 count++;
910 }
911 *aRowCount = count;
912 return NS_OK;
913 }
914
915 /* attribute nsITreeSelection selection; */
916 NS_IMETHODIMP
917 nsCertTree::GetSelection(nsITreeSelection * *aSelection)
918 {
919 *aSelection = mSelection;
920 NS_IF_ADDREF(*aSelection);
921 return NS_OK;
922 }
923
924 NS_IMETHODIMP
925 nsCertTree::SetSelection(nsITreeSelection * aSelection)
926 {
927 mSelection = aSelection;
928 return NS_OK;
929 }
930
931 NS_IMETHODIMP
932 nsCertTree::GetRowProperties(int32_t index, nsAString& aProps)
933 {
934 return NS_OK;
935 }
936
937 NS_IMETHODIMP
938 nsCertTree::GetCellProperties(int32_t row, nsITreeColumn* col,
939 nsAString& aProps)
940 {
941 return NS_OK;
942 }
943
944 NS_IMETHODIMP
945 nsCertTree::GetColumnProperties(nsITreeColumn* col, nsAString& aProps)
946 {
947 return NS_OK;
948 }
949 /* boolean isContainer (in long index); */
950 NS_IMETHODIMP
951 nsCertTree::IsContainer(int32_t index, bool *_retval)
952 {
953 if (!mTreeArray)
954 return NS_ERROR_NOT_INITIALIZED;
955 treeArrayEl *el = GetThreadDescAtIndex(index);
956 if (el) {
957 *_retval = true;
958 } else {
959 *_retval = false;
960 }
961 return NS_OK;
962 }
963
964 /* boolean isContainerOpen (in long index); */
965 NS_IMETHODIMP
966 nsCertTree::IsContainerOpen(int32_t index, bool *_retval)
967 {
968 if (!mTreeArray)
969 return NS_ERROR_NOT_INITIALIZED;
970 treeArrayEl *el = GetThreadDescAtIndex(index);
971 if (el && el->open) {
972 *_retval = true;
973 } else {
974 *_retval = false;
975 }
976 return NS_OK;
977 }
978
979 /* boolean isContainerEmpty (in long index); */
980 NS_IMETHODIMP
981 nsCertTree::IsContainerEmpty(int32_t index, bool *_retval)
982 {
983 *_retval = !mTreeArray;
984 return NS_OK;
985 }
986
987 /* boolean isSeparator (in long index); */
988 NS_IMETHODIMP
989 nsCertTree::IsSeparator(int32_t index, bool *_retval)
990 {
991 *_retval = false;
992 return NS_OK;
993 }
994
995 /* long getParentIndex (in long rowIndex); */
996 NS_IMETHODIMP
997 nsCertTree::GetParentIndex(int32_t rowIndex, int32_t *_retval)
998 {
999 if (!mTreeArray)
1000 return NS_ERROR_NOT_INITIALIZED;
1001 int i, idx = 0;
1002 for (i = 0; i < mNumOrgs && idx < rowIndex; i++, idx++) {
1003 if (mTreeArray[i].open) {
1004 if (rowIndex <= idx + mTreeArray[i].numChildren) {
1005 *_retval = idx;
1006 return NS_OK;
1007 }
1008 idx += mTreeArray[i].numChildren;
1009 }
1010 }
1011 *_retval = -1;
1012 return NS_OK;
1013 }
1014
1015 /* boolean hasNextSibling (in long rowIndex, in long afterIndex); */
1016 NS_IMETHODIMP
1017 nsCertTree::HasNextSibling(int32_t rowIndex, int32_t afterIndex,
1018 bool *_retval)
1019 {
1020 if (!mTreeArray)
1021 return NS_ERROR_NOT_INITIALIZED;
1022
1023 int i, idx = 0;
1024 for (i = 0; i < mNumOrgs && idx <= rowIndex; i++, idx++) {
1025 if (mTreeArray[i].open) {
1026 idx += mTreeArray[i].numChildren;
1027 if (afterIndex <= idx) {
1028 *_retval = afterIndex < idx;
1029 return NS_OK;
1030 }
1031 }
1032 }
1033 *_retval = false;
1034 return NS_OK;
1035 }
1036
1037 /* long getLevel (in long index); */
1038 NS_IMETHODIMP
1039 nsCertTree::GetLevel(int32_t index, int32_t *_retval)
1040 {
1041 if (!mTreeArray)
1042 return NS_ERROR_NOT_INITIALIZED;
1043 treeArrayEl *el = GetThreadDescAtIndex(index);
1044 if (el) {
1045 *_retval = 0;
1046 } else {
1047 *_retval = 1;
1048 }
1049 return NS_OK;
1050 }
1051
1052 /* Astring getImageSrc (in long row, in nsITreeColumn col); */
1053 NS_IMETHODIMP
1054 nsCertTree::GetImageSrc(int32_t row, nsITreeColumn* col,
1055 nsAString& _retval)
1056 {
1057 _retval.Truncate();
1058 return NS_OK;
1059 }
1060
1061 /* long getProgressMode (in long row, in nsITreeColumn col); */
1062 NS_IMETHODIMP
1063 nsCertTree::GetProgressMode(int32_t row, nsITreeColumn* col, int32_t* _retval)
1064 {
1065 return NS_OK;
1066 }
1067
1068 /* Astring getCellValue (in long row, in nsITreeColumn col); */
1069 NS_IMETHODIMP
1070 nsCertTree::GetCellValue(int32_t row, nsITreeColumn* col,
1071 nsAString& _retval)
1072 {
1073 _retval.Truncate();
1074 return NS_OK;
1075 }
1076
1077 /* Astring getCellText (in long row, in nsITreeColumn col); */
1078 NS_IMETHODIMP
1079 nsCertTree::GetCellText(int32_t row, nsITreeColumn* col,
1080 nsAString& _retval)
1081 {
1082 if (!mTreeArray)
1083 return NS_ERROR_NOT_INITIALIZED;
1084
1085 nsresult rv;
1086 _retval.Truncate();
1087
1088 const char16_t* colID;
1089 col->GetIdConst(&colID);
1090
1091 treeArrayEl *el = GetThreadDescAtIndex(row);
1092 if (el) {
1093 if (NS_LITERAL_STRING("certcol").Equals(colID))
1094 _retval.Assign(el->orgName);
1095 else
1096 _retval.Truncate();
1097 return NS_OK;
1098 }
1099
1100 int32_t absoluteCertOffset;
1101 RefPtr<nsCertTreeDispInfo> certdi(GetDispInfoAtIndex(row, &absoluteCertOffset));
1102 if (!certdi)
1103 return NS_ERROR_FAILURE;
1104
1105 nsCOMPtr<nsIX509Cert> cert = certdi->mCert;
1106 if (!cert && certdi->mAddonInfo) {
1107 cert = certdi->mAddonInfo->mCert;
1108 }
1109
1110 int32_t colIndex;
1111 col->GetIndex(&colIndex);
1112 uint32_t arrayIndex=absoluteCertOffset+colIndex*(mNumRows-mNumOrgs);
1113 uint32_t arrayLength=0;
1114 if (mCellText) {
1115 mCellText->GetLength(&arrayLength);
1116 }
1117 if (arrayIndex < arrayLength) {
1118 nsCOMPtr<nsISupportsString> myString(do_QueryElementAt(mCellText, arrayIndex));
1119 if (myString) {
1120 myString->GetData(_retval);
1121 return NS_OK;
1122 }
1123 }
1124
1125 if (NS_LITERAL_STRING("certcol").Equals(colID)) {
1126 if (!cert) {
1127 mNSSComponent->GetPIPNSSBundleString("CertNotStored", _retval);
1128 }
1129 else {
1130 rv = cert->GetCommonName(_retval);
1131 if (NS_FAILED(rv) || _retval.IsEmpty()) {
1132 // kaie: I didn't invent the idea to cut off anything before
1133 // the first colon. :-)
1134 nsAutoString nick;
1135 rv = cert->GetNickname(nick);
1136
1137 nsAString::const_iterator start, end, end2;
1138 nick.BeginReading(start);
1139 nick.EndReading(end);
1140 end2 = end;
1141
1142 if (FindInReadable(NS_LITERAL_STRING(":"), start, end)) {
1143 // found. end points to the first char after the colon,
1144 // that's what we want.
1145 _retval = Substring(end, end2);
1146 }
1147 else {
1148 _retval = nick;
1149 }
1150 }
1151 }
1152 } else if (NS_LITERAL_STRING("tokencol").Equals(colID) && cert) {
1153 rv = cert->GetTokenName(_retval);
1154 } else if (NS_LITERAL_STRING("emailcol").Equals(colID) && cert) {
1155 rv = cert->GetEmailAddress(_retval);
1156 } else if (NS_LITERAL_STRING("purposecol").Equals(colID) && mNSSComponent && cert) {
1157 uint32_t verified;
1158
1159 nsAutoString theUsages;
1160 rv = cert->GetUsagesString(false, &verified, theUsages); // allow OCSP
1161 if (NS_FAILED(rv)) {
1162 verified = nsIX509Cert::NOT_VERIFIED_UNKNOWN;
1163 }
1164
1165 switch (verified) {
1166 case nsIX509Cert::VERIFIED_OK:
1167 _retval = theUsages;
1168 break;
1169
1170 case nsIX509Cert::CERT_REVOKED:
1171 rv = mNSSComponent->GetPIPNSSBundleString("VerifyRevoked", _retval);
1172 break;
1173 case nsIX509Cert::CERT_EXPIRED:
1174 rv = mNSSComponent->GetPIPNSSBundleString("VerifyExpired", _retval);
1175 break;
1176 case nsIX509Cert::CERT_NOT_TRUSTED:
1177 rv = mNSSComponent->GetPIPNSSBundleString("VerifyNotTrusted", _retval);
1178 break;
1179 case nsIX509Cert::ISSUER_NOT_TRUSTED:
1180 rv = mNSSComponent->GetPIPNSSBundleString("VerifyIssuerNotTrusted", _retval);
1181 break;
1182 case nsIX509Cert::ISSUER_UNKNOWN:
1183 rv = mNSSComponent->GetPIPNSSBundleString("VerifyIssuerUnknown", _retval);
1184 break;
1185 case nsIX509Cert::INVALID_CA:
1186 rv = mNSSComponent->GetPIPNSSBundleString("VerifyInvalidCA", _retval);
1187 break;
1188 case nsIX509Cert::SIGNATURE_ALGORITHM_DISABLED:
1189 rv = mNSSComponent->GetPIPNSSBundleString("VerifyDisabledAlgorithm", _retval);
1190 break;
1191 case nsIX509Cert::NOT_VERIFIED_UNKNOWN:
1192 case nsIX509Cert::USAGE_NOT_ALLOWED:
1193 default:
1194 rv = mNSSComponent->GetPIPNSSBundleString("VerifyUnknown", _retval);
1195 break;
1196 }
1197 } else if (NS_LITERAL_STRING("issuedcol").Equals(colID) && cert) {
1198 nsCOMPtr<nsIX509CertValidity> validity;
1199
1200 rv = cert->GetValidity(getter_AddRefs(validity));
1201 if (NS_SUCCEEDED(rv)) {
1202 validity->GetNotBeforeLocalDay(_retval);
1203 }
1204 } else if (NS_LITERAL_STRING("expiredcol").Equals(colID) && cert) {
1205 nsCOMPtr<nsIX509CertValidity> validity;
1206
1207 rv = cert->GetValidity(getter_AddRefs(validity));
1208 if (NS_SUCCEEDED(rv)) {
1209 validity->GetNotAfterLocalDay(_retval);
1210 }
1211 } else if (NS_LITERAL_STRING("serialnumcol").Equals(colID) && cert) {
1212 rv = cert->GetSerialNumber(_retval);
1213
1214
1215 } else if (NS_LITERAL_STRING("overridetypecol").Equals(colID)) {
1216 // default to classic permanent-trust
1217 nsCertOverride::OverrideBits ob = nsCertOverride::ob_Untrusted;
1218 if (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override) {
1219 ob = certdi->mOverrideBits;
1220 }
1221 nsAutoCString temp;
1222 nsCertOverride::convertBitsToString(ob, temp);
1223 _retval = NS_ConvertUTF8toUTF16(temp);
1224 } else if (NS_LITERAL_STRING("sitecol").Equals(colID)) {
1225 if (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override) {
1226 nsAutoCString hostPort;
1227 nsCertOverrideService::GetHostWithPort(certdi->mAsciiHost, certdi->mPort, hostPort);
1228 _retval = NS_ConvertUTF8toUTF16(hostPort);
1229 }
1230 else {
1231 _retval = NS_LITERAL_STRING("*");
1232 }
1233 } else if (NS_LITERAL_STRING("lifetimecol").Equals(colID)) {
1234 const char *stringID =
1235 (certdi->mIsTemporary) ? "CertExceptionTemporary" : "CertExceptionPermanent";
1236 rv = mNSSComponent->GetPIPNSSBundleString(stringID, _retval);
1237 } else if (NS_LITERAL_STRING("typecol").Equals(colID) && cert) {
1238 nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
1239 uint32_t type = nsIX509Cert::UNKNOWN_CERT;
1240
1241 if (pipCert) {
1242 rv = pipCert->GetCertType(&type);
1243 }
1244
1245 switch (type) {
1246 case nsIX509Cert::USER_CERT:
1247 rv = mNSSComponent->GetPIPNSSBundleString("CertUser", _retval);
1248 break;
1249 case nsIX509Cert::CA_CERT:
1250 rv = mNSSComponent->GetPIPNSSBundleString("CertCA", _retval);
1251 break;
1252 case nsIX509Cert::SERVER_CERT:
1253 rv = mNSSComponent->GetPIPNSSBundleString("CertSSL", _retval);
1254 break;
1255 case nsIX509Cert::EMAIL_CERT:
1256 rv = mNSSComponent->GetPIPNSSBundleString("CertEmail", _retval);
1257 break;
1258 default:
1259 rv = mNSSComponent->GetPIPNSSBundleString("CertUnknown", _retval);
1260 break;
1261 }
1262
1263 } else {
1264 return NS_ERROR_FAILURE;
1265 }
1266 if (mCellText) {
1267 nsCOMPtr<nsISupportsString> text(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
1268 NS_ENSURE_SUCCESS(rv, rv);
1269 text->SetData(_retval);
1270 mCellText->ReplaceElementAt(text, arrayIndex, false);
1271 }
1272 return rv;
1273 }
1274
1275 /* void setTree (in nsITreeBoxObject tree); */
1276 NS_IMETHODIMP
1277 nsCertTree::SetTree(nsITreeBoxObject *tree)
1278 {
1279 mTree = tree;
1280 return NS_OK;
1281 }
1282
1283 /* void toggleOpenState (in long index); */
1284 NS_IMETHODIMP
1285 nsCertTree::ToggleOpenState(int32_t index)
1286 {
1287 if (!mTreeArray)
1288 return NS_ERROR_NOT_INITIALIZED;
1289 treeArrayEl *el = GetThreadDescAtIndex(index);
1290 if (el) {
1291 el->open = !el->open;
1292 int32_t newChildren = (el->open) ? el->numChildren : -el->numChildren;
1293 if (mTree) mTree->RowCountChanged(index + 1, newChildren);
1294 }
1295 return NS_OK;
1296 }
1297
1298 /* void cycleHeader (in nsITreeColumn); */
1299 NS_IMETHODIMP
1300 nsCertTree::CycleHeader(nsITreeColumn* col)
1301 {
1302 return NS_OK;
1303 }
1304
1305 /* void selectionChanged (); */
1306 NS_IMETHODIMP
1307 nsCertTree::SelectionChanged()
1308 {
1309 return NS_ERROR_NOT_IMPLEMENTED;
1310 }
1311
1312 /* void cycleCell (in long row, in nsITreeColumn col); */
1313 NS_IMETHODIMP
1314 nsCertTree::CycleCell(int32_t row, nsITreeColumn* col)
1315 {
1316 return NS_OK;
1317 }
1318
1319 /* boolean isEditable (in long row, in nsITreeColumn col); */
1320 NS_IMETHODIMP
1321 nsCertTree::IsEditable(int32_t row, nsITreeColumn* col, bool *_retval)
1322 {
1323 *_retval = false;
1324 return NS_OK;
1325 }
1326
1327 /* boolean isSelectable (in long row, in nsITreeColumn col); */
1328 NS_IMETHODIMP
1329 nsCertTree::IsSelectable(int32_t row, nsITreeColumn* col, bool *_retval)
1330 {
1331 *_retval = false;
1332 return NS_OK;
1333 }
1334
1335 /* void setCellValue (in long row, in nsITreeColumn col, in AString value); */
1336 NS_IMETHODIMP
1337 nsCertTree::SetCellValue(int32_t row, nsITreeColumn* col,
1338 const nsAString& value)
1339 {
1340 return NS_OK;
1341 }
1342
1343 /* void setCellText (in long row, in nsITreeColumn col, in AString value); */
1344 NS_IMETHODIMP
1345 nsCertTree::SetCellText(int32_t row, nsITreeColumn* col,
1346 const nsAString& value)
1347 {
1348 return NS_OK;
1349 }
1350
1351 /* void performAction (in wstring action); */
1352 NS_IMETHODIMP
1353 nsCertTree::PerformAction(const char16_t *action)
1354 {
1355 return NS_OK;
1356 }
1357
1358 /* void performActionOnRow (in wstring action, in long row); */
1359 NS_IMETHODIMP
1360 nsCertTree::PerformActionOnRow(const char16_t *action, int32_t row)
1361 {
1362 return NS_OK;
1363 }
1364
1365 /* void performActionOnCell (in wstring action, in long row,
1366 * in wstring colID);
1367 */
1368 NS_IMETHODIMP
1369 nsCertTree::PerformActionOnCell(const char16_t *action, int32_t row,
1370 nsITreeColumn* col)
1371 {
1372 return NS_OK;
1373 }
1374
1375 #ifdef DEBUG_CERT_TREE
1376 void
1377 nsCertTree::dumpMap()
1378 {
1379 for (int i=0; i<mNumOrgs; i++) {
1380 nsAutoString org(mTreeArray[i].orgName);
1381 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("ORG[%s]", NS_LossyConvertUTF16toASCII(org).get()));
1382 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("OPEN[%d]", mTreeArray[i].open));
1383 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("INDEX[%d]", mTreeArray[i].certIndex));
1384 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NCHILD[%d]", mTreeArray[i].numChildren));
1385 }
1386 for (int i=0; i<mNumRows; i++) {
1387 treeArrayEl *el = GetThreadDescAtIndex(i);
1388 if (el) {
1389 nsAutoString td(el->orgName);
1390 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("thread desc[%d]: %s", i, NS_LossyConvertUTF16toASCII(td).get()));
1391 }
1392 nsCOMPtr<nsIX509Cert> ct = GetCertAtIndex(i);
1393 if (ct) {
1394 char16_t *goo;
1395 ct->GetCommonName(&goo);
1396 nsAutoString doo(goo);
1397 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert [%d]: %s", i, NS_LossyConvertUTF16toASCII(doo).get()));
1398 }
1399 }
1400 }
1401 #endif
1402
1403 //
1404 // CanDrop
1405 //
1406 NS_IMETHODIMP nsCertTree::CanDrop(int32_t index, int32_t orientation,
1407 nsIDOMDataTransfer* aDataTransfer, bool *_retval)
1408 {
1409 NS_ENSURE_ARG_POINTER(_retval);
1410 *_retval = false;
1411
1412 return NS_OK;
1413 }
1414
1415
1416 //
1417 // Drop
1418 //
1419 NS_IMETHODIMP nsCertTree::Drop(int32_t row, int32_t orient, nsIDOMDataTransfer* aDataTransfer)
1420 {
1421 return NS_OK;
1422 }
1423
1424
1425 //
1426 // IsSorted
1427 //
1428 // ...
1429 //
1430 NS_IMETHODIMP nsCertTree::IsSorted(bool *_retval)
1431 {
1432 *_retval = false;
1433 return NS_OK;
1434 }
1435
1436 #define RETURN_NOTHING
1437
1438 void
1439 nsCertTree::CmpInitCriterion(nsIX509Cert *cert, CompareCacheHashEntry *entry,
1440 sortCriterion crit, int32_t level)
1441 {
1442 NS_ENSURE_TRUE(cert && entry, RETURN_NOTHING);
1443
1444 entry->mCritInit[level] = true;
1445 nsXPIDLString &str = entry->mCrit[level];
1446
1447 switch (crit) {
1448 case sort_IssuerOrg:
1449 cert->GetIssuerOrganization(str);
1450 if (str.IsEmpty())
1451 cert->GetCommonName(str);
1452 break;
1453 case sort_Org:
1454 cert->GetOrganization(str);
1455 break;
1456 case sort_Token:
1457 cert->GetTokenName(str);
1458 break;
1459 case sort_CommonName:
1460 cert->GetCommonName(str);
1461 break;
1462 case sort_IssuedDateDescending:
1463 {
1464 nsresult rv;
1465 nsCOMPtr<nsIX509CertValidity> validity;
1466 PRTime notBefore;
1467
1468 rv = cert->GetValidity(getter_AddRefs(validity));
1469 if (NS_SUCCEEDED(rv)) {
1470 rv = validity->GetNotBefore(&notBefore);
1471 }
1472
1473 if (NS_SUCCEEDED(rv)) {
1474 PRExplodedTime explodedTime;
1475 PR_ExplodeTime(notBefore, PR_GMTParameters, &explodedTime);
1476 char datebuf[20]; // 4 + 2 + 2 + 2 + 2 + 2 + 1 = 15
1477 if (0 != PR_FormatTime(datebuf, sizeof(datebuf), "%Y%m%d%H%M%S", &explodedTime)) {
1478 str = NS_ConvertASCIItoUTF16(nsDependentCString(datebuf));
1479 }
1480 }
1481 }
1482 break;
1483 case sort_Email:
1484 cert->GetEmailAddress(str);
1485 break;
1486 case sort_None:
1487 default:
1488 break;
1489 }
1490 }
1491
1492 int32_t
1493 nsCertTree::CmpByCrit(nsIX509Cert *a, CompareCacheHashEntry *ace,
1494 nsIX509Cert *b, CompareCacheHashEntry *bce,
1495 sortCriterion crit, int32_t level)
1496 {
1497 NS_ENSURE_TRUE(a && ace && b && bce, 0);
1498
1499 if (!ace->mCritInit[level]) {
1500 CmpInitCriterion(a, ace, crit, level);
1501 }
1502
1503 if (!bce->mCritInit[level]) {
1504 CmpInitCriterion(b, bce, crit, level);
1505 }
1506
1507 nsXPIDLString &str_a = ace->mCrit[level];
1508 nsXPIDLString &str_b = bce->mCrit[level];
1509
1510 int32_t result;
1511 if (str_a && str_b)
1512 result = Compare(str_a, str_b, nsCaseInsensitiveStringComparator());
1513 else
1514 result = !str_a ? (!str_b ? 0 : -1) : 1;
1515
1516 if (sort_IssuedDateDescending == crit)
1517 result *= -1; // reverse compare order
1518
1519 return result;
1520 }
1521
1522 int32_t
1523 nsCertTree::CmpBy(void *cache, nsIX509Cert *a, nsIX509Cert *b,
1524 sortCriterion c0, sortCriterion c1, sortCriterion c2)
1525 {
1526 // This will be called when comparing items for display sorting.
1527 // Some items might have no cert associated, so either a or b is null.
1528 // We want all those orphans show at the top of the list,
1529 // so we treat a null cert as "smaller" by returning -1.
1530 // We don't try to sort within the group of no-cert entries,
1531 // so we treat them as equal wrt sort order.
1532
1533 if (!a && !b)
1534 return 0;
1535
1536 if (!a)
1537 return -1;
1538
1539 if (!b)
1540 return 1;
1541
1542 NS_ENSURE_TRUE(cache && a && b, 0);
1543
1544 CompareCacheHashEntry *ace = getCacheEntry(cache, a);
1545 CompareCacheHashEntry *bce = getCacheEntry(cache, b);
1546
1547 int32_t cmp;
1548 cmp = CmpByCrit(a, ace, b, bce, c0, 0);
1549 if (cmp != 0)
1550 return cmp;
1551
1552 if (c1 != sort_None) {
1553 cmp = CmpByCrit(a, ace, b, bce, c1, 1);
1554 if (cmp != 0)
1555 return cmp;
1556
1557 if (c2 != sort_None) {
1558 return CmpByCrit(a, ace, b, bce, c2, 2);
1559 }
1560 }
1561
1562 return cmp;
1563 }
1564
1565 int32_t
1566 nsCertTree::CmpCACert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
1567 {
1568 // XXX we assume issuer org is always criterion 1
1569 return CmpBy(cache, a, b, sort_IssuerOrg, sort_Org, sort_Token);
1570 }
1571
1572 int32_t
1573 nsCertTree::CmpWebSiteCert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
1574 {
1575 // XXX we assume issuer org is always criterion 1
1576 return CmpBy(cache, a, b, sort_IssuerOrg, sort_CommonName, sort_None);
1577 }
1578
1579 int32_t
1580 nsCertTree::CmpUserCert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
1581 {
1582 // XXX we assume issuer org is always criterion 1
1583 return CmpBy(cache, a, b, sort_IssuerOrg, sort_Token, sort_IssuedDateDescending);
1584 }
1585
1586 int32_t
1587 nsCertTree::CmpEmailCert(void *cache, nsIX509Cert *a, nsIX509Cert *b)
1588 {
1589 // XXX we assume issuer org is always criterion 1
1590 return CmpBy(cache, a, b, sort_IssuerOrg, sort_Email, sort_CommonName);
1591 }
1592

mercurial