Home | History | Annotate | Download | only in cert
      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 
     36 namespace net {
     37 
     38 namespace {
     39 
     40 struct FreeChainEngineFunctor {
     41   void operator()(HCERTCHAINENGINE engine) const {
     42     if (engine)
     43       CertFreeCertificateChainEngine(engine);
     44   }
     45 };
     46 
     47 struct FreeCertChainContextFunctor {
     48   void operator()(PCCERT_CHAIN_CONTEXT chain_context) const {
     49     if (chain_context)
     50       CertFreeCertificateChain(chain_context);
     51   }
     52 };
     53 
     54 struct FreeCertContextFunctor {
     55   void operator()(PCCERT_CONTEXT context) const {
     56     if (context)
     57       CertFreeCertificateContext(context);
     58   }
     59 };
     60 
     61 typedef crypto::ScopedCAPIHandle<HCERTCHAINENGINE, FreeChainEngineFunctor>
     62     ScopedHCERTCHAINENGINE;
     63 
     64 typedef scoped_ptr<const CERT_CHAIN_CONTEXT, FreeCertChainContextFunctor>
     65     ScopedPCCERT_CHAIN_CONTEXT;
     66 
     67 typedef scoped_ptr<const CERT_CONTEXT, FreeCertContextFunctor>
     68     ScopedPCCERT_CONTEXT;
     69 
     70 //-----------------------------------------------------------------------------
     71 
     72 int 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.
    115 int 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.
    185 bool 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
    276 bool 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.
    292 void 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.
    351 void 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 
    379 enum 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.
    392 CRLSetResult 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 
    460 void 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.
    496 bool 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 
    535 CertVerifyProcWin::CertVerifyProcWin() {}
    536 
    537 CertVerifyProcWin::~CertVerifyProcWin() {}
    538 
    539 bool CertVerifyProcWin::SupportsAdditionalTrustAnchors() const {
    540   return false;
    541 }
    542 
    543 int 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