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     } 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.
    358 void 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 
    386 enum 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.
    404 CRLSetResult 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 
    479 void 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.
    515 bool 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 
    554 CertVerifyProcWin::CertVerifyProcWin() {}
    555 
    556 CertVerifyProcWin::~CertVerifyProcWin() {}
    557 
    558 bool CertVerifyProcWin::SupportsAdditionalTrustAnchors() const {
    559   return false;
    560 }
    561 
    562 int 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