1 // Copyright 2012 The Chromium Authors
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/ev_root_ca_metadata.h"
6
7 #include <string_view>
8
9 #include "base/containers/contains.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "build/build_config.h"
13 #include "third_party/boringssl/src/pki/input.h"
14 #if defined(PLATFORM_USES_CHROMIUM_EV_METADATA)
15 #include "third_party/boringssl/src/include/openssl/bytestring.h"
16 #include "third_party/boringssl/src/include/openssl/mem.h"
17 #endif
18
19 namespace net {
20
21 namespace {
22 #if defined(PLATFORM_USES_CHROMIUM_EV_METADATA)
23 // Raw metadata.
24 struct EVMetadata {
25 // kMaxOIDsPerCA is the number of OIDs that we can support per root CA. At
26 // least one CA has different EV policies for business vs government
27 // entities and, in the case of cross-signing, we might need to list another
28 // CA's policy OID under the cross-signing root.
29 static const size_t kMaxOIDsPerCA = 2;
30
31 // The SHA-256 fingerprint of the root CA certificate, used as a unique
32 // identifier for a root CA certificate.
33 SHA256HashValue fingerprint;
34
35 // The EV policy OIDs of the root CA.
36 const std::string_view policy_oids[kMaxOIDsPerCA];
37 };
38
39 #include "net/data/ssl/chrome_root_store/chrome-ev-roots-inc.cc"
40
41 #endif // defined(PLATFORM_USES_CHROMIUM_EV_METADATA)
42 } // namespace
43
44 static base::LazyInstance<EVRootCAMetadata>::Leaky g_ev_root_ca_metadata =
45 LAZY_INSTANCE_INITIALIZER;
46
47 // static
GetInstance()48 EVRootCAMetadata* EVRootCAMetadata::GetInstance() {
49 return g_ev_root_ca_metadata.Pointer();
50 }
51
52 #if defined(PLATFORM_USES_CHROMIUM_EV_METADATA)
53
54 namespace {
55
OIDStringToDER(std::string_view policy)56 std::string OIDStringToDER(std::string_view policy) {
57 uint8_t* der;
58 size_t len;
59 bssl::ScopedCBB cbb;
60 if (!CBB_init(cbb.get(), 32) ||
61 !CBB_add_asn1_oid_from_text(cbb.get(), policy.data(), policy.size()) ||
62 !CBB_finish(cbb.get(), &der, &len)) {
63 return std::string();
64 }
65 bssl::UniquePtr<uint8_t> delete_der(der);
66 return std::string(reinterpret_cast<const char*>(der), len);
67 }
68
69 } // namespace
70
IsEVPolicyOID(bssl::der::Input policy_oid) const71 bool EVRootCAMetadata::IsEVPolicyOID(bssl::der::Input policy_oid) const {
72 return policy_oids_.find(policy_oid.AsStringView()) != policy_oids_.end();
73 }
74
HasEVPolicyOID(const SHA256HashValue & fingerprint,bssl::der::Input policy_oid) const75 bool EVRootCAMetadata::HasEVPolicyOID(const SHA256HashValue& fingerprint,
76 bssl::der::Input policy_oid) const {
77 PolicyOIDMap::const_iterator iter = ev_policy_.find(fingerprint);
78 if (iter == ev_policy_.end())
79 return false;
80 for (const std::string& ev_oid : iter->second) {
81 if (bssl::der::Input(ev_oid) == policy_oid) {
82 return true;
83 }
84 }
85 return false;
86 }
87
AddEVCA(const SHA256HashValue & fingerprint,const char * policy)88 bool EVRootCAMetadata::AddEVCA(const SHA256HashValue& fingerprint,
89 const char* policy) {
90 if (ev_policy_.find(fingerprint) != ev_policy_.end())
91 return false;
92
93 std::string der_policy = OIDStringToDER(policy);
94 if (der_policy.empty())
95 return false;
96
97 ev_policy_[fingerprint].push_back(der_policy);
98 policy_oids_.insert(der_policy);
99 return true;
100 }
101
RemoveEVCA(const SHA256HashValue & fingerprint)102 bool EVRootCAMetadata::RemoveEVCA(const SHA256HashValue& fingerprint) {
103 PolicyOIDMap::iterator it = ev_policy_.find(fingerprint);
104 if (it == ev_policy_.end())
105 return false;
106 std::string oid = it->second[0];
107 ev_policy_.erase(it);
108 policy_oids_.erase(oid);
109 return true;
110 }
111
112 #else
113
114 // These are just stub functions for platforms where we don't use this EV
115 // metadata.
116 //
117
IsEVPolicyOID(bssl::der::Input policy_oid) const118 bool EVRootCAMetadata::IsEVPolicyOID(bssl::der::Input policy_oid) const {
119 LOG(WARNING) << "Not implemented";
120 return false;
121 }
122
HasEVPolicyOID(const SHA256HashValue & fingerprint,bssl::der::Input policy_oid) const123 bool EVRootCAMetadata::HasEVPolicyOID(const SHA256HashValue& fingerprint,
124 bssl::der::Input policy_oid) const {
125 LOG(WARNING) << "Not implemented";
126 return false;
127 }
128
AddEVCA(const SHA256HashValue & fingerprint,const char * policy)129 bool EVRootCAMetadata::AddEVCA(const SHA256HashValue& fingerprint,
130 const char* policy) {
131 LOG(WARNING) << "Not implemented";
132 return true;
133 }
134
RemoveEVCA(const SHA256HashValue & fingerprint)135 bool EVRootCAMetadata::RemoveEVCA(const SHA256HashValue& fingerprint) {
136 LOG(WARNING) << "Not implemented";
137 return true;
138 }
139
140 #endif
141
EVRootCAMetadata()142 EVRootCAMetadata::EVRootCAMetadata() {
143 // Constructs the object from the raw metadata in kEvRootCaMetadata.
144 #if defined(PLATFORM_USES_CHROMIUM_EV_METADATA)
145 for (const auto& ev_root : kEvRootCaMetadata) {
146 for (const auto& policy : ev_root.policy_oids) {
147 if (policy.empty())
148 break;
149
150 std::string policy_der = OIDStringToDER(policy);
151 if (policy_der.empty()) {
152 LOG(ERROR) << "Failed to decode OID: " << policy;
153 continue;
154 }
155
156 ev_policy_[ev_root.fingerprint].push_back(policy_der);
157 policy_oids_.insert(policy_der);
158 }
159 }
160 #endif
161 }
162
163 EVRootCAMetadata::~EVRootCAMetadata() = default;
164
165 } // namespace net
166