1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/x509_certificate.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <cert.h>
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <cryptohi.h>
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <keyhi.h>
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <nss.h>
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <pk11pub.h>
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <prerror.h>
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <prtime.h>
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <secder.h>
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <secerr.h>
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sechash.h>
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sslerr.h>
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/pickle.h"
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/time.h"
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/nss_util.h"
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/rsa_private_key.h"
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/cert_status_flags.h"
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/cert_verify_result.h"
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/ev_root_ca_metadata.h"
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h"
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass ScopedCERTCertificatePolicies {
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies)
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : policies_(policies) {}
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~ScopedCERTCertificatePolicies() {
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (policies_)
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CERT_DestroyCertificatePoliciesExtension(policies_);
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTCertificatePolicies* policies_;
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertificatePolicies);
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// ScopedCERTValOutParam manages destruction of values in the CERTValOutParam
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// array that cvout points to.  cvout must be initialized as passed to
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// CERT_PKIXVerifyCert, so that the array must be terminated with
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// cert_po_end type.
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// When it goes out of scope, it destroys values of cert_po_trustAnchor
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// and cert_po_certList types, but doesn't release the array itself.
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass ScopedCERTValOutParam {
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  explicit ScopedCERTValOutParam(CERTValOutParam* cvout)
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : cvout_(cvout) {}
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~ScopedCERTValOutParam() {
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (cvout_ == NULL)
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return;
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    for (CERTValOutParam *p = cvout_; p->type != cert_po_end; p++) {
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      switch (p->type) {
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        case cert_po_trustAnchor:
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          if (p->value.pointer.cert) {
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            CERT_DestroyCertificate(p->value.pointer.cert);
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            p->value.pointer.cert = NULL;
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          }
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          break;
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        case cert_po_certList:
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          if (p->value.pointer.chain) {
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            CERT_DestroyCertList(p->value.pointer.chain);
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            p->value.pointer.chain = NULL;
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          }
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          break;
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        default:
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          break;
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTValOutParam* cvout_;
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DISALLOW_COPY_AND_ASSIGN(ScopedCERTValOutParam);
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Map PORT_GetError() return values to our network error codes.
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint MapSecurityError(int err) {
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  switch (err) {
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case PR_DIRECTORY_LOOKUP_ERROR:  // DNS lookup error.
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_NAME_NOT_RESOLVED;
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_INVALID_ARGS:
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_INVALID_ARGUMENT;
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SSL_ERROR_BAD_CERT_DOMAIN:
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_CERT_COMMON_NAME_INVALID;
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_INVALID_TIME:
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_EXPIRED_CERTIFICATE:
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_CERT_DATE_INVALID;
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_UNKNOWN_ISSUER:
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_UNTRUSTED_ISSUER:
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_CA_CERT_INVALID:
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_CERT_AUTHORITY_INVALID;
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_REVOKED_CERTIFICATE:
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_UNTRUSTED_CERT:  // Treat as revoked.
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_CERT_REVOKED;
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_BAD_DER:
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_BAD_SIGNATURE:
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_CERT_NOT_VALID:
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // TODO(port): add an ERR_CERT_WRONG_USAGE error code.
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_CERT_USAGES_INVALID:
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_INADEQUATE_KEY_USAGE:
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_INADEQUATE_CERT_TYPE:
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case SEC_ERROR_POLICY_VALIDATION_FAILED:
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID:
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_EXTENSION_VALUE_INVALID:
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_CERT_INVALID;
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    default:
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_FAILED;
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Map PORT_GetError() return values to our cert status flags.
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint MapCertErrorToCertStatus(int err) {
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  switch (err) {
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SSL_ERROR_BAD_CERT_DOMAIN:
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return CERT_STATUS_COMMON_NAME_INVALID;
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_INVALID_TIME:
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_EXPIRED_CERTIFICATE:
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return CERT_STATUS_DATE_INVALID;
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_UNKNOWN_ISSUER:
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_UNTRUSTED_ISSUER:
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_CA_CERT_INVALID:
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return CERT_STATUS_AUTHORITY_INVALID;
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // TODO(port): map CERT_STATUS_NO_REVOCATION_MECHANISM.
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_OCSP_BAD_HTTP_RESPONSE:
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_OCSP_SERVER_ERROR:
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_REVOKED_CERTIFICATE:
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_UNTRUSTED_CERT:  // Treat as revoked.
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return CERT_STATUS_REVOKED;
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_BAD_DER:
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_BAD_SIGNATURE:
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_CERT_NOT_VALID:
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // TODO(port): add a CERT_STATUS_WRONG_USAGE error code.
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case SEC_ERROR_CERT_USAGES_INVALID:
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_INADEQUATE_KEY_USAGE:  // Key usage.
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_INADEQUATE_CERT_TYPE:  // Extended key usage and whether
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                          // the certificate is a CA.
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case SEC_ERROR_POLICY_VALIDATION_FAILED:
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID:
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SEC_ERROR_EXTENSION_VALUE_INVALID:
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return CERT_STATUS_INVALID;
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    default:
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return 0;
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Saves some information about the certificate chain cert_list in
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// *verify_result.  The caller MUST initialize *verify_result before calling
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// this function.
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Note that cert_list[0] is the end entity certificate and cert_list doesn't
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// contain the root CA certificate.
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid GetCertChainInfo(CERTCertList* cert_list,
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      CertVerifyResult* verify_result) {
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // NOTE: Using a NSS library before 3.12.3.1 will crash below.  To see the
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // NSS version currently in use:
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // 1. use ldd on the chrome executable for NSS's location (ie. libnss3.so*)
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // 2. use ident libnss3.so* for the library's version
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(cert_list);
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int i = 0;
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott       !CERT_LIST_END(node, cert_list);
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott       node = CERT_LIST_NEXT(node), i++) {
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SECAlgorithmID& signature = node->cert->signature;
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm);
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    switch (oid_tag) {
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        verify_result->has_md5 = true;
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (i != 0)
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          verify_result->has_md5_ca = true;
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        verify_result->has_md2 = true;
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (i != 0)
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          verify_result->has_md2_ca = true;
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        verify_result->has_md4 = true;
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      default:
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// IsKnownRoot returns true if the given certificate is one that we believe
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// is a standard (as opposed to user-installed) root.
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool IsKnownRoot(CERTCertificate* root) {
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!root->slot)
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This magic name is taken from
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/builtins/constants.c&rev=1.13&mark=86,89#79
214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return 0 == strcmp(PK11_GetSlotName(root->slot),
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     "NSS Builtin Objects");
216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttypedef char* (*CERTGetNameFunc)(CERTName* name);
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid ParsePrincipal(CERTName* name,
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    CertPrincipal* principal) {
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // TODO(jcampan): add business_category and serial_number.
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // CERT_GetDomainComponentName functions, but they return only the most
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // general (the first) RDN.  NSS doesn't have a function for the street
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // address.
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  static const SECOidTag kOIDs[] = {
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      SEC_OID_AVA_STREET_ADDRESS,
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      SEC_OID_AVA_ORGANIZATION_NAME,
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      SEC_OID_AVA_DC };
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::vector<std::string>* values[] = {
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      &principal->street_addresses,
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      &principal->organization_names,
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      &principal->organization_unit_names,
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      &principal->domain_components };
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(arraysize(kOIDs) == arraysize(values));
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTRDN** rdns = name->rdns;
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (size_t rdn = 0; rdns[rdn]; ++rdn) {
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CERTAVA** avas = rdns[rdn]->avas;
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    for (size_t pair = 0; avas[pair] != 0; ++pair) {
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      SECOidTag tag = CERT_GetAVATag(avas[pair]);
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) {
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (kOIDs[oid] == tag) {
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value);
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          if (!decode_item)
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            break;
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          std::string value(reinterpret_cast<char*>(decode_item->data),
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            decode_item->len);
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          values[oid]->push_back(value);
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          SECITEM_FreeItem(decode_item, PR_TRUE);
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          break;
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        }
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Get CN, L, S, and C.
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTGetNameFunc get_name_funcs[4] = {
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CERT_GetCommonName, CERT_GetLocalityName,
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CERT_GetStateName, CERT_GetCountryName };
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string* single_values[4] = {
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      &principal->common_name, &principal->locality_name,
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      &principal->state_or_province_name, &principal->country_name };
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (size_t i = 0; i < arraysize(get_name_funcs); ++i) {
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    char* value = get_name_funcs[i](name);
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (value) {
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      single_values[i]->assign(value);
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      PORT_Free(value);
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid ParseDate(SECItem* der_date, base::Time* result) {
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PRTime prtime;
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECStatus rv = DER_DecodeTimeChoice(&prtime, der_date);
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(rv == SECSuccess);
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  *result = crypto::PRTimeToBaseTime(prtime);
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid GetCertSubjectAltNamesOfType(X509Certificate::OSCertHandle cert_handle,
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                  CERTGeneralNameType name_type,
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                  std::vector<std::string>* result) {
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // For future extension: We only support general names of types
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // RFC822Name, DNSName or URI.
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(name_type == certRFC822Name ||
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott         name_type == certDNSName ||
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott         name_type == certURI);
292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECItem alt_name;
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECStatus rv = CERT_FindCertExtension(cert_handle,
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      SEC_OID_X509_SUBJECT_ALT_NAME, &alt_name);
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv != SECSuccess)
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PRArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(arena != NULL);
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTGeneralName* alt_name_list;
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  alt_name_list = CERT_DecodeAltNameExtension(arena, &alt_name);
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECITEM_FreeItem(&alt_name, PR_FALSE);
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTGeneralName* name = alt_name_list;
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (name) {
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // All of the general name types we support are encoded as
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // IA5String. In general, we should be switching off
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // |name->type| and doing type-appropriate conversions.
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (name->type == name_type) {
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      unsigned char* p = name->name.other.data;
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      int len = name->name.other.len;
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      std::string value = std::string(reinterpret_cast<char*>(p), len);
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      result->push_back(value);
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    name = CERT_GetNextGeneralName(name);
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (name == alt_name_list)
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      break;
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PORT_FreeArena(arena, PR_FALSE);
322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Forward declarations.
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSECStatus RetryPKIXVerifyCertWithWorkarounds(
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    X509Certificate::OSCertHandle cert_handle, int num_policy_oids,
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<CERTValInParam>* cvin, CERTValOutParam* cvout);
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle);
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Call CERT_PKIXVerifyCert for the cert_handle.
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Verification results are stored in an array of CERTValOutParam.
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// If policy_oids is not NULL and num_policy_oids is positive, policies
333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// are also checked.
334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Caller must initialize cvout before calling this function.
335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSECStatus PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle,
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         bool check_revocation,
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         const SECOidTag* policy_oids,
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         int num_policy_oids,
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         CERTValOutParam* cvout) {
340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool use_crl = check_revocation;
341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool use_ocsp = check_revocation;
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // These CAs have multiple keys, which trigger two bugs in NSS's CRL code.
3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // 1. NSS may use one key to verify a CRL signed with another key,
3453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  //    incorrectly concluding that the CRL's signature is invalid.
3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  //    Hopefully this bug will be fixed in NSS 3.12.9.
3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // 2. NSS considers all certificates issued by the CA as revoked when it
3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  //    receives a CRL with an invalid signature.  This overly strict policy
3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  //    has been relaxed in NSS 3.12.7.  See
3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  //    https://bugzilla.mozilla.org/show_bug.cgi?id=562542.
3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // So we have to turn off CRL checking for these CAs.  See
3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // http://crbug.com/55695.
3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static const char* const kMultipleKeyCA[] = {
3543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    "CN=Microsoft Secure Server Authority,"
3553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    "DC=redmond,DC=corp,DC=microsoft,DC=com",
3563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    "CN=Microsoft Secure Server Authority",
3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
3583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!NSS_VersionCheck("3.12.7")) {
3603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    for (size_t i = 0; i < arraysize(kMultipleKeyCA); ++i) {
3613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (strcmp(cert_handle->issuerName, kMultipleKeyCA[i]) == 0) {
3623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        use_crl = false;
3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
3643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
3673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PRUint64 revocation_method_flags =
369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD |
370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CERT_REV_M_ALLOW_NETWORK_FETCHING |
371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE |
372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CERT_REV_M_IGNORE_MISSING_FRESH_INFO |
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PRUint64 revocation_method_independent_flags =
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (policy_oids && num_policy_oids > 0) {
377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // EV verification requires revocation checking.  Consider the certificate
378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // revoked if we don't have revocation info.
379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // TODO(wtc): Add a bool parameter to expressly specify we're doing EV
380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // verification or we want strict revocation flags.
381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE;
382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    revocation_method_independent_flags |=
383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    revocation_method_flags |= CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE;
386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    revocation_method_independent_flags |=
387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT;
388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PRUint64 method_flags[2];
390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  method_flags[cert_revocation_method_crl] = revocation_method_flags;
391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  method_flags[cert_revocation_method_ocsp] = revocation_method_flags;
392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (use_crl) {
394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    method_flags[cert_revocation_method_crl] |=
395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        CERT_REV_M_TEST_USING_THIS_METHOD;
396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (use_ocsp) {
398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    method_flags[cert_revocation_method_ocsp] |=
399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        CERT_REV_M_TEST_USING_THIS_METHOD;
400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTRevocationMethodIndex preferred_revocation_methods[1];
403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (use_ocsp) {
404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    preferred_revocation_methods[0] = cert_revocation_method_ocsp;
405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    preferred_revocation_methods[0] = cert_revocation_method_crl;
407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTRevocationFlags revocation_flags;
410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  revocation_flags.leafTests.number_of_defined_methods =
411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      arraysize(method_flags);
412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  revocation_flags.leafTests.cert_rev_flags_per_method = method_flags;
413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  revocation_flags.leafTests.number_of_preferred_methods =
414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      arraysize(preferred_revocation_methods);
415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  revocation_flags.leafTests.preferred_methods = preferred_revocation_methods;
416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  revocation_flags.leafTests.cert_rev_method_independent_flags =
417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      revocation_method_independent_flags;
418c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
419c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  revocation_flags.chainTests.number_of_defined_methods =
420c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      arraysize(method_flags);
421c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  revocation_flags.chainTests.cert_rev_flags_per_method = method_flags;
422c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  revocation_flags.chainTests.number_of_preferred_methods =
423c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      arraysize(preferred_revocation_methods);
424c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  revocation_flags.chainTests.preferred_methods = preferred_revocation_methods;
425c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  revocation_flags.chainTests.cert_rev_method_independent_flags =
426c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      revocation_method_independent_flags;
427c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<CERTValInParam> cvin;
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cvin.reserve(5);
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CERTValInParam in_param;
431c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // No need to set cert_pi_trustAnchors here.
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  in_param.type = cert_pi_revocationFlags;
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  in_param.value.pointer.revocation = &revocation_flags;
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cvin.push_back(in_param);
435c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (policy_oids && num_policy_oids > 0) {
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    in_param.type = cert_pi_policyOID;
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    in_param.value.arraySize = num_policy_oids;
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    in_param.value.array.oids = policy_oids;
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cvin.push_back(in_param);
440c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  in_param.type = cert_pi_end;
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cvin.push_back(in_param);
443c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
444c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECStatus rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     &cvin[0], cvout, NULL);
446c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv != SECSuccess) {
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids,
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            &cvin, cvout);
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// PKIXVerifyCert calls this function to work around some bugs in
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// CERT_PKIXVerifyCert.  All the arguments of this function are either the
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// arguments or local variables of PKIXVerifyCert.
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSECStatus RetryPKIXVerifyCertWithWorkarounds(
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    X509Certificate::OSCertHandle cert_handle, int num_policy_oids,
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<CERTValInParam>* cvin, CERTValOutParam* cvout) {
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We call this function when the first CERT_PKIXVerifyCert call in
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // PKIXVerifyCert failed,  so we initialize |rv| to SECFailure.
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECStatus rv = SECFailure;
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int nss_error = PORT_GetError();
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CERTValInParam in_param;
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // CA certificate, so we retry with cert_pi_useAIACertFetch.
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // cert_pi_useAIACertFetch has several bugs in its error handling and
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // error reporting (NSS bug 528743), so we don't use it by default.
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Note: When building a certificate chain, CERT_PKIXVerifyCert may
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // incorrectly pick a CA certificate with the same subject name as the
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // missing intermediate CA certificate, and  fail with the
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // SEC_ERROR_BAD_SIGNATURE error (NSS bug 524013), so we also retry with
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // cert_pi_useAIACertFetch on SEC_ERROR_BAD_SIGNATURE.
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (nss_error == SEC_ERROR_UNKNOWN_ISSUER ||
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      nss_error == SEC_ERROR_BAD_SIGNATURE) {
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK_EQ(cvin->back().type,  cert_pi_end);
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cvin->pop_back();
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    in_param.type = cert_pi_useAIACertFetch;
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    in_param.value.scalar.b = PR_TRUE;
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cvin->push_back(in_param);
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    in_param.type = cert_pi_end;
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cvin->push_back(in_param);
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             &(*cvin)[0], cvout, NULL);
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (rv == SECSuccess)
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return rv;
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int new_nss_error = PORT_GetError();
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (new_nss_error == SEC_ERROR_INVALID_ARGS ||
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_nss_error == SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE ||
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_nss_error == SEC_ERROR_BAD_HTTP_RESPONSE ||
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_nss_error == SEC_ERROR_BAD_LDAP_RESPONSE ||
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !IS_SEC_ERROR(new_nss_error)) {
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Use the original error code because of cert_pi_useAIACertFetch's
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // bad error reporting.
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PORT_SetError(nss_error);
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return rv;
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    nss_error = new_nss_error;
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If an intermediate CA certificate has requireExplicitPolicy in its
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // policyConstraints extension, CERT_PKIXVerifyCert fails with
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // SEC_ERROR_POLICY_VALIDATION_FAILED because we didn't specify any
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // certificate policy (NSS bug 552775).  So we retry with the certificate
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // policy found in the server certificate.
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (nss_error == SEC_ERROR_POLICY_VALIDATION_FAILED &&
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      num_policy_oids == 0) {
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SECOidTag policy = GetFirstCertPolicy(cert_handle);
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (policy != SEC_OID_UNKNOWN) {
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK_EQ(cvin->back().type,  cert_pi_end);
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cvin->pop_back();
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      in_param.type = cert_pi_policyOID;
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      in_param.value.arraySize = 1;
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      in_param.value.array.oids = &policy;
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cvin->push_back(in_param);
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      in_param.type = cert_pi_end;
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cvin->push_back(in_param);
518c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               &(*cvin)[0], cvout, NULL);
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (rv != SECSuccess) {
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Use the original error code.
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        PORT_SetError(nss_error);
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
524c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
525c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
527c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return rv;
528c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
529c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Decodes the certificatePolicies extension of the certificate.  Returns
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// NULL if the certificate doesn't have the extension or the extension can't
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// be decoded.  The returned value must be freed with a
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// CERT_DestroyCertificatePoliciesExtension call.
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCERTCertificatePolicies* DecodeCertPolicies(
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    X509Certificate::OSCertHandle cert_handle) {
536c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECItem policy_ext;
537c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECStatus rv = CERT_FindCertExtension(
538c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      cert_handle, SEC_OID_X509_CERTIFICATE_POLICIES, &policy_ext);
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != SECSuccess)
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
541c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTCertificatePolicies* policies =
542c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CERT_DecodeCertificatePoliciesExtension(&policy_ext);
543c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECITEM_FreeItem(&policy_ext, PR_FALSE);
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return policies;
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns the OID tag for the first certificate policy in the certificate's
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// certificatePolicies extension.  Returns SEC_OID_UNKNOWN if the certificate
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// has no certificate policy.
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle) {
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!policies)
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return SEC_OID_UNKNOWN;
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedCERTCertificatePolicies scoped_policies(policies);
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CERTPolicyInfo* policy_info = policies->policyInfos[0];
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!policy_info)
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return SEC_OID_UNKNOWN;
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (policy_info->oid != SEC_OID_UNKNOWN)
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return policy_info->oid;
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The certificate policy is unknown to NSS.  We need to create a dynamic
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // OID tag for the policy.
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECOidData od;
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  od.oid.len = policy_info->policyID.len;
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  od.oid.data = policy_info->policyID.data;
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  od.offset = SEC_OID_UNKNOWN;
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NSS doesn't allow us to pass an empty description, so I use a hardcoded,
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // default description here.  The description doesn't need to be unique for
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // each OID.
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  od.desc = "a certificate policy";
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  od.mechanism = CKM_INVALID_MECHANISM;
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  od.supportedExtension = INVALID_CERT_EXTENSION;
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return SECOID_AddEntry(&od);
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       SECOidTag ev_policy_tag) {
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
579c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!policies) {
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Cert has no policies extension or extension couldn't be "
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  "decoded.";
582c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
583c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
584c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ScopedCERTCertificatePolicies scoped_policies(policies);
585c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTPolicyInfo** policy_infos = policies->policyInfos;
586c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (*policy_infos != NULL) {
587c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CERTPolicyInfo* policy_info = *policy_infos++;
588c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SECOidTag oid_tag = policy_info->oid;
589c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (oid_tag == SEC_OID_UNKNOWN)
590c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
591c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (oid_tag == ev_policy_tag)
592c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return true;
593c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
594c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  LOG(ERROR) << "No EV Policy Tag";
595c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return false;
596c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
597c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5983345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickSECStatus PR_CALLBACK
5993345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickCollectCertsCallback(void* arg, SECItem** certs, int num_certs) {
6003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  X509Certificate::OSCertHandles* results =
6013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      reinterpret_cast<X509Certificate::OSCertHandles*>(arg);
6023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (int i = 0; i < num_certs; ++i) {
6043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    X509Certificate::OSCertHandle handle =
6053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        X509Certificate::CreateOSCertHandleFromBytes(
6063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            reinterpret_cast<char*>(certs[i]->data), certs[i]->len);
6073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (handle)
6083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      results->push_back(handle);
6093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
6103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return SECSuccess;
6123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
6133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
614ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSHA1Fingerprint CertPublicKeyHash(CERTCertificate* cert) {
615ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SHA1Fingerprint hash;
616ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data,
617ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              cert->derPublicKey.data, cert->derPublicKey.len);
618ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(rv, SECSuccess);
619ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return hash;
620ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
621ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
622ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid AppendPublicKeyHashes(CERTCertList* cert_list,
623ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           CERTCertificate* root_cert,
624ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           std::vector<SHA1Fingerprint>* hashes) {
625ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
626ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       !CERT_LIST_END(node, cert_list);
627ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       node = CERT_LIST_NEXT(node)) {
628ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    hashes->push_back(CertPublicKeyHash(node->cert));
629ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
630ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  hashes->push_back(CertPublicKeyHash(root_cert));
631ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
632ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
633c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace
634c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
635c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid X509Certificate::Initialize() {
636c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ParsePrincipal(&cert_handle_->subject, &subject_);
637c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ParsePrincipal(&cert_handle_->issuer, &issuer_);
638c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
639c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ParseDate(&cert_handle_->validity.notBefore, &valid_start_);
640c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_);
641c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
642c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  fingerprint_ = CalculateFingerprint(cert_handle_);
643c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
644ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  serial_number_ = std::string(
645ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      reinterpret_cast<char*>(cert_handle_->serialNumber.data),
646ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      cert_handle_->serialNumber.len);
647ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Remove leading zeros.
648ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  while (serial_number_.size() > 1 && serial_number_[0] == 0)
649ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    serial_number_ = serial_number_.substr(1, serial_number_.size() - 1);
650c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
651c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
65221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// static
65321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenX509Certificate* X509Certificate::CreateSelfSigned(
654ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    crypto::RSAPrivateKey* key,
65521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const std::string& subject,
65621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    uint32 serial_number,
65721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    base::TimeDelta valid_duration) {
65821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(key);
65921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
66021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Create info about public key.
66121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTSubjectPublicKeyInfo* spki =
66221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      SECKEY_CreateSubjectPublicKeyInfo(key->public_key());
66321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!spki)
66421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return NULL;
66521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
66621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Create the certificate request.
66721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTName* subject_name =
66821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CERT_AsciiToName(const_cast<char*>(subject.c_str()));
66921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTCertificateRequest* cert_request =
67021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CERT_CreateCertificateRequest(subject_name, spki, NULL);
67121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  SECKEY_DestroySubjectPublicKeyInfo(spki);
67221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
67321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!cert_request) {
67421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    PRErrorCode prerr = PR_GetError();
67521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    LOG(ERROR) << "Failed to create certificate request: " << prerr;
67621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CERT_DestroyName(subject_name);
67721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return NULL;
67821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
67921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
68021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PRTime now = PR_Now();
68121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PRTime not_after = now + valid_duration.InMicroseconds();
68221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
68321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Note that the time is now in micro-second unit.
68421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTValidity* validity = CERT_CreateValidity(now, not_after);
68521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTCertificate* cert = CERT_CreateCertificate(serial_number, subject_name,
68621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                 validity, cert_request);
68721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!cert) {
68821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    PRErrorCode prerr = PR_GetError();
68921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    LOG(ERROR) << "Failed to create certificate: " << prerr;
69021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
69121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
69221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Cleanup for resources used to generate the cert.
69321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERT_DestroyName(subject_name);
69421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERT_DestroyValidity(validity);
69521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERT_DestroyCertificateRequest(cert_request);
69621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
69721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Sign the cert here. The logic of this method references SignCert() in NSS
69821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // utility certutil: http://mxr.mozilla.org/security/ident?i=SignCert.
69921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
70021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // |arena| is used to encode the cert.
70121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PRArenaPool* arena = cert->arena;
70221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  SECOidTag algo_id = SEC_GetSignatureAlgorithmOidTag(key->key()->keyType,
70321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                      SEC_OID_SHA1);
70421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (algo_id == SEC_OID_UNKNOWN) {
70521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CERT_DestroyCertificate(cert);
70621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return NULL;
70721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
70821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
70921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  SECStatus rv = SECOID_SetAlgorithmID(arena, &cert->signature, algo_id, 0);
71021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (rv != SECSuccess) {
71121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CERT_DestroyCertificate(cert);
71221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return NULL;
71321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
71421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
71521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Generate a cert of version 3.
71621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  *(cert->version.data) = 2;
71721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  cert->version.len = 1;
71821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
71921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  SECItem der;
72021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  der.len = 0;
72121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  der.data = NULL;
72221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
72321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Use ASN1 DER to encode the cert.
72421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void* encode_result = SEC_ASN1EncodeItem(
72521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      arena, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate));
72621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!encode_result) {
72721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CERT_DestroyCertificate(cert);
72821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return NULL;
72921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
73021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
73121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Allocate space to contain the signed cert.
73221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  SECItem* result = SECITEM_AllocItem(arena, NULL, 0);
73321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!result) {
73421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CERT_DestroyCertificate(cert);
73521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return NULL;
73621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
73721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
73821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Sign the ASN1 encoded cert and save it to |result|.
73921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  rv = SEC_DerSignData(arena, result, der.data, der.len, key->key(), algo_id);
74021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (rv != SECSuccess) {
74121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CERT_DestroyCertificate(cert);
74221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return NULL;
74321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
74421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
74521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Save the signed result to the cert.
74621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  cert->derCert = *result;
74721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
74821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  X509Certificate* x509_cert =
74921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CreateFromHandle(cert, SOURCE_LONE_CERT_IMPORT, OSCertHandles());
75021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERT_DestroyCertificate(cert);
75121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return x509_cert;
75221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
75321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
754c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const {
755c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  dns_names->clear();
756c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
757c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Compare with CERT_VerifyCertName().
758c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  GetCertSubjectAltNamesOfType(cert_handle_, certDNSName, dns_names);
759c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
760c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (dns_names->empty())
761c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    dns_names->push_back(subject_.common_name);
762c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
763c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
764c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint X509Certificate::Verify(const std::string& hostname,
765c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            int flags,
766c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            CertVerifyResult* verify_result) const {
767c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  verify_result->Reset();
768c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
769ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsBlacklisted()) {
770ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    verify_result->cert_status |= CERT_STATUS_REVOKED;
771ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return ERR_CERT_REVOKED;
772ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
773ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
774c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Make sure that the hostname matches with the common name of the cert.
775c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECStatus status = CERT_VerifyCertName(cert_handle_, hostname.c_str());
776c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (status != SECSuccess)
777c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
778c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
779c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Make sure that the cert is valid now.
780c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECCertTimeValidity validity = CERT_CheckCertValidTimes(
781c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      cert_handle_, PR_Now(), PR_TRUE);
782c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (validity != secCertTimeValid)
783c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
784c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
785c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTValOutParam cvout[3];
786c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int cvout_index = 0;
787c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cvout[cvout_index].type = cert_po_certList;
788c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cvout[cvout_index].value.pointer.chain = NULL;
789c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int cvout_cert_list_index = cvout_index;
790c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cvout_index++;
791ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  cvout[cvout_index].type = cert_po_trustAnchor;
792ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  cvout[cvout_index].value.pointer.cert = NULL;
793ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int cvout_trust_anchor_index = cvout_index;
794ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  cvout_index++;
795c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cvout[cvout_index].type = cert_po_end;
796c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ScopedCERTValOutParam scoped_cvout(cvout);
797c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
798c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool check_revocation = (flags & VERIFY_REV_CHECKING_ENABLED);
799c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (check_revocation) {
800c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
801c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
802c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // EV requires revocation checking.
803c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    flags &= ~VERIFY_EV_CERT;
804c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
805c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  status = PKIXVerifyCert(cert_handle_, check_revocation, NULL, 0, cvout);
806c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (status != SECSuccess) {
807c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int err = PORT_GetError();
808c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname
809c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott               << " failed err=" << err;
810c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // CERT_PKIXVerifyCert rerports the wrong error code for
811c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // expired certificates (NSS bug 491174)
812c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (err == SEC_ERROR_CERT_NOT_VALID &&
813c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        (verify_result->cert_status & CERT_STATUS_DATE_INVALID) != 0)
814c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      err = SEC_ERROR_EXPIRED_CERTIFICATE;
815c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int cert_status = MapCertErrorToCertStatus(err);
816c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (cert_status) {
817c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      verify_result->cert_status |= cert_status;
818c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return MapCertStatusToNetError(verify_result->cert_status);
819c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
820c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // |err| is not a certificate error.
821c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return MapSecurityError(err);
822c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
823c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
824c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain,
825c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   verify_result);
826c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (IsCertStatusError(verify_result->cert_status))
827c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return MapCertStatusToNetError(verify_result->cert_status);
828c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
829ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain,
830ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        cvout[cvout_trust_anchor_index].value.pointer.cert,
831ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        &verify_result->public_key_hashes);
832ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
833ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  verify_result->is_issued_by_known_root =
834ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert);
835ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
836c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if ((flags & VERIFY_EV_CERT) && VerifyEV())
837c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    verify_result->cert_status |= CERT_STATUS_IS_EV;
83894ea77830f08742eaf1760a8ccc858530cb1c36eKristian Monsen
83994ea77830f08742eaf1760a8ccc858530cb1c36eKristian Monsen  if (IsPublicKeyBlacklisted(verify_result->public_key_hashes)) {
84094ea77830f08742eaf1760a8ccc858530cb1c36eKristian Monsen    verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
84194ea77830f08742eaf1760a8ccc858530cb1c36eKristian Monsen    return MapCertStatusToNetError(verify_result->cert_status);
84294ea77830f08742eaf1760a8ccc858530cb1c36eKristian Monsen  }
84394ea77830f08742eaf1760a8ccc858530cb1c36eKristian Monsen
844c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return OK;
845c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
846c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
847dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool X509Certificate::VerifyNameMatch(const std::string& hostname) const {
848dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return CERT_VerifyCertName(cert_handle_, hostname.c_str()) == SECSuccess;
849dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
850dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
851c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp
852c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// and nsNSSCertHelper.cpp) to learn how to verify EV certificate.
853c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// TODO(wtc): A possible optimization is that we get the trust anchor from
854c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// the first PKIXVerifyCert call.  We look up the EV policy for the trust
855c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// anchor.  If the trust anchor has no EV policy, we know the cert isn't EV.
856c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Otherwise, we pass just that EV policy (as opposed to all the EV policies)
857c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// to the second PKIXVerifyCert call.
858c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool X509Certificate::VerifyEV() const {
859ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
860c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
861c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTValOutParam cvout[3];
862c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int cvout_index = 0;
863c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cvout[cvout_index].type = cert_po_trustAnchor;
864c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cvout[cvout_index].value.pointer.cert = NULL;
865c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int cvout_trust_anchor_index = cvout_index;
866c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cvout_index++;
867c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cvout[cvout_index].type = cert_po_end;
868c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ScopedCERTValOutParam scoped_cvout(cvout);
869c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
870c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECStatus status = PKIXVerifyCert(cert_handle_,
871c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    true,
872c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    metadata->GetPolicyOIDs(),
873c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    metadata->NumPolicyOIDs(),
874c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    cvout);
875c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (status != SECSuccess)
876c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
877c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
878c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERTCertificate* root_ca =
879c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      cvout[cvout_trust_anchor_index].value.pointer.cert;
880c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (root_ca == NULL)
881c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SHA1Fingerprint fingerprint =
883c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      X509Certificate::CalculateFingerprint(root_ca);
884c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECOidTag ev_policy_tag = SEC_OID_UNKNOWN;
885c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!metadata->GetPolicyOID(fingerprint, &ev_policy_tag))
886c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
887c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
888c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!CheckCertPolicies(cert_handle_, ev_policy_tag))
889c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
890c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
891c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
892c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
893c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
89421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool X509Certificate::GetDEREncoded(std::string* encoded) {
89521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!cert_handle_->derCert.len)
89621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
89721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  encoded->clear();
89821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  encoded->append(reinterpret_cast<char*>(cert_handle_->derCert.data),
89921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                  cert_handle_->derCert.len);
90021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return true;
90121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
90221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
903c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
904731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
905731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                   X509Certificate::OSCertHandle b) {
906731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(a && b);
907731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (a == b)
908731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return true;
909731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return a->derCert.len == b->derCert.len &&
910731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      memcmp(a->derCert.data, b->derCert.data, a->derCert.len) == 0;
911731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
912731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
913731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// static
914c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottX509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
915c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const char* data, int length) {
9163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (length < 0)
9173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return NULL;
9183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
919ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  crypto::EnsureNSSInit();
920c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!NSS_IsInitialized())
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SECItem der_cert;
9253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data));
9263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  der_cert.len  = length;
9273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  der_cert.type = siDERCertBuffer;
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Parse into a certificate structure.
9303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, NULL,
9313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                 PR_FALSE, PR_TRUE);
9323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
9333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
9343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static
9353345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickX509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
9363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const char* data, int length, Format format) {
9373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  OSCertHandles results;
9383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (length < 0)
9393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return results;
9403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
941ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  crypto::EnsureNSSInit();
9423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
9433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!NSS_IsInitialized())
9443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return results;
9453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
9463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  switch (format) {
9473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case FORMAT_SINGLE_CERTIFICATE: {
9483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
9493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (handle)
9503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        results.push_back(handle);
9513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
9523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
9533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case FORMAT_PKCS7: {
9543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Make a copy since CERT_DecodeCertPackage may modify it
9553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      std::vector<char> data_copy(data, data + length);
9563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
9573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      SECStatus result = CERT_DecodeCertPackage(&data_copy[0],
9583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          length, CollectCertsCallback, &results);
9593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (result != SECSuccess)
9603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        results.clear();
9613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
9623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
9633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    default:
9643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NOTREACHED() << "Certificate format " << format << " unimplemented";
9653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
9663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
9673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
9683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return results;
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
972c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochX509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OSCertHandle cert_handle) {
974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return CERT_DupCertificate(cert_handle);
975c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
976c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
977c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
978c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
979c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CERT_DestroyCertificate(cert_handle);
980c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
981c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
982c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSHA1Fingerprint X509Certificate::CalculateFingerprint(
984c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    OSCertHandle cert) {
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SHA1Fingerprint sha1;
986c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memset(sha1.data, 0, sizeof(sha1.data));
987c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
988c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(NULL != cert->derCert.data);
989c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(0 != cert->derCert.len);
990c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
991c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data,
992c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                              cert->derCert.data, cert->derCert.len);
993c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(rv == SECSuccess);
994c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
995c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return sha1;
996c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
997c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
998ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static
999ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenX509Certificate::OSCertHandle
1000ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenX509Certificate::ReadCertHandleFromPickle(const Pickle& pickle,
1001ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                          void** pickle_iter) {
1002ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const char* data;
1003ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int length;
1004ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!pickle.ReadData(pickle_iter, &data, &length))
1005ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return NULL;
1006ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1007ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return CreateOSCertHandleFromBytes(data, length);
1008ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
1009ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1010ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static
1011ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool X509Certificate::WriteCertHandleToPickle(OSCertHandle cert_handle,
1012ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              Pickle* pickle) {
1013ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return pickle->WriteData(
1014ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      reinterpret_cast<const char*>(cert_handle->derCert.data),
1015ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      cert_handle->derCert.len);
1016ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
1017ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1018c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
1019