15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/cert_verify_proc_nss.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cert.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <nss.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <prerror.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <secerr.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sechash.h>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sslerr.h>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/nss_util.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/scoped_nss_types.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/sha2.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/asn1_util.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/cert_status_flags.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/cert_verifier.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/cert_verify_result.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/crl_set.h"
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/ev_root_ca_metadata.h"
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_certificate.h"
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util_nss.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_IOS)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <CommonCrypto/CommonDigest.h>
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util_ios.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(OS_IOS)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NSS_VERSION_NUM (NSS_VMAJOR * 10000 + NSS_VMINOR * 100 + NSS_VPATCH)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if NSS_VERSION_NUM < 31305
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Added in NSS 3.13.5.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED -8016
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if NSS_VERSION_NUM < 31402
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Added in NSS 3.14.2.
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define cert_pi_useOnlyTrustAnchors static_cast<CERTValParamInType>(14)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef scoped_ptr_malloc<
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CERTCertificatePolicies,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    crypto::NSSDestroyer<CERTCertificatePolicies,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         CERT_DestroyCertificatePoliciesExtension> >
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScopedCERTCertificatePolicies;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typedef scoped_ptr_malloc<
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CERTCertList,
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    crypto::NSSDestroyer<CERTCertList, CERT_DestroyCertList> >
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ScopedCERTCertList;
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ScopedCERTValOutParam manages destruction of values in the CERTValOutParam
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// array that cvout points to.  cvout must be initialized as passed to
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CERT_PKIXVerifyCert, so that the array must be terminated with
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cert_po_end type.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When it goes out of scope, it destroys values of cert_po_trustAnchor
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and cert_po_certList types, but doesn't release the array itself.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ScopedCERTValOutParam {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
70558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  explicit ScopedCERTValOutParam(CERTValOutParam* cvout) : cvout_(cvout) {}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~ScopedCERTValOutParam() {
73558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    Clear();
74558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
75558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
76558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Free the internal resources, but do not release the array itself.
77558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  void Clear() {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cvout_ == NULL)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (CERTValOutParam *p = cvout_; p->type != cert_po_end; p++) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch (p->type) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case cert_po_trustAnchor:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (p->value.pointer.cert) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            CERT_DestroyCertificate(p->value.pointer.cert);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            p->value.pointer.cert = NULL;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case cert_po_certList:
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (p->value.pointer.chain) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            CERT_DestroyCertList(p->value.pointer.chain);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            p->value.pointer.chain = NULL;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        default:
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTValOutParam* cvout_;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ScopedCERTValOutParam);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Map PORT_GetError() return values to our network error codes.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int MapSecurityError(int err) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (err) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PR_DIRECTORY_LOOKUP_ERROR:  // DNS lookup error.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_NAME_NOT_RESOLVED;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_INVALID_ARGS:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_INVALID_ARGUMENT;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SSL_ERROR_BAD_CERT_DOMAIN:
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_CERT_COMMON_NAME_INVALID;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_INVALID_TIME:
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_EXPIRED_CERTIFICATE:
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_CERT_DATE_INVALID;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_UNKNOWN_ISSUER:
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_UNTRUSTED_ISSUER:
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_CA_CERT_INVALID:
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_CERT_AUTHORITY_INVALID;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(port): map ERR_CERT_NO_REVOCATION_MECHANISM.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_OCSP_BAD_HTTP_RESPONSE:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_OCSP_SERVER_ERROR:
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_CERT_UNABLE_TO_CHECK_REVOCATION;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_REVOKED_CERTIFICATE:
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_UNTRUSTED_CERT:  // Treat as revoked.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_CERT_REVOKED;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_BAD_DER:
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_BAD_SIGNATURE:
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_CERT_NOT_VALID:
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(port): add an ERR_CERT_WRONG_USAGE error code.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_CERT_USAGES_INVALID:
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_INADEQUATE_KEY_USAGE:  // Key usage.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_INADEQUATE_CERT_TYPE:  // Extended key usage and whether
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          // the certificate is a CA.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_POLICY_VALIDATION_FAILED:
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID:
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_EXTENSION_VALUE_INVALID:
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_CERT_INVALID;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_CERT_WEAK_SIGNATURE_ALGORITHM;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_FAILED;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Map PORT_GetError() return values to our cert status flags.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CertStatus MapCertErrorToCertStatus(int err) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int net_error = MapSecurityError(err);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MapNetErrorToCertStatus(net_error);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Saves some information about the certificate chain cert_list in
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// *verify_result.  The caller MUST initialize *verify_result before calling
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this function.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that cert_list[0] is the end entity certificate.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetCertChainInfo(CERTCertList* cert_list,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      CERTCertificate* root_cert,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      CertVerifyResult* verify_result) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(cert_list);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTCertificate* verified_cert = NULL;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<CERTCertificate*> verified_chain;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i = 0;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       !CERT_LIST_END(node, cert_list);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       node = CERT_LIST_NEXT(node), ++i) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i == 0) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      verified_cert = node->cert;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Because of an NSS bug, CERT_PKIXVerifyCert may chain a self-signed
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // certificate of a root CA to another certificate of the same root CA
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // key.  Detect that error and ignore the root CA certificate.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // See https://bugzilla.mozilla.org/show_bug.cgi?id=721288.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (node->cert->isRoot) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // NOTE: isRoot doesn't mean the certificate is a trust anchor.  It
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // means the certificate is self-signed.  Here we assume isRoot only
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // implies the certificate is self-issued.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CERTCertListNode* next_node = CERT_LIST_NEXT(node);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CERTCertificate* next_cert;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!CERT_LIST_END(next_node, cert_list)) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          next_cert = next_node->cert;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          next_cert = root_cert;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Test that |node->cert| is actually a self-signed certificate
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // whose key is equal to |next_cert|, and not a self-issued
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // certificate signed by another key of the same CA.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (next_cert && SECITEM_ItemsAreEqual(&node->cert->derPublicKey,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &next_cert->derPublicKey)) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      verified_chain.push_back(node->cert);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECAlgorithmID& signature = node->cert->signature;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (oid_tag) {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        verify_result->has_md5 = true;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        verify_result->has_md2 = true;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        verify_result->has_md4 = true;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (root_cert)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    verified_chain.push_back(root_cert);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_IOS)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  verify_result->verified_cert =
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      x509_util_ios::CreateCertFromNSSHandles(verified_cert, verified_chain);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  verify_result->verified_cert =
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      X509Certificate::CreateFromHandle(verified_cert, verified_chain);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(OS_IOS)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// IsKnownRoot returns true if the given certificate is one that we believe
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is a standard (as opposed to user-installed) root.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsKnownRoot(CERTCertificate* root) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!root || !root->slot)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This magic name is taken from
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/builtins/constants.c&rev=1.13&mark=86,89#79
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0 == strcmp(PK11_GetSlotName(root->slot),
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     "NSS Builtin Objects");
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns true if the given certificate is one of the additional trust anchors.
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsAdditionalTrustAnchor(CERTCertList* additional_trust_anchors,
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             CERTCertificate* root) {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!additional_trust_anchors || !root)
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (CERTCertListNode* node = CERT_LIST_HEAD(additional_trust_anchors);
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       !CERT_LIST_END(node, additional_trust_anchors);
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       node = CERT_LIST_NEXT(node)) {
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (CERT_CompareCerts(node->cert, root))
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum CRLSetResult {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kCRLSetOk,
258a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  kCRLSetRevoked,
259a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  kCRLSetUnknown,
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CheckRevocationWithCRLSet attempts to check each element of |cert_list|
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// against |crl_set|. It returns:
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   kCRLSetRevoked: if any element of the chain is known to have been revoked.
265a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)//   kCRLSetUnknown: if there is no fresh information about some element in
266a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)//       the chain.
267a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)//   kCRLSetOk: if every element in the chain is covered by a fresh CRLSet and
268a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)//       is unrevoked.
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       CERTCertificate* root,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       CRLSet* crl_set) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<CERTCertificate*> certs;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cert_list) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         !CERT_LIST_END(node, cert_list);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         node = CERT_LIST_NEXT(node)) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      certs.push_back(node->cert);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (root)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    certs.push_back(root);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  bool covered = true;
285a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We iterate from the root certificate down to the leaf, keeping track of
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the issuer's SPKI at each step.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string issuer_spki_hash;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<CERTCertificate*>::reverse_iterator i = certs.rbegin();
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != certs.rend(); ++i) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CERTCertificate* cert = *i;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data),
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          cert->derCert.len);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::StringPiece spki;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!asn1::ExtractSPKIFromDERCert(der, &spki)) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
299a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      covered = false;
300a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      continue;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string spki_hash = crypto::SHA256HashString(spki);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::StringPiece serial_number = base::StringPiece(
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<char*>(cert->serialNumber.data),
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cert->serialNumber.len);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CRLSet::Result result = crl_set->CheckSPKI(spki_hash);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result != CRLSet::REVOKED && !issuer_spki_hash.empty())
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = crl_set->CheckSerial(serial_number, issuer_spki_hash);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    issuer_spki_hash = spki_hash;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (result) {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case CRLSet::REVOKED:
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return kCRLSetRevoked;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case CRLSet::UNKNOWN:
319a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        covered = false;
320a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        continue;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case CRLSet::GOOD:
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
325a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        covered = false;
326a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        continue;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
330a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!covered || crl_set->IsExpired())
331a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return kCRLSetUnknown;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kCRLSetOk;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Forward declarations.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus RetryPKIXVerifyCertWithWorkarounds(
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CERTCertificate* cert_handle, int num_policy_oids,
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool cert_io_enabled, std::vector<CERTValInParam>* cvin,
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CERTValOutParam* cvout);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Call CERT_PKIXVerifyCert for the cert_handle.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verification results are stored in an array of CERTValOutParam.
344558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// If |hard_fail| is true, and no policy_oids are supplied (eg: EV is NOT being
345558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// checked), then the failure to obtain valid CRL/OCSP information for all
346558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// certificates that contain CRL/OCSP URLs will cause the certificate to be
347558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// treated as if it was revoked. Since failures may be caused by transient
348558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// network failures or by malicious attackers, in general, hard_fail should be
349558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// false.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If policy_oids is not NULL and num_policy_oids is positive, policies
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are also checked.
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// additional_trust_anchors is an optional list of certificates that can be
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// trusted as anchors when building a certificate chain.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Caller must initialize cvout before calling this function.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus PKIXVerifyCert(CERTCertificate* cert_handle,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         bool check_revocation,
357558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                         bool hard_fail,
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         bool cert_io_enabled,
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const SECOidTag* policy_oids,
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int num_policy_oids,
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         CERTCertList* additional_trust_anchors,
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         CERTValOutParam* cvout) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool use_crl = check_revocation;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool use_ocsp = check_revocation;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PRUint64 revocation_method_flags =
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD |
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CERT_REV_M_ALLOW_NETWORK_FETCHING |
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE |
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CERT_REV_M_IGNORE_MISSING_FRESH_INFO |
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PRUint64 revocation_method_independent_flags =
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (check_revocation && policy_oids && num_policy_oids > 0) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // EV verification requires revocation checking.  Consider the certificate
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // revoked if we don't have revocation info.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(wtc): Add a bool parameter to expressly specify we're doing EV
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // verification or we want strict revocation flags.
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    revocation_method_independent_flags |=
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
382558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  } else if (check_revocation && hard_fail) {
383558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    revocation_method_flags |= CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO;
384558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    revocation_method_independent_flags |=
385558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    revocation_method_flags |= CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    revocation_method_independent_flags |=
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PRUint64 method_flags[2];
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  method_flags[cert_revocation_method_crl] = revocation_method_flags;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  method_flags[cert_revocation_method_ocsp] = revocation_method_flags;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (use_crl) {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_flags[cert_revocation_method_crl] |=
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CERT_REV_M_TEST_USING_THIS_METHOD;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (use_ocsp) {
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_flags[cert_revocation_method_ocsp] |=
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CERT_REV_M_TEST_USING_THIS_METHOD;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTRevocationMethodIndex preferred_revocation_methods[1];
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (use_ocsp) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preferred_revocation_methods[0] = cert_revocation_method_ocsp;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preferred_revocation_methods[0] = cert_revocation_method_crl;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTRevocationFlags revocation_flags;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  revocation_flags.leafTests.number_of_defined_methods =
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arraysize(method_flags);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  revocation_flags.leafTests.cert_rev_flags_per_method = method_flags;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  revocation_flags.leafTests.number_of_preferred_methods =
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arraysize(preferred_revocation_methods);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  revocation_flags.leafTests.preferred_methods = preferred_revocation_methods;
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  revocation_flags.leafTests.cert_rev_method_independent_flags =
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      revocation_method_independent_flags;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  revocation_flags.chainTests.number_of_defined_methods =
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arraysize(method_flags);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  revocation_flags.chainTests.cert_rev_flags_per_method = method_flags;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  revocation_flags.chainTests.number_of_preferred_methods =
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arraysize(preferred_revocation_methods);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  revocation_flags.chainTests.preferred_methods = preferred_revocation_methods;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  revocation_flags.chainTests.cert_rev_method_independent_flags =
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      revocation_method_independent_flags;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<CERTValInParam> cvin;
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cvin.reserve(7);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTValInParam in_param;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  in_param.type = cert_pi_revocationFlags;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  in_param.value.pointer.revocation = &revocation_flags;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvin.push_back(in_param);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (policy_oids && num_policy_oids > 0) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in_param.type = cert_pi_policyOID;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in_param.value.arraySize = num_policy_oids;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in_param.value.array.oids = policy_oids;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cvin.push_back(in_param);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (additional_trust_anchors) {
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    in_param.type = cert_pi_trustAnchors;
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    in_param.value.pointer.chain = additional_trust_anchors;
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cvin.push_back(in_param);
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    in_param.type = cert_pi_useOnlyTrustAnchors;
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    in_param.value.scalar.b = PR_FALSE;
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cvin.push_back(in_param);
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  in_param.type = cert_pi_end;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvin.push_back(in_param);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     &cvin[0], cvout, NULL);
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != SECSuccess) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids,
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            cert_io_enabled, &cvin, cvout);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PKIXVerifyCert calls this function to work around some bugs in
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CERT_PKIXVerifyCert.  All the arguments of this function are either the
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// arguments or local variables of PKIXVerifyCert.
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus RetryPKIXVerifyCertWithWorkarounds(
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CERTCertificate* cert_handle, int num_policy_oids,
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool cert_io_enabled, std::vector<CERTValInParam>* cvin,
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CERTValOutParam* cvout) {
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We call this function when the first CERT_PKIXVerifyCert call in
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PKIXVerifyCert failed,  so we initialize |rv| to SECFailure.
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = SECFailure;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nss_error = PORT_GetError();
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTValInParam in_param;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CA certificate, so we retry with cert_pi_useAIACertFetch.
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cert_pi_useAIACertFetch has several bugs in its error handling and
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // error reporting (NSS bug 528743), so we don't use it by default.
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: When building a certificate chain, CERT_PKIXVerifyCert may
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // incorrectly pick a CA certificate with the same subject name as the
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // missing intermediate CA certificate, and  fail with the
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SEC_ERROR_BAD_SIGNATURE error (NSS bug 524013), so we also retry with
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cert_pi_useAIACertFetch on SEC_ERROR_BAD_SIGNATURE.
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cert_io_enabled &&
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (nss_error == SEC_ERROR_UNKNOWN_ISSUER ||
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       nss_error == SEC_ERROR_BAD_SIGNATURE)) {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(cvin->back().type,  cert_pi_end);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cvin->pop_back();
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in_param.type = cert_pi_useAIACertFetch;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in_param.value.scalar.b = PR_TRUE;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cvin->push_back(in_param);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in_param.type = cert_pi_end;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cvin->push_back(in_param);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             &(*cvin)[0], cvout, NULL);
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv == SECSuccess)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return rv;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int new_nss_error = PORT_GetError();
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (new_nss_error == SEC_ERROR_INVALID_ARGS ||
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_nss_error == SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE ||
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_nss_error == SEC_ERROR_BAD_INFO_ACCESS_LOCATION ||
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_nss_error == SEC_ERROR_BAD_HTTP_RESPONSE ||
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_nss_error == SEC_ERROR_BAD_LDAP_RESPONSE ||
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !IS_SEC_ERROR(new_nss_error)) {
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Use the original error code because of cert_pi_useAIACertFetch's
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // bad error reporting.
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PORT_SetError(nss_error);
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return rv;
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nss_error = new_nss_error;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If an intermediate CA certificate has requireExplicitPolicy in its
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // policyConstraints extension, CERT_PKIXVerifyCert fails with
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SEC_ERROR_POLICY_VALIDATION_FAILED because we didn't specify any
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // certificate policy (NSS bug 552775).  So we retry with the certificate
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // policy found in the server certificate.
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (nss_error == SEC_ERROR_POLICY_VALIDATION_FAILED &&
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_policy_oids == 0) {
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECOidTag policy = GetFirstCertPolicy(cert_handle);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (policy != SEC_OID_UNKNOWN) {
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(cvin->back().type,  cert_pi_end);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cvin->pop_back();
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      in_param.type = cert_pi_policyOID;
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      in_param.value.arraySize = 1;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      in_param.value.array.oids = &policy;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cvin->push_back(in_param);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      in_param.type = cert_pi_end;
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cvin->push_back(in_param);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &(*cvin)[0], cvout, NULL);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (rv != SECSuccess) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Use the original error code.
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PORT_SetError(nss_error);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Decodes the certificatePolicies extension of the certificate.  Returns
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NULL if the certificate doesn't have the extension or the extension can't
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be decoded.  The returned value must be freed with a
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CERT_DestroyCertificatePoliciesExtension call.
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CERTCertificatePolicies* DecodeCertPolicies(
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CERTCertificate* cert_handle) {
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem policy_ext;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = CERT_FindCertExtension(cert_handle,
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        SEC_OID_X509_CERTIFICATE_POLICIES,
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        &policy_ext);
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != SECSuccess)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTCertificatePolicies* policies =
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CERT_DecodeCertificatePoliciesExtension(&policy_ext);
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECITEM_FreeItem(&policy_ext, PR_FALSE);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return policies;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the OID tag for the first certificate policy in the certificate's
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// certificatePolicies extension.  Returns SEC_OID_UNKNOWN if the certificate
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// has no certificate policy.
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle) {
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle));
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!policies.get())
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SEC_OID_UNKNOWN;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTPolicyInfo* policy_info = policies->policyInfos[0];
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!policy_info)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SEC_OID_UNKNOWN;
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (policy_info->oid != SEC_OID_UNKNOWN)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return policy_info->oid;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The certificate policy is unknown to NSS.  We need to create a dynamic
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // OID tag for the policy.
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECOidData od;
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  od.oid.len = policy_info->policyID.len;
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  od.oid.data = policy_info->policyID.data;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  od.offset = SEC_OID_UNKNOWN;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NSS doesn't allow us to pass an empty description, so I use a hardcoded,
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // default description here.  The description doesn't need to be unique for
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // each OID.
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  od.desc = "a certificate policy";
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  od.mechanism = CKM_INVALID_MECHANISM;
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  od.supportedExtension = INVALID_CERT_EXTENSION;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SECOID_AddEntry(&od);
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HashValue CertPublicKeyHashSHA1(CERTCertificate* cert) {
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HashValue hash(HASH_VALUE_SHA1);
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_IOS)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CC_SHA1(cert->derPublicKey.data, cert->derPublicKey.len, hash.data());
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data(),
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              cert->derPublicKey.data, cert->derPublicKey.len);
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(SECSuccess, rv);
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hash;
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HashValue CertPublicKeyHashSHA256(CERTCertificate* cert) {
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HashValue hash(HASH_VALUE_SHA256);
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_IOS)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CC_SHA256(cert->derPublicKey.data, cert->derPublicKey.len, hash.data());
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, hash.data(),
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              cert->derPublicKey.data, cert->derPublicKey.len);
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(rv, SECSuccess);
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hash;
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppendPublicKeyHashes(CERTCertList* cert_list,
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           CERTCertificate* root_cert,
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           HashValueVector* hashes) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       !CERT_LIST_END(node, cert_list);
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       node = CERT_LIST_NEXT(node)) {
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hashes->push_back(CertPublicKeyHashSHA1(node->cert));
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hashes->push_back(CertPublicKeyHashSHA256(node->cert));
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (root_cert) {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hashes->push_back(CertPublicKeyHashSHA1(root_cert));
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hashes->push_back(CertPublicKeyHashSHA256(root_cert));
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |cert_handle| contains a policy OID that is an EV policy
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OID according to |metadata|, storing the resulting policy OID in
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |*ev_policy_oid|. A true return is not sufficient to establish that a
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// certificate is EV, but a false return is sufficient to establish the
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// certificate cannot be EV.
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsEVCandidate(EVRootCAMetadata* metadata,
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   CERTCertificate* cert_handle,
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   SECOidTag* ev_policy_oid) {
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(cert_handle);
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle));
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!policies.get())
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTPolicyInfo** policy_infos = policies->policyInfos;
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (*policy_infos != NULL) {
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CERTPolicyInfo* policy_info = *policy_infos++;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the Policy OID is unknown, that implicitly means it has not been
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // registered as an EV policy.
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (policy_info->oid == SEC_OID_UNKNOWN)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (metadata->IsEVPolicyOID(policy_info->oid)) {
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *ev_policy_oid = policy_info->oid;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and nsNSSCertHelper.cpp) to learn how to verify EV certificate.
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(wtc): A possible optimization is that we get the trust anchor from
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the first PKIXVerifyCert call.  We look up the EV policy for the trust
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// anchor.  If the trust anchor has no EV policy, we know the cert isn't EV.
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Otherwise, we pass just that EV policy (as opposed to all the EV policies)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to the second PKIXVerifyCert call.
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VerifyEV(CERTCertificate* cert_handle,
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              int flags,
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              CRLSet* crl_set,
668a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)              bool rev_checking_enabled,
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              EVRootCAMetadata* metadata,
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              SECOidTag ev_policy_oid,
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              CERTCertList* additional_trust_anchors) {
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTValOutParam cvout[3];
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int cvout_index = 0;
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout[cvout_index].type = cert_po_certList;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout[cvout_index].value.pointer.chain = NULL;
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int cvout_cert_list_index = cvout_index;
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout_index++;
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout[cvout_index].type = cert_po_trustAnchor;
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout[cvout_index].value.pointer.cert = NULL;
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int cvout_trust_anchor_index = cvout_index;
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout_index++;
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout[cvout_index].type = cert_po_end;
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedCERTValOutParam scoped_cvout(cvout);
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus status = PKIXVerifyCert(
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cert_handle,
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rev_checking_enabled,
688558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      true, /* hard fail is implied in EV. */
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      flags & CertVerifier::VERIFY_CERT_IO_ENABLED,
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &ev_policy_oid,
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      1,
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      additional_trust_anchors,
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cvout);
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != SECSuccess)
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTCertificate* root_ca =
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cvout[cvout_trust_anchor_index].value.pointer.cert;
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (root_ca == NULL)
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This second PKIXVerifyCert call could have found a different certification
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // path and one or more of the certificates on this new path, that weren't on
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the old path, might have been revoked.
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (crl_set) {
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CRLSetResult crl_set_result = CheckRevocationWithCRLSet(
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cvout[cvout_cert_list_index].value.pointer.chain,
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cvout[cvout_trust_anchor_index].value.pointer.cert,
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        crl_set);
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (crl_set_result == kCRLSetRevoked)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_IOS)
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHA1HashValue fingerprint = x509_util_ios::CalculateFingerprintNSS(root_ca);
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHA1HashValue fingerprint =
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      X509Certificate::CalculateFingerprint(root_ca);
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid);
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)CERTCertList* CertificateListToCERTCertList(const CertificateList& list) {
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CERTCertList* result = CERT_NewCertList();
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < list.size(); ++i) {
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_IOS)
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // X509Certificate::os_cert_handle() on iOS is a SecCertificateRef; convert
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // it to an NSS CERTCertificate.
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CERTCertificate* cert = x509_util_ios::CreateNSSCertHandleFromOSHandle(
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        list[i]->os_cert_handle());
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CERTCertificate* cert = list[i]->os_cert_handle();
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CERT_AddCertToListTail(result, CERT_DupCertificate(cert));
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result;
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CertVerifyProcNSS::CertVerifyProcNSS() {}
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CertVerifyProcNSS::~CertVerifyProcNSS() {}
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool CertVerifyProcNSS::SupportsAdditionalTrustAnchors() const {
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This requires APIs introduced in 3.14.2.
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NSS_VersionCheck("3.14.2");
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int CertVerifyProcNSS::VerifyInternal(
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    X509Certificate* cert,
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& hostname,
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int flags,
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CRLSet* crl_set,
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const CertificateList& additional_trust_anchors,
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CertVerifyResult* verify_result) {
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_IOS)
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For iOS, the entire chain must be loaded into NSS's in-memory certificate
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // store.
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x509_util_ios::NSSCertChain scoped_chain(cert);
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTCertificate* cert_handle = scoped_chain.cert_handle();
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTCertificate* cert_handle = cert->os_cert_handle();
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(OS_IOS)
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure that the hostname matches with the common name of the cert.
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus status = CERT_VerifyCertName(cert_handle, hostname.c_str());
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != SECSuccess)
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure that the cert is valid now.
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECCertTimeValidity validity = CERT_CheckCertValidTimes(
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cert_handle, PR_Now(), PR_TRUE);
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (validity != secCertTimeValid)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTValOutParam cvout[3];
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int cvout_index = 0;
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout[cvout_index].type = cert_po_certList;
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout[cvout_index].value.pointer.chain = NULL;
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int cvout_cert_list_index = cvout_index;
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout_index++;
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout[cvout_index].type = cert_po_trustAnchor;
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout[cvout_index].value.pointer.cert = NULL;
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int cvout_trust_anchor_index = cvout_index;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout_index++;
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cvout[cvout_index].type = cert_po_end;
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedCERTValOutParam scoped_cvout(cvout);
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECOidTag ev_policy_oid = SEC_OID_UNKNOWN;
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_ev_candidate =
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (flags & CertVerifier::VERIFY_EV_CERT) &&
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IsEVCandidate(metadata, cert_handle, &ev_policy_oid);
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool cert_io_enabled = flags & CertVerifier::VERIFY_CERT_IO_ENABLED;
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool check_revocation =
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cert_io_enabled &&
798a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED);
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (check_revocation)
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScopedCERTCertList trust_anchors;
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (SupportsAdditionalTrustAnchors() && !additional_trust_anchors.empty()) {
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    trust_anchors.reset(
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        CertificateListToCERTCertList(additional_trust_anchors));
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
808558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  status = PKIXVerifyCert(cert_handle, check_revocation, false,
809558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                          cert_io_enabled, NULL, 0, trust_anchors.get(),
810558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                          cvout);
811558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
812558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (status == SECSuccess &&
813558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) &&
814558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      !IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert)) {
815558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // TODO(rsleevi): Optimize this by supplying the constructed chain to
816558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // libpkix via cvin. Omitting for now, due to lack of coverage in upstream
817558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // NSS tests for that feature.
818558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    scoped_cvout.Clear();
819558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
820558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    status = PKIXVerifyCert(cert_handle, true, true,
821558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            cert_io_enabled, NULL, 0, trust_anchors.get(),
822558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                            cvout);
823558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status == SECSuccess) {
8262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain,
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          cvout[cvout_trust_anchor_index].value.pointer.cert,
8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          &verify_result->public_key_hashes);
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    verify_result->is_issued_by_known_root =
8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert);
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    verify_result->is_issued_by_additional_trust_anchor =
8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IsAdditionalTrustAnchor(
8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            trust_anchors.get(),
8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            cvout[cvout_trust_anchor_index].value.pointer.cert);
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain,
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     cvout[cvout_trust_anchor_index].value.pointer.cert,
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     verify_result);
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
842a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  CRLSetResult crl_set_result = kCRLSetUnknown;
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (crl_set) {
844a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    crl_set_result = CheckRevocationWithCRLSet(
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cvout[cvout_cert_list_index].value.pointer.chain,
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cvout[cvout_trust_anchor_index].value.pointer.cert,
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        crl_set);
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (crl_set_result == kCRLSetRevoked) {
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status = SECFailure;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != SECSuccess) {
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int err = PORT_GetError();
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " failed err=" << err;
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // CERT_PKIXVerifyCert rerports the wrong error code for
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // expired certificates (NSS bug 491174)
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (err == SEC_ERROR_CERT_NOT_VALID &&
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (verify_result->cert_status & CERT_STATUS_DATE_INVALID))
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      err = SEC_ERROR_EXPIRED_CERTIFICATE;
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CertStatus cert_status = MapCertErrorToCertStatus(err);
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cert_status) {
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      verify_result->cert_status |= cert_status;
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return MapCertStatusToNetError(verify_result->cert_status);
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |err| is not a certificate error.
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return MapSecurityError(err);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsCertStatusError(verify_result->cert_status))
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return MapCertStatusToNetError(verify_result->cert_status);
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) {
876a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    check_revocation |=
877a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        crl_set_result != kCRLSetOk &&
878a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        cert_io_enabled &&
879a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY);
880a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (check_revocation)
881a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
882a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
883a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (VerifyEV(cert_handle, flags, crl_set, check_revocation, metadata,
884a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                 ev_policy_oid, trust_anchors.get())) {
885a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      verify_result->cert_status |= CERT_STATUS_IS_EV;
886a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OK;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
893