known_roots_nss.cc 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. // Copyright (c) 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/cert/known_roots_nss.h"
  5. #include <cert.h>
  6. #include <dlfcn.h>
  7. #include <pk11pub.h>
  8. #include <secmod.h>
  9. #include <memory>
  10. #include "base/compiler_specific.h"
  11. #include "crypto/nss_util_internal.h"
  12. #include "net/base/hash_value.h"
  13. #include "net/cert/x509_util_nss.h"
  14. namespace net {
  15. namespace {
  16. // This can be removed once the minimum NSS version to build is >= 3.30.
  17. #if !defined(CKA_NSS_MOZILLA_CA_POLICY)
  18. #define CKA_NSS_MOZILLA_CA_POLICY (CKA_NSS + 34)
  19. #endif
  20. using PK11HasAttributeSetFunction = CK_BBOOL (*)(PK11SlotInfo* slot,
  21. CK_OBJECT_HANDLE id,
  22. CK_ATTRIBUTE_TYPE type,
  23. PRBool haslock);
  24. } // namespace
  25. // IsKnownRoot returns true if the given certificate is one that we believe
  26. // is a standard (as opposed to user-installed) root.
  27. NO_SANITIZE("cfi-icall")
  28. bool IsKnownRoot(CERTCertificate* root) {
  29. if (!root || !root->slot)
  30. return false;
  31. static PK11HasAttributeSetFunction pk11_has_attribute_set =
  32. reinterpret_cast<PK11HasAttributeSetFunction>(
  33. dlsym(RTLD_DEFAULT, "PK11_HasAttributeSet"));
  34. if (pk11_has_attribute_set) {
  35. // Historically, the set of root certs was determined based on whether or
  36. // not it was part of nssckbi.[so,dll], the read-only PKCS#11 module that
  37. // exported the certs with trust settings. However, some distributions,
  38. // notably those in the Red Hat family, replace nssckbi with a redirect to
  39. // their own store, such as from p11-kit, which can support more robust
  40. // trust settings, like per-system trust, admin-defined, and user-defined
  41. // trust.
  42. //
  43. // As a given certificate may exist in multiple modules and slots, scan
  44. // through all of the available modules, all of the (connected) slots on
  45. // those modules, and check to see if it has the CKA_NSS_MOZILLA_CA_POLICY
  46. // attribute set. This attribute indicates it's from the upstream Mozilla
  47. // trust store, and these distributions preserve the attribute as a flag.
  48. crypto::AutoSECMODListReadLock lock_id;
  49. for (const SECMODModuleList* item = SECMOD_GetDefaultModuleList();
  50. item != nullptr; item = item->next) {
  51. for (int i = 0; i < item->module->slotCount; ++i) {
  52. PK11SlotInfo* slot = item->module->slots[i];
  53. if (PK11_IsPresent(slot) && PK11_HasRootCerts(slot)) {
  54. CK_OBJECT_HANDLE handle = PK11_FindCertInSlot(slot, root, nullptr);
  55. if (handle != CK_INVALID_HANDLE &&
  56. pk11_has_attribute_set(slot, handle, CKA_NSS_MOZILLA_CA_POLICY,
  57. PR_FALSE) == CK_TRUE) {
  58. return true;
  59. }
  60. }
  61. }
  62. }
  63. return false;
  64. }
  65. // This magic name is taken from
  66. // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/builtins/constants.c&rev=1.13&mark=86,89#79
  67. return 0 == strcmp(PK11_GetSlotName(root->slot), "NSS Builtin Objects");
  68. }
  69. } // namespace net