blob: ff4507f8e111d567ba3ff4a25c630b281020d587 [file] [log] [blame]
eromanf2971fd2017-04-20 20:10:451// 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
5#include "net/cert/known_roots_nss.h"
6
7#include <cert.h>
Ryan Sleevib7b04572017-12-28 02:15:418#include <dlfcn.h>
eromanf2971fd2017-04-20 20:10:459#include <pk11pub.h>
Ryan Sleevib7b04572017-12-28 02:15:4110#include <secmod.h>
eromanf2971fd2017-04-20 20:10:4511
12#include <memory>
13
Ryan Sleevib7b04572017-12-28 02:15:4114#include "base/memory/protected_memory.h"
15#include "base/memory/protected_memory_cfi.h"
16#include "crypto/nss_util_internal.h"
17#include "net/base/hash_value.h"
18#include "net/cert/x509_util_nss.h"
19
eromanf2971fd2017-04-20 20:10:4520namespace net {
21
Ryan Sleevib7b04572017-12-28 02:15:4122namespace {
23
24// This can be removed once the minimum NSS version to build is >= 3.30.
25#if !defined(CKA_NSS_MOZILLA_CA_POLICY)
26#define CKA_NSS_MOZILLA_CA_POLICY (CKA_NSS + 34)
27#endif
28
29using PK11HasAttributeSetFunction = CK_BBOOL (*)(PK11SlotInfo* slot,
30 CK_OBJECT_HANDLE id,
31 CK_ATTRIBUTE_TYPE type,
32 PRBool haslock);
33static PROTECTED_MEMORY_SECTION
34 base::ProtectedMemory<PK11HasAttributeSetFunction>
35 g_pk11_has_attribute_set;
36
37// The function pointer for PK11_HasAttributeSet is saved to read-only memory
38// after being dynamically resolved as a security mitigation to prevent the
39// pointer from being tampered with. See https://crbug.com/771365 for details.
40const base::ProtectedMemory<PK11HasAttributeSetFunction>&
41ResolvePK11HasAttributeSet() {
42 static base::ProtectedMemory<PK11HasAttributeSetFunction>::Initializer init(
43 &g_pk11_has_attribute_set,
44 reinterpret_cast<PK11HasAttributeSetFunction>(
45 dlsym(RTLD_DEFAULT, "PK11_HasAttributeSet")));
46 return g_pk11_has_attribute_set;
47}
48
49} // namespace
50
eromanf2971fd2017-04-20 20:10:4551// IsKnownRoot returns true if the given certificate is one that we believe
52// is a standard (as opposed to user-installed) root.
53bool IsKnownRoot(CERTCertificate* root) {
54 if (!root || !root->slot)
55 return false;
56
Ryan Sleevib7b04572017-12-28 02:15:4157 if (*ResolvePK11HasAttributeSet() != nullptr) {
58 // Historically, the set of root certs was determined based on whether or
59 // not it was part of nssckbi.[so,dll], the read-only PKCS#11 module that
60 // exported the certs with trust settings. However, some distributions,
61 // notably those in the Red Hat family, replace nssckbi with a redirect to
62 // their own store, such as from p11-kit, which can support more robust
63 // trust settings, like per-system trust, admin-defined, and user-defined
64 // trust.
65 //
66 // As a given certificate may exist in multiple modules and slots, scan
67 // through all of the available modules, all of the (connected) slots on
68 // those modules, and check to see if it has the CKA_NSS_MOZILLA_CA_POLICY
69 // attribute set. This attribute indicates it's from the upstream Mozilla
70 // trust store, and these distributions preserve the attribute as a flag.
71 crypto::AutoSECMODListReadLock lock_id;
72 for (const SECMODModuleList* item = SECMOD_GetDefaultModuleList();
73 item != nullptr; item = item->next) {
74 for (int i = 0; i < item->module->slotCount; ++i) {
75 PK11SlotInfo* slot = item->module->slots[i];
76 if (PK11_IsPresent(slot) && PK11_HasRootCerts(slot)) {
77 CK_OBJECT_HANDLE handle = PK11_FindCertInSlot(slot, root, nullptr);
78 if (handle != CK_INVALID_HANDLE &&
79 UnsanitizedCfiCall(ResolvePK11HasAttributeSet())(
80 root->slot, handle, CKA_NSS_MOZILLA_CA_POLICY, PR_FALSE) ==
81 CK_TRUE) {
82 return true;
83 }
84 }
85 }
86 }
Ryan Sleevib0784be2018-08-08 19:43:0287
88 return false;
Ryan Sleevib7b04572017-12-28 02:15:4189 }
90
eromanf2971fd2017-04-20 20:10:4591 // This magic name is taken from
92 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/builtins/constants.c&rev=1.13&mark=86,89#79
93 return 0 == strcmp(PK11_GetSlotName(root->slot), "NSS Builtin Objects");
94}
95
96} // namespace net