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    }
338  }
339
340  if (verified_cert) {
341    // Add the root certificate, if present, as it was not added above.
342    if (has_root_ca)
343      verified_chain.push_back(element[num_elements]->pCertContext);
344    verify_result->verified_cert =
345          X509Certificate::CreateFromHandle(verified_cert, verified_chain);
346  }
347}
348
349// Decodes the cert's certificatePolicies extension into a CERT_POLICIES_INFO
350// structure and stores it in *output.
351void GetCertPoliciesInfo(
352    PCCERT_CONTEXT cert,
353    scoped_ptr<CERT_POLICIES_INFO, base::FreeDeleter>* output) {
354  PCERT_EXTENSION extension = CertFindExtension(szOID_CERT_POLICIES,
355                                                cert->pCertInfo->cExtension,
356                                                cert->pCertInfo->rgExtension);
357  if (!extension)
358    return;
359
360  CRYPT_DECODE_PARA decode_para;
361  decode_para.cbSize = sizeof(decode_para);
362  decode_para.pfnAlloc = crypto::CryptAlloc;
363  decode_para.pfnFree = crypto::CryptFree;
364  CERT_POLICIES_INFO* policies_info = NULL;
365  DWORD policies_info_size = 0;
366  BOOL rv;
367  rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
368                           szOID_CERT_POLICIES,
369                           extension->Value.pbData,
370                           extension->Value.cbData,
371                           CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
372                           &decode_para,
373                           &policies_info,
374                           &policies_info_size);
375  if (rv)
376    output->reset(policies_info);
377}
378
379enum CRLSetResult {
380  kCRLSetOk,
381  kCRLSetUnknown,
382  kCRLSetRevoked,
383};
384
385// CheckRevocationWithCRLSet attempts to check each element of |chain|
386// against |crl_set|. It returns:
387//   kCRLSetRevoked: if any element of the chain is known to have been revoked.
388//   kCRLSetUnknown: if there is no fresh information about some element in
389//       the chain.
390//   kCRLSetOk: if every element in the chain is covered by a fresh CRLSet and
391//       is unrevoked.
392CRLSetResult CheckRevocationWithCRLSet(PCCERT_CHAIN_CONTEXT chain,
393                                       CRLSet* crl_set) {
394  if (chain->cChain == 0)
395    return kCRLSetOk;
396
397  const PCERT_SIMPLE_CHAIN first_chain = chain->rgpChain[0];
398  const PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement;
399
400  const int num_elements = first_chain->cElement;
401  if (num_elements == 0)
402    return kCRLSetOk;
403
404  bool covered = true;
405
406  // We iterate from the root certificate down to the leaf, keeping track of
407  // the issuer's SPKI at each step.
408  std::string issuer_spki_hash;
409  for (int i = num_elements - 1; i >= 0; i--) {
410    PCCERT_CONTEXT cert = element[i]->pCertContext;
411
412    base::StringPiece der_bytes(
413        reinterpret_cast<const char*>(cert->pbCertEncoded),
414        cert->cbCertEncoded);
415
416    base::StringPiece spki;
417    if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) {
418      NOTREACHED();
419      covered = false;
420      continue;
421    }
422
423    const std::string spki_hash = crypto::SHA256HashString(spki);
424
425    const CRYPT_INTEGER_BLOB* serial_blob = &cert->pCertInfo->SerialNumber;
426    scoped_ptr<uint8[]> serial_bytes(new uint8[serial_blob->cbData]);
427    // The bytes of the serial number are stored little-endian.
428    for (unsigned j = 0; j < serial_blob->cbData; j++)
429      serial_bytes[j] = serial_blob->pbData[serial_blob->cbData - j - 1];
430    base::StringPiece serial(reinterpret_cast<const char*>(serial_bytes.get()),
431                             serial_blob->cbData);
432
433    CRLSet::Result result = crl_set->CheckSPKI(spki_hash);
434
435    if (result != CRLSet::REVOKED && !issuer_spki_hash.empty())
436      result = crl_set->CheckSerial(serial, issuer_spki_hash);
437
438    issuer_spki_hash = spki_hash;
439
440    switch (result) {
441      case CRLSet::REVOKED:
442        return kCRLSetRevoked;
443      case CRLSet::UNKNOWN:
444        covered = false;
445        continue;
446      case CRLSet::GOOD:
447        continue;
448      default:
449        NOTREACHED();
450        covered = false;
451        continue;
452    }
453  }
454
455  if (!covered || crl_set->IsExpired())
456    return kCRLSetUnknown;
457  return kCRLSetOk;
458}
459
460void AppendPublicKeyHashes(PCCERT_CHAIN_CONTEXT chain,
461                           HashValueVector* hashes) {
462  if (chain->cChain == 0)
463    return;
464
465  PCERT_SIMPLE_CHAIN first_chain = chain->rgpChain[0];
466  PCERT_CHAIN_ELEMENT* const element = first_chain->rgpElement;
467
468  const DWORD num_elements = first_chain->cElement;
469  for (DWORD i = 0; i < num_elements; i++) {
470    PCCERT_CONTEXT cert = element[i]->pCertContext;
471
472    base::StringPiece der_bytes(
473        reinterpret_cast<const char*>(cert->pbCertEncoded),
474        cert->cbCertEncoded);
475    base::StringPiece spki_bytes;
476    if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes))
477      continue;
478
479    HashValue sha1(HASH_VALUE_SHA1);
480    base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()),
481                        spki_bytes.size(), sha1.data());
482    hashes->push_back(sha1);
483
484    HashValue sha256(HASH_VALUE_SHA256);
485    crypto::SHA256HashString(spki_bytes, sha256.data(), crypto::kSHA256Length);
486    hashes->push_back(sha256);
487  }
488}
489
490// Returns true if the certificate is an extended-validation certificate.
491//
492// This function checks the certificatePolicies extensions of the
493// certificates in the certificate chain according to Section 7 (pp. 11-12)
494// of the EV Certificate Guidelines Version 1.0 at
495// http://cabforum.org/EV_Certificate_Guidelines.pdf.
496bool CheckEV(PCCERT_CHAIN_CONTEXT chain_context,
497             bool rev_checking_enabled,
498             const char* policy_oid) {
499  DCHECK_NE(static_cast<DWORD>(0), chain_context->cChain);
500  // If the cert doesn't match any of the policies, the
501  // CERT_TRUST_IS_NOT_VALID_FOR_USAGE bit (0x10) in
502  // chain_context->TrustStatus.dwErrorStatus is set.
503  DWORD error_status = chain_context->TrustStatus.dwErrorStatus;
504
505  if (!rev_checking_enabled) {
506    // If online revocation checking is disabled then we will have still
507    // requested that the revocation cache be checked. However, that will often
508    // cause the following two error bits to be set. These error bits mean that
509    // the local OCSP/CRL is stale or missing entries for these certificates.
510    // Since they are expected, we mask them away.
511    error_status &= ~(CERT_TRUST_IS_OFFLINE_REVOCATION |
512                      CERT_TRUST_REVOCATION_STATUS_UNKNOWN);
513  }
514  if (!chain_context->cChain || error_status != CERT_TRUST_NO_ERROR)
515    return false;
516
517  // Check the end certificate simple chain (chain_context->rgpChain[0]).
518  // If the end certificate's certificatePolicies extension contains the
519  // EV policy OID of the root CA, return true.
520  PCERT_CHAIN_ELEMENT* element = chain_context->rgpChain[0]->rgpElement;
521  int num_elements = chain_context->rgpChain[0]->cElement;
522  if (num_elements < 2)
523    return false;
524
525  // Look up the EV policy OID of the root CA.
526  PCCERT_CONTEXT root_cert = element[num_elements - 1]->pCertContext;
527  SHA1HashValue fingerprint =
528      X509Certificate::CalculateFingerprint(root_cert);
529  EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
530  return metadata->HasEVPolicyOID(fingerprint, policy_oid);
531}
532
533}  // namespace
534
535CertVerifyProcWin::CertVerifyProcWin() {}
536
537CertVerifyProcWin::~CertVerifyProcWin() {}
538
539bool CertVerifyProcWin::SupportsAdditionalTrustAnchors() const {
540  return false;
541}
542
543int CertVerifyProcWin::VerifyInternal(
544    X509Certificate* cert,
545    const std::string& hostname,
546    int flags,
547    CRLSet* crl_set,
548    const CertificateList& additional_trust_anchors,
549    CertVerifyResult* verify_result) {
550  PCCERT_CONTEXT cert_handle = cert->os_cert_handle();
551  if (!cert_handle)
552    return ERR_UNEXPECTED;
553
554  // Build and validate certificate chain.
555  CERT_CHAIN_PARA chain_para;
556  memset(&chain_para, 0, sizeof(chain_para));
557  chain_para.cbSize = sizeof(chain_para);
558  // ExtendedKeyUsage.
559  // We still need to request szOID_SERVER_GATED_CRYPTO and szOID_SGC_NETSCAPE
560  // today because some certificate chains need them.  IE also requests these
561  // two usages.
562  static const LPSTR usage[] = {
563    szOID_PKIX_KP_SERVER_AUTH,
564    szOID_SERVER_GATED_CRYPTO,
565    szOID_SGC_NETSCAPE
566  };
567  chain_para.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
568  chain_para.RequestedUsage.Usage.cUsageIdentifier = arraysize(usage);
569  chain_para.RequestedUsage.Usage.rgpszUsageIdentifier =
570      const_cast<LPSTR*>(usage);
571
572  // Get the certificatePolicies extension of the certificate.
573  scoped_ptr<CERT_POLICIES_INFO, base::FreeDeleter> policies_info;
574  LPSTR ev_policy_oid = NULL;
575  if (flags & CertVerifier::VERIFY_EV_CERT) {
576    GetCertPoliciesInfo(cert_handle, &policies_info);
577    if (policies_info.get()) {
578      EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
579      for (DWORD i = 0; i < policies_info->cPolicyInfo; ++i) {
580        LPSTR policy_oid = policies_info->rgPolicyInfo[i].pszPolicyIdentifier;
581        if (metadata->IsEVPolicyOID(policy_oid)) {
582          ev_policy_oid = policy_oid;
583          chain_para.RequestedIssuancePolicy.dwType = USAGE_MATCH_TYPE_AND;
584          chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 1;
585          chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier =
586              &ev_policy_oid;
587          break;
588        }
589      }
590    }
591  }
592
593  // We can set CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS to get more chains.
594  DWORD chain_flags = CERT_CHAIN_CACHE_END_CERT |
595                      CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
596  bool rev_checking_enabled =
597      (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED);
598
599  if (rev_checking_enabled) {
600    verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
601  } else {
602    chain_flags |= CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
603  }
604
605  // For non-test scenarios, use the default HCERTCHAINENGINE, NULL, which
606  // corresponds to HCCE_CURRENT_USER and is is initialized as needed by
607  // crypt32. However, when testing, it is necessary to create a new
608  // HCERTCHAINENGINE and use that instead. This is because each
609  // HCERTCHAINENGINE maintains a cache of information about certificates
610  // encountered, and each test run may modify the trust status of a
611  // certificate.
612  ScopedHCERTCHAINENGINE chain_engine(NULL);
613  if (TestRootCerts::HasInstance())
614    chain_engine.reset(TestRootCerts::GetInstance()->GetChainEngine());
615
616  ScopedPCCERT_CONTEXT cert_list(cert->CreateOSCertChainForCert());
617  PCCERT_CHAIN_CONTEXT chain_context;
618  // IE passes a non-NULL pTime argument that specifies the current system
619  // time.  IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the
620  // chain_flags argument.
621  if (!CertGetCertificateChain(
622           chain_engine,
623           cert_list.get(),
624           NULL,  // current system time
625           cert_list->hCertStore,
626           &chain_para,
627           chain_flags,
628           NULL,  // reserved
629           &chain_context)) {
630    verify_result->cert_status |= CERT_STATUS_INVALID;
631    return MapSecurityError(GetLastError());
632  }
633
634  CRLSetResult crl_set_result = kCRLSetUnknown;
635  if (crl_set)
636    crl_set_result = CheckRevocationWithCRLSet(chain_context, crl_set);
637
638  if (crl_set_result == kCRLSetRevoked) {
639    verify_result->cert_status |= CERT_STATUS_REVOKED;
640  } else if (crl_set_result == kCRLSetUnknown &&
641             (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) &&
642             !rev_checking_enabled &&
643             ev_policy_oid != NULL) {
644    // We don't have fresh information about this chain from the CRLSet and
645    // it's probably an EV certificate. Retry with online revocation checking.
646    rev_checking_enabled = true;
647    chain_flags &= ~CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
648    verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
649
650    CertFreeCertificateChain(chain_context);
651    if (!CertGetCertificateChain(
652             chain_engine,
653             cert_list.get(),
654             NULL,  // current system time
655             cert_list->hCertStore,
656             &chain_para,
657             chain_flags,
658             NULL,  // reserved
659             &chain_context)) {
660      verify_result->cert_status |= CERT_STATUS_INVALID;
661      return MapSecurityError(GetLastError());
662    }
663  }
664
665  if (chain_context->TrustStatus.dwErrorStatus &
666      CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
667    ev_policy_oid = NULL;
668    chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 0;
669    chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = NULL;
670    CertFreeCertificateChain(chain_context);
671    if (!CertGetCertificateChain(
672             chain_engine,
673             cert_list.get(),
674             NULL,  // current system time
675             cert_list->hCertStore,
676             &chain_para,
677             chain_flags,
678             NULL,  // reserved
679             &chain_context)) {
680      verify_result->cert_status |= CERT_STATUS_INVALID;
681      return MapSecurityError(GetLastError());
682    }
683  }
684
685  CertVerifyResult temp_verify_result = *verify_result;
686  GetCertChainInfo(chain_context, verify_result);
687  if (!verify_result->is_issued_by_known_root &&
688      (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS)) {
689    *verify_result = temp_verify_result;
690
691    rev_checking_enabled = true;
692    verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
693    chain_flags &= ~CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
694
695    CertFreeCertificateChain(chain_context);
696    if (!CertGetCertificateChain(
697             chain_engine,
698             cert_list.get(),
699             NULL,  // current system time
700             cert_list->hCertStore,
701             &chain_para,
702             chain_flags,
703             NULL,  // reserved
704             &chain_context)) {
705      verify_result->cert_status |= CERT_STATUS_INVALID;
706      return MapSecurityError(GetLastError());
707    }
708    GetCertChainInfo(chain_context, verify_result);
709
710    if (chain_context->TrustStatus.dwErrorStatus &
711        CERT_TRUST_IS_OFFLINE_REVOCATION) {
712      verify_result->cert_status |= CERT_STATUS_REVOKED;
713    }
714  }
715
716  ScopedPCCERT_CHAIN_CONTEXT scoped_chain_context(chain_context);
717
718  verify_result->cert_status |= MapCertChainErrorStatusToCertStatus(
719      chain_context->TrustStatus.dwErrorStatus);
720
721  // Flag certificates that have a Subject common name with a NULL character.
722  if (CertSubjectCommonNameHasNull(cert_handle))
723    verify_result->cert_status |= CERT_STATUS_INVALID;
724
725  std::wstring wstr_hostname = base::ASCIIToWide(hostname);
726
727  SSL_EXTRA_CERT_CHAIN_POLICY_PARA extra_policy_para;
728  memset(&extra_policy_para, 0, sizeof(extra_policy_para));
729  extra_policy_para.cbSize = sizeof(extra_policy_para);
730  extra_policy_para.dwAuthType = AUTHTYPE_SERVER;
731  // Certificate name validation happens separately, later, using an internal
732  // routine that has better support for RFC 6125 name matching.
733  extra_policy_para.fdwChecks =
734      0x00001000;  // SECURITY_FLAG_IGNORE_CERT_CN_INVALID
735  extra_policy_para.pwszServerName =
736      const_cast<wchar_t*>(wstr_hostname.c_str());
737
738  CERT_CHAIN_POLICY_PARA policy_para;
739  memset(&policy_para, 0, sizeof(policy_para));
740  policy_para.cbSize = sizeof(policy_para);
741  policy_para.dwFlags = 0;
742  policy_para.pvExtraPolicyPara = &extra_policy_para;
743
744  CERT_CHAIN_POLICY_STATUS policy_status;
745  memset(&policy_status, 0, sizeof(policy_status));
746  policy_status.cbSize = sizeof(policy_status);
747
748  if (!CertVerifyCertificateChainPolicy(
749           CERT_CHAIN_POLICY_SSL,
750           chain_context,
751           &policy_para,
752           &policy_status)) {
753    return MapSecurityError(GetLastError());
754  }
755
756  if (policy_status.dwError) {
757    verify_result->cert_status |= MapNetErrorToCertStatus(
758        MapSecurityError(policy_status.dwError));
759  }
760
761  // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be
762  // compatible with WinHTTP, which doesn't report this error (bug 3004).
763  verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM;
764
765  // Perform hostname verification independent of
766  // CertVerifyCertificateChainPolicy.
767  if (!cert->VerifyNameMatch(hostname,
768                             &verify_result->common_name_fallback_used)) {
769    verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
770  }
771
772  if (!rev_checking_enabled) {
773    // If we didn't do online revocation checking then Windows will report
774    // CERT_UNABLE_TO_CHECK_REVOCATION unless it had cached OCSP or CRL
775    // information for every certificate. We only want to put up revoked
776    // statuses from the offline checks so we squash this error.
777    verify_result->cert_status &= ~CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
778  }
779
780  AppendPublicKeyHashes(chain_context, &verify_result->public_key_hashes);
781  verify_result->is_issued_by_known_root = IsIssuedByKnownRoot(chain_context);
782
783  if (IsCertStatusError(verify_result->cert_status))
784    return MapCertStatusToNetError(verify_result->cert_status);
785
786  if (ev_policy_oid &&
787      CheckEV(chain_context, rev_checking_enabled, ev_policy_oid)) {
788    verify_result->cert_status |= CERT_STATUS_IS_EV;
789  }
790  return OK;
791}
792
793}  // namespace net
794