1 // Copyright (c) 2010 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/base/ev_root_ca_metadata.h"
6
7 #if defined(USE_NSS)
8 #include <cert.h>
9 #include <pkcs11n.h>
10 #include <secerr.h>
11 #include <secoid.h>
12 #elif defined(OS_WIN)
13 #include <stdlib.h>
14 #endif
15
16 #include "base/lazy_instance.h"
17 #include "base/logging.h"
18
19 namespace net {
20
21 // Raw metadata.
22 struct EVMetadata {
23 // The SHA-1 fingerprint of the root CA certificate, used as a unique
24 // identifier for a root CA certificate.
25 SHA1Fingerprint fingerprint;
26
27 // The EV policy OID of the root CA.
28 // Note: a root CA may have multiple EV policies. When that actually
29 // happens, we'll need to support that.
30 const char* policy_oid;
31 };
32
33 static const EVMetadata ev_root_ca_metadata[] = {
34 // AddTrust External CA Root
35 // https://addtrustexternalcaroot-ev.comodoca.com
36 { { { 0x02, 0xfa, 0xf3, 0xe2, 0x91, 0x43, 0x54, 0x68, 0x60, 0x78,
37 0x57, 0x69, 0x4d, 0xf5, 0xe4, 0x5b, 0x68, 0x85, 0x18, 0x68 } },
38 "1.3.6.1.4.1.6449.1.2.1.5.1"
39 },
40 // AffirmTrust Commercial
41 // https://commercial.affirmtrust.com/
42 { { { 0xf9, 0xb5, 0xb6, 0x32, 0x45, 0x5f, 0x9c, 0xbe, 0xec, 0x57,
43 0x5f, 0x80, 0xdc, 0xe9, 0x6e, 0x2c, 0xc7, 0xb2, 0x78, 0xb7 } },
44 "1.3.6.1.4.1.34697.2.1"
45 },
46 // AffirmTrust Networking
47 // https://networking.affirmtrust.com:4431
48 { { { 0x29, 0x36, 0x21, 0x02, 0x8b, 0x20, 0xed, 0x02, 0xf5, 0x66,
49 0xc5, 0x32, 0xd1, 0xd6, 0xed, 0x90, 0x9f, 0x45, 0x00, 0x2f } },
50 "1.3.6.1.4.1.34697.2.2"
51 },
52 // AffirmTrust Premium
53 // https://premium.affirmtrust.com:4432/
54 { { { 0xd8, 0xa6, 0x33, 0x2c, 0xe0, 0x03, 0x6f, 0xb1, 0x85, 0xf6,
55 0x63, 0x4f, 0x7d, 0x6a, 0x06, 0x65, 0x26, 0x32, 0x28, 0x27 } },
56 "1.3.6.1.4.1.34697.2.3"
57 },
58 // AffirmTrust Premium ECC
59 // https://premiumecc.affirmtrust.com:4433/
60 { { { 0xb8, 0x23, 0x6b, 0x00, 0x2f, 0x1d, 0x16, 0x86, 0x53, 0x01,
61 0x55, 0x6c, 0x11, 0xa4, 0x37, 0xca, 0xeb, 0xff, 0xc3, 0xbb } },
62 "1.3.6.1.4.1.34697.2.4"
63 },
64 // CertPlus Class 2 Primary CA (KEYNECTIS)
65 // https://www.keynectis.com/
66 { { { 0x74, 0x20, 0x74, 0x41, 0x72, 0x9c, 0xdd, 0x92, 0xec, 0x79,
67 0x31, 0xd8, 0x23, 0x10, 0x8d, 0xc2, 0x81, 0x92, 0xe2, 0xbb } },
68 "1.3.6.1.4.1.22234.2.5.2.3.1"
69 },
70 // COMODO Certification Authority
71 // https://secure.comodo.com/
72 { { { 0x66, 0x31, 0xbf, 0x9e, 0xf7, 0x4f, 0x9e, 0xb6, 0xc9, 0xd5,
73 0xa6, 0x0c, 0xba, 0x6a, 0xbe, 0xd1, 0xf7, 0xbd, 0xef, 0x7b } },
74 "1.3.6.1.4.1.6449.1.2.1.5.1"
75 },
76 // COMODO ECC Certification Authority
77 // https://comodoecccertificationauthority-ev.comodoca.com/
78 { { { 0x9f, 0x74, 0x4e, 0x9f, 0x2b, 0x4d, 0xba, 0xec, 0x0f, 0x31,
79 0x2c, 0x50, 0xb6, 0x56, 0x3b, 0x8e, 0x2d, 0x93, 0xc3, 0x11 } },
80 "1.3.6.1.4.1.6449.1.2.1.5.1"
81 },
82 // Cybertrust Global Root
83 // https://evup.cybertrust.ne.jp/ctj-ev-upgrader/evseal.gif
84 { { { 0x5f, 0x43, 0xe5, 0xb1, 0xbf, 0xf8, 0x78, 0x8c, 0xac, 0x1c,
85 0xc7, 0xca, 0x4a, 0x9a, 0xc6, 0x22, 0x2b, 0xcc, 0x34, 0xc6 } },
86 "1.3.6.1.4.1.6334.1.100.1"
87 },
88 // DigiCert High Assurance EV Root CA
89 // https://www.digicert.com
90 { { { 0x5f, 0xb7, 0xee, 0x06, 0x33, 0xe2, 0x59, 0xdb, 0xad, 0x0c,
91 0x4c, 0x9a, 0xe6, 0xd3, 0x8f, 0x1a, 0x61, 0xc7, 0xdc, 0x25 } },
92 "2.16.840.1.114412.2.1"
93 },
94 // Entrust.net Secure Server Certification Authority
95 // https://www.entrust.net/
96 { { { 0x99, 0xa6, 0x9b, 0xe6, 0x1a, 0xfe, 0x88, 0x6b, 0x4d, 0x2b,
97 0x82, 0x00, 0x7c, 0xb8, 0x54, 0xfc, 0x31, 0x7e, 0x15, 0x39 } },
98 "2.16.840.1.114028.10.1.2"
99 },
100 // Entrust Root Certification Authority
101 // https://www.entrust.net/
102 { { { 0xb3, 0x1e, 0xb1, 0xb7, 0x40, 0xe3, 0x6c, 0x84, 0x02, 0xda,
103 0xdc, 0x37, 0xd4, 0x4d, 0xf5, 0xd4, 0x67, 0x49, 0x52, 0xf9 } },
104 "2.16.840.1.114028.10.1.2"
105 },
106 // Equifax Secure Certificate Authority (GeoTrust)
107 // https://www.geotrust.com/
108 { { { 0xd2, 0x32, 0x09, 0xad, 0x23, 0xd3, 0x14, 0x23, 0x21, 0x74,
109 0xe4, 0x0d, 0x7f, 0x9d, 0x62, 0x13, 0x97, 0x86, 0x63, 0x3a } },
110 "1.3.6.1.4.1.14370.1.6"
111 },
112 // GeoTrust Primary Certification Authority
113 // https://www.geotrust.com/
114 { { { 0x32, 0x3c, 0x11, 0x8e, 0x1b, 0xf7, 0xb8, 0xb6, 0x52, 0x54,
115 0xe2, 0xe2, 0x10, 0x0d, 0xd6, 0x02, 0x90, 0x37, 0xf0, 0x96 } },
116 "1.3.6.1.4.1.14370.1.6"
117 },
118 // GlobalSign
119 // https://www.globalsign.com/
120 { { { 0x75, 0xe0, 0xab, 0xb6, 0x13, 0x85, 0x12, 0x27, 0x1c, 0x04,
121 0xf8, 0x5f, 0xdd, 0xde, 0x38, 0xe4, 0xb7, 0x24, 0x2e, 0xfe } },
122 "1.3.6.1.4.1.4146.1.1"
123 },
124 // GlobalSign Root CA
125 { { { 0xb1, 0xbc, 0x96, 0x8b, 0xd4, 0xf4, 0x9d, 0x62, 0x2a, 0xa8,
126 0x9a, 0x81, 0xf2, 0x15, 0x01, 0x52, 0xa4, 0x1d, 0x82, 0x9c } },
127 "1.3.6.1.4.1.4146.1.1"
128 },
129 // Go Daddy Class 2 Certification Authority
130 // https://www.godaddy.com/
131 { { { 0x27, 0x96, 0xba, 0xe6, 0x3f, 0x18, 0x01, 0xe2, 0x77, 0x26,
132 0x1b, 0xa0, 0xd7, 0x77, 0x70, 0x02, 0x8f, 0x20, 0xee, 0xe4 } },
133 "2.16.840.1.114413.1.7.23.3"
134 },
135 // GTE CyberTrust Global Root
136 // https://www.cybertrust.ne.jp/
137 { { { 0x97, 0x81, 0x79, 0x50, 0xd8, 0x1c, 0x96, 0x70, 0xcc, 0x34,
138 0xd8, 0x09, 0xcf, 0x79, 0x44, 0x31, 0x36, 0x7e, 0xf4, 0x74 } },
139 "1.3.6.1.4.1.6334.1.100.1"
140 },
141 // Network Solutions Certificate Authority
142 // https://www.networksolutions.com/website-packages/index.jsp
143 { { { 0x74, 0xf8, 0xa3, 0xc3, 0xef, 0xe7, 0xb3, 0x90, 0x06, 0x4b,
144 0x83, 0x90, 0x3c, 0x21, 0x64, 0x60, 0x20, 0xe5, 0xdf, 0xce } },
145 "1.3.6.1.4.1.782.1.2.1.8.1"
146 },
147 // QuoVadis Root CA 2
148 // https://www.quovadis.bm/
149 { { { 0xca, 0x3a, 0xfb, 0xcf, 0x12, 0x40, 0x36, 0x4b, 0x44, 0xb2,
150 0x16, 0x20, 0x88, 0x80, 0x48, 0x39, 0x19, 0x93, 0x7c, 0xf7 } },
151 "1.3.6.1.4.1.8024.0.2.100.1.2"
152 },
153 // SecureTrust CA, SecureTrust Corporation
154 // https://www.securetrust.com
155 // https://www.trustwave.com/
156 { { { 0x87, 0x82, 0xc6, 0xc3, 0x04, 0x35, 0x3b, 0xcf, 0xd2, 0x96,
157 0x92, 0xd2, 0x59, 0x3e, 0x7d, 0x44, 0xd9, 0x34, 0xff, 0x11 } },
158 "2.16.840.1.114404.1.1.2.4.1"
159 },
160 // Secure Global CA, SecureTrust Corporation
161 { { { 0x3a, 0x44, 0x73, 0x5a, 0xe5, 0x81, 0x90, 0x1f, 0x24, 0x86,
162 0x61, 0x46, 0x1e, 0x3b, 0x9c, 0xc4, 0x5f, 0xf5, 0x3a, 0x1b } },
163 "2.16.840.1.114404.1.1.2.4.1"
164 },
165 // Security Communication RootCA1
166 // https://www.secomtrust.net/contact/form.html
167 { { { 0x36, 0xb1, 0x2b, 0x49, 0xf9, 0x81, 0x9e, 0xd7, 0x4c, 0x9e,
168 0xbc, 0x38, 0x0f, 0xc6, 0x56, 0x8f, 0x5d, 0xac, 0xb2, 0xf7 } },
169 "1.2.392.200091.100.721.1"
170 },
171 // Security Communication EV RootCA1
172 // https://www.secomtrust.net/contact/form.html
173 { { { 0xfe, 0xb8, 0xc4, 0x32, 0xdc, 0xf9, 0x76, 0x9a, 0xce, 0xae,
174 0x3d, 0xd8, 0x90, 0x8f, 0xfd, 0x28, 0x86, 0x65, 0x64, 0x7d } },
175 "1.2.392.200091.100.721.1"
176 },
177 // StartCom Certification Authority
178 // https://www.startssl.com/
179 { { { 0x3e, 0x2b, 0xf7, 0xf2, 0x03, 0x1b, 0x96, 0xf3, 0x8c, 0xe6,
180 0xc4, 0xd8, 0xa8, 0x5d, 0x3e, 0x2d, 0x58, 0x47, 0x6a, 0x0f } },
181 "1.3.6.1.4.1.23223.1.1.1"
182 },
183 // Starfield Class 2 Certification Authority
184 // https://www.starfieldtech.com/
185 { { { 0xad, 0x7e, 0x1c, 0x28, 0xb0, 0x64, 0xef, 0x8f, 0x60, 0x03,
186 0x40, 0x20, 0x14, 0xc3, 0xd0, 0xe3, 0x37, 0x0e, 0xb5, 0x8a } },
187 "2.16.840.1.114414.1.7.23.3"
188 },
189 // SwissSign Gold CA - G2
190 // https://testevg2.swisssign.net/
191 { { { 0xd8, 0xc5, 0x38, 0x8a, 0xb7, 0x30, 0x1b, 0x1b, 0x6e, 0xd4,
192 0x7a, 0xe6, 0x45, 0x25, 0x3a, 0x6f, 0x9f, 0x1a, 0x27, 0x61 } },
193 "2.16.756.1.89.1.2.1.1"
194 },
195 // Thawte Premium Server CA
196 // https://www.thawte.com/
197 { { { 0x62, 0x7f, 0x8d, 0x78, 0x27, 0x65, 0x63, 0x99, 0xd2, 0x7d,
198 0x7f, 0x90, 0x44, 0xc9, 0xfe, 0xb3, 0xf3, 0x3e, 0xfa, 0x9a } },
199 "2.16.840.1.113733.1.7.48.1"
200 },
201 // thawte Primary Root CA
202 // https://www.thawte.com/
203 { { { 0x91, 0xc6, 0xd6, 0xee, 0x3e, 0x8a, 0xc8, 0x63, 0x84, 0xe5,
204 0x48, 0xc2, 0x99, 0x29, 0x5c, 0x75, 0x6c, 0x81, 0x7b, 0x81 } },
205 "2.16.840.1.113733.1.7.48.1"
206 },
207 // UTN - DATACorp SGC
208 { { { 0x58, 0x11, 0x9f, 0x0e, 0x12, 0x82, 0x87, 0xea, 0x50, 0xfd,
209 0xd9, 0x87, 0x45, 0x6f, 0x4f, 0x78, 0xdc, 0xfa, 0xd6, 0xd4 } },
210 "1.3.6.1.4.1.6449.1.2.1.5.1"
211 },
212 // UTN-USERFirst-Hardware
213 { { { 0x04, 0x83, 0xed, 0x33, 0x99, 0xac, 0x36, 0x08, 0x05, 0x87,
214 0x22, 0xed, 0xbc, 0x5e, 0x46, 0x00, 0xe3, 0xbe, 0xf9, 0xd7 } },
215 "1.3.6.1.4.1.6449.1.2.1.5.1"
216 },
217 // ValiCert Class 2 Policy Validation Authority
218 // TODO(wtc): bug 1165107: this CA has another policy OID
219 // "2.16.840.1.114414.1.7.23.3".
220 { { { 0x31, 0x7a, 0x2a, 0xd0, 0x7f, 0x2b, 0x33, 0x5e, 0xf5, 0xa1,
221 0xc3, 0x4e, 0x4b, 0x57, 0xe8, 0xb7, 0xd8, 0xf1, 0xfc, 0xa6 } },
222 "2.16.840.1.114413.1.7.23.3"
223 },
224 // VeriSign Class 3 Public Primary Certification Authority
225 // https://www.verisign.com/
226 { { { 0x74, 0x2c, 0x31, 0x92, 0xe6, 0x07, 0xe4, 0x24, 0xeb, 0x45,
227 0x49, 0x54, 0x2b, 0xe1, 0xbb, 0xc5, 0x3e, 0x61, 0x74, 0xe2 } },
228 "2.16.840.1.113733.1.7.23.6"
229 },
230 // VeriSign Class 3 Public Primary Certification Authority - G5
231 // https://www.verisign.com/
232 { { { 0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58,
233 0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5 } },
234 "2.16.840.1.113733.1.7.23.6"
235 },
236 // Wells Fargo WellsSecure Public Root Certificate Authority
237 // https://nerys.wellsfargo.com/test.html
238 { { { 0xe7, 0xb4, 0xf6, 0x9d, 0x61, 0xec, 0x90, 0x69, 0xdb, 0x7e,
239 0x90, 0xa7, 0x40, 0x1a, 0x3c, 0xf4, 0x7d, 0x4f, 0xe8, 0xee } },
240 "2.16.840.1.114171.500.9"
241 },
242 // XRamp Global Certification Authority
243 { { { 0xb8, 0x01, 0x86, 0xd1, 0xeb, 0x9c, 0x86, 0xa5, 0x41, 0x04,
244 0xcf, 0x30, 0x54, 0xf3, 0x4c, 0x52, 0xb7, 0xe5, 0x58, 0xc6 } },
245 "2.16.840.1.114404.1.1.2.4.1"
246 }
247 };
248
249 #if defined(OS_WIN)
250 // static
251 const EVRootCAMetadata::PolicyOID EVRootCAMetadata::policy_oids_[] = {
252 // The OIDs must be sorted in ascending order.
253 "1.2.392.200091.100.721.1",
254 "1.3.6.1.4.1.14370.1.6",
255 "1.3.6.1.4.1.22234.2.5.2.3.1",
256 "1.3.6.1.4.1.23223.1.1.1",
257 "1.3.6.1.4.1.34697.2.1",
258 "1.3.6.1.4.1.34697.2.2",
259 "1.3.6.1.4.1.34697.2.3",
260 "1.3.6.1.4.1.34697.2.4",
261 "1.3.6.1.4.1.4146.1.1",
262 "1.3.6.1.4.1.6334.1.100.1",
263 "1.3.6.1.4.1.6449.1.2.1.5.1",
264 "1.3.6.1.4.1.782.1.2.1.8.1",
265 "1.3.6.1.4.1.8024.0.2.100.1.2",
266 "2.16.756.1.89.1.2.1.1",
267 "2.16.840.1.113733.1.7.23.6",
268 "2.16.840.1.113733.1.7.48.1",
269 "2.16.840.1.114028.10.1.2",
270 "2.16.840.1.114171.500.9",
271 "2.16.840.1.114404.1.1.2.4.1",
272 "2.16.840.1.114412.2.1",
273 "2.16.840.1.114413.1.7.23.3",
274 "2.16.840.1.114414.1.7.23.3",
275 };
276 #endif
277
278 static base::LazyInstance<EVRootCAMetadata,
279 base::LeakyLazyInstanceTraits<EVRootCAMetadata> >
280 g_ev_root_ca_metadata(base::LINKER_INITIALIZED);
281
282 // static
GetInstance()283 EVRootCAMetadata* EVRootCAMetadata::GetInstance() {
284 return g_ev_root_ca_metadata.Pointer();
285 }
286
GetPolicyOID(const SHA1Fingerprint & fingerprint,PolicyOID * policy_oid) const287 bool EVRootCAMetadata::GetPolicyOID(
288 const SHA1Fingerprint& fingerprint,
289 PolicyOID* policy_oid) const {
290 PolicyOidMap::const_iterator iter = ev_policy_.find(fingerprint);
291 if (iter == ev_policy_.end())
292 return false;
293 *policy_oid = iter->second;
294 return true;
295 }
296
297 #if defined(OS_WIN)
PolicyOIDCmp(const void * keyval,const void * datum)298 static int PolicyOIDCmp(const void* keyval, const void* datum) {
299 const char* oid1 = reinterpret_cast<const char*>(keyval);
300 const char* const* oid2 = reinterpret_cast<const char* const*>(datum);
301 return strcmp(oid1, *oid2);
302 }
303
IsEVPolicyOID(PolicyOID policy_oid) const304 bool EVRootCAMetadata::IsEVPolicyOID(PolicyOID policy_oid) const {
305 return bsearch(policy_oid, &policy_oids_[0], num_policy_oids_,
306 sizeof(PolicyOID), PolicyOIDCmp) != NULL;
307 }
308 #else
IsEVPolicyOID(PolicyOID policy_oid) const309 bool EVRootCAMetadata::IsEVPolicyOID(PolicyOID policy_oid) const {
310 for (size_t i = 0; i < policy_oids_.size(); ++i) {
311 if (PolicyOIDsAreEqual(policy_oid, policy_oids_[i]))
312 return true;
313 }
314 return false;
315 }
316 #endif
317
HasEVPolicyOID(const SHA1Fingerprint & fingerprint,PolicyOID policy_oid) const318 bool EVRootCAMetadata::HasEVPolicyOID(const SHA1Fingerprint& fingerprint,
319 PolicyOID policy_oid) const {
320 PolicyOID ev_policy_oid;
321 if (!GetPolicyOID(fingerprint, &ev_policy_oid))
322 return false;
323 return PolicyOIDsAreEqual(ev_policy_oid, policy_oid);
324 }
325
EVRootCAMetadata()326 EVRootCAMetadata::EVRootCAMetadata() {
327 // Constructs the object from the raw metadata in ev_root_ca_metadata.
328 #if defined(USE_NSS)
329 for (size_t i = 0; i < arraysize(ev_root_ca_metadata); i++) {
330 const EVMetadata& metadata = ev_root_ca_metadata[i];
331 PRUint8 buf[1024];
332 SECItem oid_item;
333 oid_item.data = buf;
334 oid_item.len = sizeof(buf);
335 SECStatus status = SEC_StringToOID(NULL, &oid_item, metadata.policy_oid, 0);
336 if (status != SECSuccess) {
337 LOG(ERROR) << "Failed to convert to OID: " << metadata.policy_oid;
338 continue;
339 }
340 // Register the OID.
341 SECOidData od;
342 od.oid.len = oid_item.len;
343 od.oid.data = oid_item.data;
344 od.offset = SEC_OID_UNKNOWN;
345 od.desc = metadata.policy_oid;
346 od.mechanism = CKM_INVALID_MECHANISM;
347 od.supportedExtension = INVALID_CERT_EXTENSION;
348 SECOidTag policy = SECOID_AddEntry(&od);
349 DCHECK(policy != SEC_OID_UNKNOWN);
350 ev_policy_[metadata.fingerprint] = policy;
351 policy_oids_.push_back(policy);
352 }
353 #elif defined(OS_WIN)
354 num_policy_oids_ = arraysize(policy_oids_);
355 // Verify policy_oids_ is in ascending order.
356 for (int i = 0; i < num_policy_oids_ - 1; i++)
357 DCHECK(strcmp(policy_oids_[i], policy_oids_[i + 1]) < 0);
358
359 for (size_t i = 0; i < arraysize(ev_root_ca_metadata); i++) {
360 const EVMetadata& metadata = ev_root_ca_metadata[i];
361 ev_policy_[metadata.fingerprint] = metadata.policy_oid;
362 // Verify policy_oids_ contains every EV policy OID.
363 DCHECK(IsEVPolicyOID(metadata.policy_oid));
364 }
365 #else
366 for (size_t i = 0; i < arraysize(ev_root_ca_metadata); i++) {
367 const EVMetadata& metadata = ev_root_ca_metadata[i];
368 ev_policy_[metadata.fingerprint] = metadata.policy_oid;
369 // Multiple root CA certs may use the same EV policy OID. Having
370 // duplicates in the policy_oids_ array does no harm, so we don't
371 // bother detecting duplicates.
372 policy_oids_.push_back(metadata.policy_oid);
373 }
374 #endif
375 }
376
~EVRootCAMetadata()377 EVRootCAMetadata::~EVRootCAMetadata() {
378 }
379
380 // static
PolicyOIDsAreEqual(PolicyOID a,PolicyOID b)381 bool EVRootCAMetadata::PolicyOIDsAreEqual(PolicyOID a, PolicyOID b) {
382 #if defined(USE_NSS)
383 return a == b;
384 #else
385 return !strcmp(a, b);
386 #endif
387 }
388
389 } // namespace net
390