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
19namespace net {
20
21// Raw metadata.
22struct 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
33static 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
251const 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
278static base::LazyInstance<EVRootCAMetadata,
279                          base::LeakyLazyInstanceTraits<EVRootCAMetadata> >
280    g_ev_root_ca_metadata(base::LINKER_INITIALIZED);
281
282// static
283EVRootCAMetadata* EVRootCAMetadata::GetInstance() {
284  return g_ev_root_ca_metadata.Pointer();
285}
286
287bool 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)
298static 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
304bool 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
309bool 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
318bool 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
326EVRootCAMetadata::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
377EVRootCAMetadata::~EVRootCAMetadata() {
378}
379
380// static
381bool 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