1// Copyright (c) 2012 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/cert_verify_proc_win.h"
6
7#include <string>
8#include <vector>
9
10#include "base/memory/scoped_ptr.h"
11#include "base/sha1.h"
12#include "base/strings/string_util.h"
13#include "base/strings/utf_string_conversions.h"
14#include "crypto/capi_util.h"
15#include "crypto/scoped_capi_types.h"
16#include "crypto/sha2.h"
17#include "net/base/net_errors.h"
18#include "net/cert/asn1_util.h"
19#include "net/cert/cert_status_flags.h"
20#include "net/cert/cert_verifier.h"
21#include "net/cert/cert_verify_result.h"
22#include "net/cert/crl_set.h"
23#include "net/cert/ev_root_ca_metadata.h"
24#include "net/cert/test_root_certs.h"
25#include "net/cert/x509_certificate.h"
26#include "net/cert/x509_certificate_known_roots_win.h"
27
28#pragma comment(lib, "crypt32.lib")
29
30#if !defined(CERT_TRUST_HAS_WEAK_SIGNATURE)
31// This was introduced in Windows 8 / Windows Server 2012, but retroactively
32// ported as far back as Windows XP via system update.
33#define CERT_TRUST_HAS_WEAK_SIGNATURE 0x00100000
34#endif
35
36namespace net {
37
38namespace {
39
40struct FreeChainEngineFunctor {
41  void operator()(HCERTCHAINENGINE engine) const {
42    if (engine)
43      CertFreeCertificateChainEngine(engine);
44  }
45};
46
47struct FreeCertChainContextFunctor {
48  void operator()(PCCERT_CHAIN_CONTEXT chain_context) const {
49    if (chain_context)
50      CertFreeCertificateChain(chain_context);
51  }
52};
53
54struct FreeCertContextFunctor {
55  void operator()(PCCERT_CONTEXT context) const {
56    if (context)
57      CertFreeCertificateContext(context);
58  }
59};
60
61typedef crypto::ScopedCAPIHandle<HCERTCHAINENGINE, FreeChainEngineFunctor>
62    ScopedHCERTCHAINENGINE;
63
64typedef scoped_ptr<const CERT_CHAIN_CONTEXT, FreeCertChainContextFunctor>
65    ScopedPCCERT_CHAIN_CONTEXT;
66
67typedef scoped_ptr<const CERT_CONTEXT, FreeCertContextFunctor>
68    ScopedPCCERT_CONTEXT;
69
70//-----------------------------------------------------------------------------
71
72int MapSecurityError(SECURITY_STATUS err) {
73  // There are numerous security error codes, but these are the ones we thus
74  // far find interesting.
75  switch (err) {
76    case SEC_E_WRONG_PRINCIPAL:  // Schannel
77    case CERT_E_CN_NO_MATCH:  // CryptoAPI
78      return ERR_CERT_COMMON_NAME_INVALID;
79    case SEC_E_UNTRUSTED_ROOT:  // Schannel
80    case CERT_E_UNTRUSTEDROOT:  // CryptoAPI
81      return ERR_CERT_AUTHORITY_INVALID;
82    case SEC_E_CERT_EXPIRED:  // Schannel
83    case CERT_E_EXPIRED:  // CryptoAPI
84      return ERR_CERT_DATE_INVALID;
85    case CRYPT_E_NO_REVOCATION_CHECK:
86      return ERR_CERT_NO_REVOCATION_MECHANISM;
87    case CRYPT_E_REVOCATION_OFFLINE:
88      return ERR_CERT_UNABLE_TO_CHECK_REVOCATION;
89    case CRYPT_E_REVOKED:  // Schannel and CryptoAPI
90      return ERR_CERT_REVOKED;
91    case SEC_E_CERT_UNKNOWN:
92    case CERT_E_ROLE:
93      return ERR_CERT_INVALID;
94    case CERT_E_WRONG_USAGE:
95      // TODO(wtc): Should we add ERR_CERT_WRONG_USAGE?
96      return ERR_CERT_INVALID;
97    // We received an unexpected_message or illegal_parameter alert message
98    // from the server.
99    case SEC_E_ILLEGAL_MESSAGE:
100      return ERR_SSL_PROTOCOL_ERROR;
101    case SEC_E_ALGORITHM_MISMATCH:
102      return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
103    case SEC_E_INVALID_HANDLE:
104      return ERR_UNEXPECTED;
105    case SEC_E_OK:
106      return OK;
107    default:
108      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
109      return ERR_FAILED;
110  }
111}
112
113// Map the errors in the chain_context->TrustStatus.dwErrorStatus returned by
114// CertGetCertificateChain to our certificate status flags.
115int MapCertChainErrorStatusToCertStatus(DWORD error_status) {
116  CertStatus cert_status = 0;
117
118  // We don't include CERT_TRUST_IS_NOT_TIME_NESTED because it's obsolete and
119  // we wouldn't consider it an error anyway
120  const DWORD kDateInvalidErrors = CERT_TRUST_IS_NOT_TIME_VALID |
121                                   CERT_TRUST_CTL_IS_NOT_TIME_VALID;
122  if (error_status & kDateInvalidErrors)
123    cert_status |= CERT_STATUS_DATE_INVALID;
124
125  const DWORD kAuthorityInvalidErrors = CERT_TRUST_IS_UNTRUSTED_ROOT |
126                                        CERT_TRUST_IS_EXPLICIT_DISTRUST |
127                                        CERT_TRUST_IS_PARTIAL_CHAIN;
128  if (error_status & kAuthorityInvalidErrors)
129    cert_status |= CERT_STATUS_AUTHORITY_INVALID;
130
131  if ((error_status & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) &&
132      !(error_status & CERT_TRUST_IS_OFFLINE_REVOCATION))
133    cert_status |= CERT_STATUS_NO_REVOCATION_MECHANISM;
134
135  if (error_status & CERT_TRUST_IS_OFFLINE_REVOCATION)
136    cert_status |= CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
137
138  if (error_status & CERT_TRUST_IS_REVOKED)
139    cert_status |= CERT_STATUS_REVOKED;
140
141  const DWORD kWrongUsageErrors = CERT_TRUST_IS_NOT_VALID_FOR_USAGE |
142                                  CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
143  if (error_status & kWrongUsageErrors) {
144    // TODO(wtc): Should we add CERT_STATUS_WRONG_USAGE?
145    cert_status |= CERT_STATUS_INVALID;
146  }
147
148  if (error_status & CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
149    // Check for a signature that does not meet the OS criteria for strong
150    // signatures.
151    // Note: These checks may be more restrictive than the current weak key
152    // criteria implemented within CertVerifier, such as excluding SHA-1 or
153    // excluding RSA keys < 2048 bits. However, if the user has configured
154    // these more stringent checks, respect that configuration and err on the
155    // more restrictive criteria.
156    if (error_status & CERT_TRUST_HAS_WEAK_SIGNATURE) {
157      cert_status |= CERT_STATUS_WEAK_KEY;
158    } else {
159      cert_status |= CERT_STATUS_INVALID;
160    }
161  }
162
163  // The rest of the errors.
164  const DWORD kCertInvalidErrors =
165      CERT_TRUST_IS_CYCLIC |
166      CERT_TRUST_INVALID_EXTENSION |
167      CERT_TRUST_INVALID_POLICY_CONSTRAINTS |
168      CERT_TRUST_INVALID_BASIC_CONSTRAINTS |
169      CERT_TRUST_INVALID_NAME_CONSTRAINTS |
170      CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID |
171      CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT |
172      CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT |
173      CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT |
174      CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT |
175      CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY |
176      CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT;
177  if (error_status & kCertInvalidErrors)
178    cert_status |= CERT_STATUS_INVALID;
179
180  return cert_status;
181}
182
183// Returns true if any common name in the certificate's Subject field contains
184// a NULL character.
185bool CertSubjectCommonNameHasNull(PCCERT_CONTEXT cert) {
186  CRYPT_DECODE_PARA decode_para;
187  decode_para.cbSize = sizeof(decode_para);
188  decode_para.pfnAlloc = crypto::CryptAlloc;
189  decode_para.pfnFree = crypto::CryptFree;
190  CERT_NAME_INFO* name_info = NULL;
191  DWORD name_info_size = 0;
192  BOOL rv;
193  rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
194                           X509_NAME,
195                           cert->pCertInfo->Subject.pbData,
196                           cert->pCertInfo->Subject.cbData,
197                           CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
198                           &decode_para,
199                           &name_info,
200                           &name_info_size);
201  if (rv) {
202    scoped_ptr<CERT_NAME_INFO, base::FreeDeleter> scoped_name_info(name_info);
203
204    // The Subject field may have multiple common names.  According to the
205    // "PKI Layer Cake" paper, CryptoAPI uses every common name in the
206    // Subject field, so we inspect every common name.
207    //
208    // From RFC 5280:
209    // X520CommonName ::= CHOICE {
210    //       teletexString     TeletexString   (SIZE (1..ub-common-name)),
211    //       printableString   PrintableString (SIZE (1..ub-common-name)),
212    //       universalString   UniversalString (SIZE (1..ub-common-name)),
213    //       utf8String        UTF8String      (SIZE (1..ub-common-name)),
214    //       bmpString         BMPString       (SIZE (1..ub-common-name)) }
215    //
216    // We also check IA5String and VisibleString.
217    for (DWORD i = 0; i < name_info->cRDN; ++i) {
218      PCERT_RDN rdn = &name_info->rgRDN[i];
219      for (DWORD j = 0; j < rdn->cRDNAttr; ++j) {
220        PCERT_RDN_ATTR rdn_attr = &rdn->rgRDNAttr[j];
221        if (strcmp(rdn_attr->pszObjId, szOID_COMMON_NAME) == 0) {
222          switch (rdn_attr->dwValueType) {
223            // After the CryptoAPI ASN.1 security vulnerabilities described in
224            // http://www.microsoft.com/technet/security/Bulletin/MS09-056.mspx
225            // were patched, we get CERT_RDN_ENCODED_BLOB for a common name
226            // that contains a NULL character.
227            case CERT_RDN_ENCODED_BLOB:
228              break;
229            // Array of 8-bit characters.
230            case CERT_RDN_PRINTABLE_STRING:
231            case CERT_RDN_TELETEX_STRING:
232            case CERT_RDN_IA5_STRING:
233            case CERT_RDN_VISIBLE_STRING:
234              for (DWORD k = 0; k < rdn_attr->Value.cbData; ++k) {
235                if (rdn_attr->Value.pbData[k] == '\0')
236                  return true;
237              }
238              break;
239            // Array of 16-bit characters.
240            case CERT_RDN_BMP_STRING:
241            case CERT_RDN_UTF8_STRING: {
242              DWORD num_wchars = rdn_attr->Value.cbData / 2;
243              wchar_t* common_name =
244                  reinterpret_cast<wchar_t*>(rdn_attr->Value.pbData);
245              for (DWORD k = 0; k < num_wchars; ++k) {
246                if (common_name[k] == L'\0')
247                  return true;
248              }
249              break;
250            }
251            // Array of ints (32-bit).
252            case CERT_RDN_UNIVERSAL_STRING: {
253              DWORD num_ints = rdn_attr->Value.cbData / 4;
254              int* common_name =
255                  reinterpret_cast<int*>(rdn_attr->Value.pbData);
256              for (DWORD k = 0; k < num_ints; ++k) {
257                if (common_name[k] == 0)
258                  return true;
259              }
260              break;
261            }
262            default:
263              NOTREACHED();
264              break;
265          }
266        }
267      }
268    }
269  }
270  return false;
271}
272
273// IsIssuedByKnownRoot returns true if the given chain is rooted at a root CA
274// which we recognise as a standard root.
275// static
276bool IsIssuedByKnownRoot(PCCERT_CHAIN_CONTEXT chain_context) {
277  PCERT_SIMPLE_CHAIN first_chain = chain_context->rgpChain[0];
278  int num_elements = first_chain->cElement;
279  if (num_elements < 1)
280    return false;
281  PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement;
282  PCCERT_CONTEXT cert = element[num_elements - 1]->pCertContext;
283
284  SHA1HashValue hash = X509Certificate::CalculateFingerprint(cert);
285  return IsSHA1HashInSortedArray(
286      hash, &kKnownRootCertSHA1Hashes[0][0], sizeof(kKnownRootCertSHA1Hashes));
287}
288
289// Saves some information about the certificate chain |chain_context| in
290// |*verify_result|. The caller MUST initialize |*verify_result| before
291// calling this function.
292void GetCertChainInfo(PCCERT_CHAIN_CONTEXT chain_context,
293                      CertVerifyResult* verify_result) {
294  if (chain_context->cChain == 0)
295    return;
296
297  PCERT_SIMPLE_CHAIN first_chain = chain_context->rgpChain[0];
298  int num_elements = first_chain->cElement;
299  PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement;
300
301  PCCERT_CONTEXT verified_cert = NULL;
302  std::vector<PCCERT_CONTEXT> verified_chain;
303
304  bool has_root_ca = num_elements > 1 &&
305      !(chain_context->TrustStatus.dwErrorStatus &
306          CERT_TRUST_IS_PARTIAL_CHAIN);
307
308  // Each chain starts with the end entity certificate (i = 0) and ends with
309  // either the root CA certificate or the last available intermediate. If a
310  // root CA certificate is present, do not inspect the signature algorithm of
311  // the root CA certificate because the signature on the trust anchor is not
312  // important.
313  if (has_root_ca) {
314    // If a full chain was constructed, regardless of whether it was trusted,
315    // don't inspect the root's signature algorithm.
316    num_elements -= 1;
317  }
318
319  for (int i = 0; i < num_elements; ++i) {
320    PCCERT_CONTEXT cert = element[i]->pCertContext;
321    if (i == 0) {
322      verified_cert = cert;
323    } else {
324      verified_chain.push_back(cert);
325    }
326
327    const char* algorithm = cert->pCertInfo->SignatureAlgorithm.pszObjId;
328    if (strcmp(algorithm, szOID_RSA_MD5RSA) == 0) {
329      // md5WithRSAEncryption: 1.2.840.113549.1.1.4
330      verify_result->has_md5 = true;
331    } else if (strcmp(algorithm, szOID_RSA_MD2RSA) == 0) {
332      // md2WithRSAEncryption: 1.2.840.113549.1.1.2
333      verify_result->has_md2 = true;
334    } else if (strcmp(algorithm, szOID_RSA_MD4RSA) == 0) {
335      // md4WithRSAEncryption: 1.2.840.113549.1.1.3
336      verify_result->has_md4 = true;
337    } else if (strcmp(algorithm, szOID_RSA_SHA1RSA) == 0 ||
338               strcmp(algorithm, szOID_X957_SHA1DSA) == 0 ||
339               strcmp(algorithm, szOID_ECDSA_SHA1) == 0) {
340      // sha1WithRSAEncryption: 1.2.840.113549.1.1.5
341      // id-dsa-with-sha1: 1.2.840.10040.4.3
342      // ecdsa-with-SHA1: 1.2.840.10045.4.1
343      verify_result->has_sha1 = true;
344    }
345  }
346
347  if (verified_cert) {
348    // Add the root certificate, if present, as it was not added above.
349    if (has_root_ca)
350      verified_chain.push_back(element[num_elements]->pCertContext);
351    verify_result->verified_cert =
352          X509Certificate::CreateFromHandle(verified_cert, verified_chain);
353  }
354}
355
356// Decodes the cert's certificatePolicies extension into a CERT_POLICIES_INFO
357// structure and stores it in *output.
358void GetCertPoliciesInfo(
359    PCCERT_CONTEXT cert,
360    scoped_ptr<CERT_POLICIES_INFO, base::FreeDeleter>* output) {
361  PCERT_EXTENSION extension = CertFindExtension(szOID_CERT_POLICIES,
362                                                cert->pCertInfo->cExtension,
363                                                cert->pCertInfo->rgExtension);
364  if (!extension)
365    return;
366
367  CRYPT_DECODE_PARA decode_para;
368  decode_para.cbSize = sizeof(decode_para);
369  decode_para.pfnAlloc = crypto::CryptAlloc;
370  decode_para.pfnFree = crypto::CryptFree;
371  CERT_POLICIES_INFO* policies_info = NULL;
372  DWORD policies_info_size = 0;
373  BOOL rv;
374  rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
375                           szOID_CERT_POLICIES,
376                           extension->Value.pbData,
377                           extension->Value.cbData,
378                           CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
379                           &decode_para,
380                           &policies_info,
381                           &policies_info_size);
382  if (rv)
383    output->reset(policies_info);
384}
385
386enum CRLSetResult {
387  kCRLSetOk,
388  kCRLSetUnknown,
389  kCRLSetRevoked,
390};
391
392// CheckRevocationWithCRLSet attempts to check each element of |chain|
393// against |crl_set|. It returns:
394//   kCRLSetRevoked: if any element of the chain is known to have been revoked.
395//   kCRLSetUnknown: if there is no fresh information about the leaf
396//       certificate in the chain or if the CRLSet has expired.
397//
398//       Only the leaf certificate is considered for coverage because some
399//       intermediates have CRLs with no revocations (after filtering) and
400//       those CRLs are pruned from the CRLSet at generation time. This means
401//       that some EV sites would otherwise take the hit of an OCSP lookup for
402//       no reason.
403//   kCRLSetOk: otherwise.
404CRLSetResult CheckRevocationWithCRLSet(PCCERT_CHAIN_CONTEXT chain,
405                                       CRLSet* crl_set) {
406  if (chain->cChain == 0)
407    return kCRLSetOk;
408
409  const PCERT_SIMPLE_CHAIN first_chain = chain->rgpChain[0];
410  const PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement;
411
412  const int num_elements = first_chain->cElement;
413  if (num_elements == 0)
414    return kCRLSetOk;
415
416  // error is set to true if any errors are found. It causes such chains to be
417  // considered as not covered.
418  bool error = false;
419  // last_covered is set to the coverage state of the previous certificate. The
420  // certificates are iterated over backwards thus, after the iteration,
421  // |last_covered| contains the coverage state of the leaf certificate.
422  bool last_covered = false;
423
424  // We iterate from the root certificate down to the leaf, keeping track of
425  // the issuer's SPKI at each step.
426  std::string issuer_spki_hash;
427  for (int i = num_elements - 1; i >= 0; i--) {
428    PCCERT_CONTEXT cert = element[i]->pCertContext;
429
430    base::StringPiece der_bytes(
431        reinterpret_cast<const char*>(cert->pbCertEncoded),
432        cert->cbCertEncoded);
433
434    base::StringPiece spki;
435    if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) {
436      NOTREACHED();
437      error = true;
438      continue;
439    }
440
441    const std::string spki_hash = crypto::SHA256HashString(spki);
442
443    const CRYPT_INTEGER_BLOB* serial_blob = &cert->pCertInfo->SerialNumber;
444    scoped_ptr<uint8[]> serial_bytes(new uint8[serial_blob->cbData]);
445    // The bytes of the serial number are stored little-endian.
446    for (unsigned j = 0; j < serial_blob->cbData; j++)
447      serial_bytes[j] = serial_blob->pbData[serial_blob->cbData - j - 1];
448    base::StringPiece serial(reinterpret_cast<const char*>(serial_bytes.get()),
449                             serial_blob->cbData);
450
451    CRLSet::Result result = crl_set->CheckSPKI(spki_hash);
452
453    if (result != CRLSet::REVOKED && !issuer_spki_hash.empty())
454      result = crl_set->CheckSerial(serial, issuer_spki_hash);
455
456    issuer_spki_hash = spki_hash;
457
458    switch (result) {
459      case CRLSet::REVOKED:
460        return kCRLSetRevoked;
461      case CRLSet::UNKNOWN:
462        last_covered = false;
463        continue;
464      case CRLSet::GOOD:
465        last_covered = true;
466        continue;
467      default:
468        NOTREACHED();
469        error = true;
470        continue;
471    }
472  }
473
474  if (error || !last_covered || crl_set->IsExpired())
475    return kCRLSetUnknown;
476  return kCRLSetOk;
477}
478
479void AppendPublicKeyHashes(PCCERT_CHAIN_CONTEXT chain,
480                           HashValueVector* hashes) {
481  if (chain->cChain == 0)
482    return;
483
484  PCERT_SIMPLE_CHAIN first_chain = chain->rgpChain[0];
485  PCERT_CHAIN_ELEMENT* const element = first_chain->rgpElement;
486
487  const DWORD num_elements = first_chain->cElement;
488  for (DWORD i = 0; i < num_elements; i++) {
489    PCCERT_CONTEXT cert = element[i]->pCertContext;
490
491    base::StringPiece der_bytes(
492        reinterpret_cast<const char*>(cert->pbCertEncoded),
493        cert->cbCertEncoded);
494    base::StringPiece spki_bytes;
495    if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes))
496      continue;
497
498    HashValue sha1(HASH_VALUE_SHA1);
499    base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()),
500                        spki_bytes.size(), sha1.data());
501    hashes->push_back(sha1);
502
503    HashValue sha256(HASH_VALUE_SHA256);
504    crypto::SHA256HashString(spki_bytes, sha256.data(), crypto::kSHA256Length);
505    hashes->push_back(sha256);
506  }
507}
508
509// Returns true if the certificate is an extended-validation certificate.
510//
511// This function checks the certificatePolicies extensions of the
512// certificates in the certificate chain according to Section 7 (pp. 11-12)
513// of the EV Certificate Guidelines Version 1.0 at
514// http://cabforum.org/EV_Certificate_Guidelines.pdf.
515bool CheckEV(PCCERT_CHAIN_CONTEXT chain_context,
516             bool rev_checking_enabled,
517             const char* policy_oid) {
518  DCHECK_NE(static_cast<DWORD>(0), chain_context->cChain);
519  // If the cert doesn't match any of the policies, the
520  // CERT_TRUST_IS_NOT_VALID_FOR_USAGE bit (0x10) in
521  // chain_context->TrustStatus.dwErrorStatus is set.
522  DWORD error_status = chain_context->TrustStatus.dwErrorStatus;
523
524  if (!rev_checking_enabled) {
525    // If online revocation checking is disabled then we will have still
526    // requested that the revocation cache be checked. However, that will often
527    // cause the following two error bits to be set. These error bits mean that
528    // the local OCSP/CRL is stale or missing entries for these certificates.
529    // Since they are expected, we mask them away.
530    error_status &= ~(CERT_TRUST_IS_OFFLINE_REVOCATION |
531                      CERT_TRUST_REVOCATION_STATUS_UNKNOWN);
532  }
533  if (!chain_context->cChain || error_status != CERT_TRUST_NO_ERROR)
534    return false;
535
536  // Check the end certificate simple chain (chain_context->rgpChain[0]).
537  // If the end certificate's certificatePolicies extension contains the
538  // EV policy OID of the root CA, return true.
539  PCERT_CHAIN_ELEMENT* element = chain_context->rgpChain[0]->rgpElement;
540  int num_elements = chain_context->rgpChain[0]->cElement;
541  if (num_elements < 2)
542    return false;
543
544  // Look up the EV policy OID of the root CA.
545  PCCERT_CONTEXT root_cert = element[num_elements - 1]->pCertContext;
546  SHA1HashValue fingerprint =
547      X509Certificate::CalculateFingerprint(root_cert);
548  EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
549  return metadata->HasEVPolicyOID(fingerprint, policy_oid);
550}
551
552}  // namespace
553
554CertVerifyProcWin::CertVerifyProcWin() {}
555
556CertVerifyProcWin::~CertVerifyProcWin() {}
557
558bool CertVerifyProcWin::SupportsAdditionalTrustAnchors() const {
559  return false;
560}
561
562int CertVerifyProcWin::VerifyInternal(
563    X509Certificate* cert,
564    const std::string& hostname,
565    int flags,
566    CRLSet* crl_set,
567    const CertificateList& additional_trust_anchors,
568    CertVerifyResult* verify_result) {
569  PCCERT_CONTEXT cert_handle = cert->os_cert_handle();
570  if (!cert_handle)
571    return ERR_UNEXPECTED;
572
573  // Build and validate certificate chain.
574  CERT_CHAIN_PARA chain_para;
575  memset(&chain_para, 0, sizeof(chain_para));
576  chain_para.cbSize = sizeof(chain_para);
577  // ExtendedKeyUsage.
578  // We still need to request szOID_SERVER_GATED_CRYPTO and szOID_SGC_NETSCAPE
579  // today because some certificate chains need them.  IE also requests these
580  // two usages.
581  static const LPCSTR usage[] = {
582    szOID_PKIX_KP_SERVER_AUTH,
583    szOID_SERVER_GATED_CRYPTO,
584    szOID_SGC_NETSCAPE
585  };
586  chain_para.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
587  chain_para.RequestedUsage.Usage.cUsageIdentifier = arraysize(usage);
588  chain_para.RequestedUsage.Usage.rgpszUsageIdentifier =
589      const_cast<LPSTR*>(usage);
590
591  // Get the certificatePolicies extension of the certificate.
592  scoped_ptr<CERT_POLICIES_INFO, base::FreeDeleter> policies_info;
593  LPSTR ev_policy_oid = NULL;
594  if (flags & CertVerifier::VERIFY_EV_CERT) {
595    GetCertPoliciesInfo(cert_handle, &policies_info);
596    if (policies_info.get()) {
597      EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
598      for (DWORD i = 0; i < policies_info->cPolicyInfo; ++i) {
599        LPSTR policy_oid = policies_info->rgPolicyInfo[i].pszPolicyIdentifier;
600        if (metadata->IsEVPolicyOID(policy_oid)) {
601          ev_policy_oid = policy_oid;
602          chain_para.RequestedIssuancePolicy.dwType = USAGE_MATCH_TYPE_AND;
603          chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 1;
604          chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier =
605              &ev_policy_oid;
606          break;
607        }
608      }
609    }
610  }
611
612  // We can set CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS to get more chains.
613  DWORD chain_flags = CERT_CHAIN_CACHE_END_CERT |
614                      CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
615  bool rev_checking_enabled =
616      (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED);
617
618  if (rev_checking_enabled) {
619    verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
620  } else {
621    chain_flags |= CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
622  }
623
624  // For non-test scenarios, use the default HCERTCHAINENGINE, NULL, which
625  // corresponds to HCCE_CURRENT_USER and is is initialized as needed by
626  // crypt32. However, when testing, it is necessary to create a new
627  // HCERTCHAINENGINE and use that instead. This is because each
628  // HCERTCHAINENGINE maintains a cache of information about certificates
629  // encountered, and each test run may modify the trust status of a
630  // certificate.
631  ScopedHCERTCHAINENGINE chain_engine(NULL);
632  if (TestRootCerts::HasInstance())
633    chain_engine.reset(TestRootCerts::GetInstance()->GetChainEngine());
634
635  ScopedPCCERT_CONTEXT cert_list(cert->CreateOSCertChainForCert());
636  PCCERT_CHAIN_CONTEXT chain_context;
637  // IE passes a non-NULL pTime argument that specifies the current system
638  // time.  IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the
639  // chain_flags argument.
640  if (!CertGetCertificateChain(
641           chain_engine,
642           cert_list.get(),
643           NULL,  // current system time
644           cert_list->hCertStore,
645           &chain_para,
646           chain_flags,
647           NULL,  // reserved
648           &chain_context)) {
649    verify_result->cert_status |= CERT_STATUS_INVALID;
650    return MapSecurityError(GetLastError());
651  }
652
653  CRLSetResult crl_set_result = kCRLSetUnknown;
654  if (crl_set)
655    crl_set_result = CheckRevocationWithCRLSet(chain_context, crl_set);
656
657  if (crl_set_result == kCRLSetRevoked) {
658    verify_result->cert_status |= CERT_STATUS_REVOKED;
659  } else if (crl_set_result == kCRLSetUnknown &&
660             (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) &&
661             !rev_checking_enabled &&
662             ev_policy_oid != NULL) {
663    // We don't have fresh information about this chain from the CRLSet and
664    // it's probably an EV certificate. Retry with online revocation checking.
665    rev_checking_enabled = true;
666    chain_flags &= ~CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
667    verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
668
669    CertFreeCertificateChain(chain_context);
670    if (!CertGetCertificateChain(
671             chain_engine,
672             cert_list.get(),
673             NULL,  // current system time
674             cert_list->hCertStore,
675             &chain_para,
676             chain_flags,
677             NULL,  // reserved
678             &chain_context)) {
679      verify_result->cert_status |= CERT_STATUS_INVALID;
680      return MapSecurityError(GetLastError());
681    }
682  }
683
684  if (chain_context->TrustStatus.dwErrorStatus &
685      CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
686    ev_policy_oid = NULL;
687    chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 0;
688    chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = NULL;
689    CertFreeCertificateChain(chain_context);
690    if (!CertGetCertificateChain(
691             chain_engine,
692             cert_list.get(),
693             NULL,  // current system time
694             cert_list->hCertStore,
695             &chain_para,
696             chain_flags,
697             NULL,  // reserved
698             &chain_context)) {
699      verify_result->cert_status |= CERT_STATUS_INVALID;
700      return MapSecurityError(GetLastError());
701    }
702  }
703
704  CertVerifyResult temp_verify_result = *verify_result;
705  GetCertChainInfo(chain_context, verify_result);
706  if (!verify_result->is_issued_by_known_root &&
707      (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS)) {
708    *verify_result = temp_verify_result;
709
710    rev_checking_enabled = true;
711    verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
712    chain_flags &= ~CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
713
714    CertFreeCertificateChain(chain_context);
715    if (!CertGetCertificateChain(
716             chain_engine,
717             cert_list.get(),
718             NULL,  // current system time
719             cert_list->hCertStore,
720             &chain_para,
721             chain_flags,
722             NULL,  // reserved
723             &chain_context)) {
724      verify_result->cert_status |= CERT_STATUS_INVALID;
725      return MapSecurityError(GetLastError());
726    }
727    GetCertChainInfo(chain_context, verify_result);
728
729    if (chain_context->TrustStatus.dwErrorStatus &
730        CERT_TRUST_IS_OFFLINE_REVOCATION) {
731      verify_result->cert_status |= CERT_STATUS_REVOKED;
732    }
733  }
734
735  ScopedPCCERT_CHAIN_CONTEXT scoped_chain_context(chain_context);
736
737  verify_result->cert_status |= MapCertChainErrorStatusToCertStatus(
738      chain_context->TrustStatus.dwErrorStatus);
739
740  // Flag certificates that have a Subject common name with a NULL character.
741  if (CertSubjectCommonNameHasNull(cert_handle))
742    verify_result->cert_status |= CERT_STATUS_INVALID;
743
744  std::wstring wstr_hostname = base::ASCIIToWide(hostname);
745
746  SSL_EXTRA_CERT_CHAIN_POLICY_PARA extra_policy_para;
747  memset(&extra_policy_para, 0, sizeof(extra_policy_para));
748  extra_policy_para.cbSize = sizeof(extra_policy_para);
749  extra_policy_para.dwAuthType = AUTHTYPE_SERVER;
750  // Certificate name validation happens separately, later, using an internal
751  // routine that has better support for RFC 6125 name matching.
752  extra_policy_para.fdwChecks =
753      0x00001000;  // SECURITY_FLAG_IGNORE_CERT_CN_INVALID
754  extra_policy_para.pwszServerName =
755      const_cast<wchar_t*>(wstr_hostname.c_str());
756
757  CERT_CHAIN_POLICY_PARA policy_para;
758  memset(&policy_para, 0, sizeof(policy_para));
759  policy_para.cbSize = sizeof(policy_para);
760  policy_para.dwFlags = 0;
761  policy_para.pvExtraPolicyPara = &extra_policy_para;
762
763  CERT_CHAIN_POLICY_STATUS policy_status;
764  memset(&policy_status, 0, sizeof(policy_status));
765  policy_status.cbSize = sizeof(policy_status);
766
767  if (!CertVerifyCertificateChainPolicy(
768           CERT_CHAIN_POLICY_SSL,
769           chain_context,
770           &policy_para,
771           &policy_status)) {
772    return MapSecurityError(GetLastError());
773  }
774
775  if (policy_status.dwError) {
776    verify_result->cert_status |= MapNetErrorToCertStatus(
777        MapSecurityError(policy_status.dwError));
778  }
779
780  // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be
781  // compatible with WinHTTP, which doesn't report this error (bug 3004).
782  verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM;
783
784  // Perform hostname verification independent of
785  // CertVerifyCertificateChainPolicy.
786  if (!cert->VerifyNameMatch(hostname,
787                             &verify_result->common_name_fallback_used)) {
788    verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
789  }
790
791  if (!rev_checking_enabled) {
792    // If we didn't do online revocation checking then Windows will report
793    // CERT_UNABLE_TO_CHECK_REVOCATION unless it had cached OCSP or CRL
794    // information for every certificate. We only want to put up revoked
795    // statuses from the offline checks so we squash this error.
796    verify_result->cert_status &= ~CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
797  }
798
799  AppendPublicKeyHashes(chain_context, &verify_result->public_key_hashes);
800  verify_result->is_issued_by_known_root = IsIssuedByKnownRoot(chain_context);
801
802  if (IsCertStatusError(verify_result->cert_status))
803    return MapCertStatusToNetError(verify_result->cert_status);
804
805  if (ev_policy_oid &&
806      CheckEV(chain_context, rev_checking_enabled, ev_policy_oid)) {
807    verify_result->cert_status |= CERT_STATUS_IS_EV;
808  }
809  return OK;
810}
811
812}  // namespace net
813