1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h"
6
7#include "net/cert/test_root_certs.h"
8#include "net/cert/x509_certificate.h"
9
10// NSS doesn't currently define CERT_LIST_TAIL.
11// See https://bugzilla.mozilla.org/show_bug.cgi?id=962413
12// Can be removed once chrome requires NSS version 3.16 to build.
13#ifndef CERT_LIST_TAIL
14#define CERT_LIST_TAIL(l) ((CERTCertListNode *)PR_LIST_TAIL(&l->list))
15#endif
16
17namespace chromeos {
18
19namespace {
20
21struct ChainVerifyArgs {
22  CertVerifyProcChromeOS* cert_verify_proc;
23  const net::CertificateList& additional_trust_anchors;
24};
25
26}  // namespace
27
28CertVerifyProcChromeOS::CertVerifyProcChromeOS() {}
29
30CertVerifyProcChromeOS::CertVerifyProcChromeOS(
31    crypto::ScopedPK11Slot public_slot) {
32  // Only the software slot is passed, since that is the only one where user
33  // trust settings are stored.
34  profile_filter_.Init(
35      public_slot.Pass(), crypto::ScopedPK11Slot(), crypto::ScopedPK11Slot());
36}
37
38CertVerifyProcChromeOS::~CertVerifyProcChromeOS() {}
39
40int CertVerifyProcChromeOS::VerifyInternal(
41    net::X509Certificate* cert,
42    const std::string& hostname,
43    int flags,
44    net::CRLSet* crl_set,
45    const net::CertificateList& additional_trust_anchors,
46    net::CertVerifyResult* verify_result) {
47  ChainVerifyArgs chain_verify_args = {this, additional_trust_anchors};
48
49  CERTChainVerifyCallback chain_verify_callback;
50  chain_verify_callback.isChainValid =
51      &CertVerifyProcChromeOS::IsChainValidFunc;
52  chain_verify_callback.isChainValidArg =
53      static_cast<void*>(&chain_verify_args);
54
55  return VerifyInternalImpl(cert,
56                            hostname,
57                            flags,
58                            crl_set,
59                            additional_trust_anchors,
60                            &chain_verify_callback,
61                            verify_result);
62}
63
64// static
65SECStatus CertVerifyProcChromeOS::IsChainValidFunc(
66    void* is_chain_valid_arg,
67    const CERTCertList* current_chain,
68    PRBool* chain_ok) {
69  ChainVerifyArgs* args = static_cast<ChainVerifyArgs*>(is_chain_valid_arg);
70  CERTCertificate* cert = CERT_LIST_TAIL(current_chain)->cert;
71
72  if (net::TestRootCerts::HasInstance()) {
73    if (net::TestRootCerts::GetInstance()->Contains(cert)) {
74      // Certs in the TestRootCerts are not stored in any slot, and thus would
75      // not be allowed by the profile_filter. This should only be hit in tests.
76      DVLOG(3) << cert->subjectName << " is a TestRootCert";
77      *chain_ok = PR_TRUE;
78      return SECSuccess;
79    }
80  }
81
82  for (net::CertificateList::const_iterator i =
83           args->additional_trust_anchors.begin();
84       i != args->additional_trust_anchors.end();
85       ++i) {
86    if (net::X509Certificate::IsSameOSCert(cert, (*i)->os_cert_handle())) {
87      // Certs in the additional_trust_anchors should always be allowed, even if
88      // they aren't stored in a slot that would be allowed by the
89      // profile_filter.
90      DVLOG(3) << cert->subjectName << " is an additional_trust_anchor";
91      *chain_ok = PR_TRUE;
92      return SECSuccess;
93    }
94  }
95
96  // TODO(mattm): If crbug.com/334384 is fixed to allow setting trust
97  // properly when the same cert is in multiple slots, this would also need
98  // updating to check the per-slot trust values.
99  *chain_ok = args->cert_verify_proc->profile_filter_.IsCertAllowed(cert)
100                  ? PR_TRUE
101                  : PR_FALSE;
102  DVLOG(3) << cert->subjectName << " is " << (*chain_ok ? "ok" : "not ok");
103  return SECSuccess;
104}
105
106}  // namespace chromeos
107