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