blob: a46d6c9aaf010ce918f003275bbb202b280b3799 [file] [log] [blame]
Andrew Top0d1858f2019-05-15 22:01:47 -07001// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/cert/internal/trust_store_nss.h"
6
7#include <cert.h>
8#include <certdb.h>
9
10#include "crypto/nss_util.h"
11#include "net/cert/internal/cert_errors.h"
12#include "net/cert/internal/parsed_certificate.h"
13#include "net/cert/scoped_nss_types.h"
14#include "net/cert/x509_util.h"
15#include "net/cert/x509_util_nss.h"
16#include "starboard/types.h"
17
18// TODO(mattm): structure so that supporting ChromeOS multi-profile stuff is
19// doable (Have a TrustStoreChromeOS which uses net::NSSProfileFilterChromeOS,
20// similar to CertVerifyProcChromeOS.)
21
22namespace net {
23
24TrustStoreNSS::TrustStoreNSS(SECTrustType trust_type)
25 : trust_type_(trust_type) {}
26
27TrustStoreNSS::~TrustStoreNSS() = default;
28
29void TrustStoreNSS::SyncGetIssuersOf(const ParsedCertificate* cert,
30 ParsedCertificateList* issuers) {
31 crypto::EnsureNSSInit();
32
33 SECItem name;
34 // Use the original issuer value instead of the normalized version. NSS does a
35 // less extensive normalization in its Name comparisons, so our normalized
36 // version may not match the unnormalized version.
37 name.len = cert->tbs().issuer_tlv.Length();
38 name.data = const_cast<uint8_t*>(cert->tbs().issuer_tlv.UnsafeData());
39 // |validOnly| in CERT_CreateSubjectCertList controls whether to return only
40 // certs that are valid at |sorttime|. Expiration isn't meaningful for trust
41 // anchors, so request all the matches.
42 CERTCertList* found_certs = CERT_CreateSubjectCertList(
43 nullptr /* certList */, CERT_GetDefaultCertDB(), &name,
44 PR_Now() /* sorttime */, PR_FALSE /* validOnly */);
45 if (!found_certs)
46 return;
47
48 for (CERTCertListNode* node = CERT_LIST_HEAD(found_certs);
49 !CERT_LIST_END(node, found_certs); node = CERT_LIST_NEXT(node)) {
50 CertErrors parse_errors;
51 scoped_refptr<ParsedCertificate> cur_cert = ParsedCertificate::Create(
52 x509_util::CreateCryptoBuffer(node->cert->derCert.data,
53 node->cert->derCert.len),
54 {}, &parse_errors);
55
56 if (!cur_cert) {
57 // TODO(crbug.com/634443): return errors better.
58 LOG(ERROR) << "Error parsing issuer certificate:\n"
59 << parse_errors.ToDebugString();
60 continue;
61 }
62
63 issuers->push_back(std::move(cur_cert));
64 }
65 CERT_DestroyCertList(found_certs);
66}
67
68void TrustStoreNSS::GetTrust(const scoped_refptr<ParsedCertificate>& cert,
69 CertificateTrust* out_trust) const {
70 crypto::EnsureNSSInit();
71
72 // TODO(eroman): Inefficient -- path building will convert between
73 // CERTCertificate and ParsedCertificate representations multiple times
74 // (when getting the issuers, and again here).
75
76 // Note that trust records in NSS are keyed on issuer + serial, and there
77 // exist builtin distrust records for which a matching certificate is not
78 // included in the builtin cert list. Therefore, create a temp NSS cert even
79 // if no existing cert matches. (Eg, this uses CERT_NewTempCertificate, not
80 // CERT_FindCertByDERCert.)
81 ScopedCERTCertificate nss_cert(x509_util::CreateCERTCertificateFromBytes(
82 cert->der_cert().UnsafeData(), cert->der_cert().Length()));
83 if (!nss_cert) {
84 *out_trust = CertificateTrust::ForUnspecified();
85 return;
86 }
87
88 // Determine the trustedness of the matched certificate.
89 CERTCertTrust trust;
90 if (CERT_GetCertTrust(nss_cert.get(), &trust) != SECSuccess) {
91 *out_trust = CertificateTrust::ForUnspecified();
92 return;
93 }
94
95 int trust_flags = SEC_GET_TRUST_FLAGS(&trust, trust_type_);
96
97 // Determine if the certificate is distrusted.
98 if ((trust_flags & (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED_CA |
99 CERTDB_TRUSTED)) == CERTDB_TERMINAL_RECORD) {
100 *out_trust = CertificateTrust::ForDistrusted();
101 return;
102 }
103
104 // Determine if the certificate is a trust anchor.
105 if ((trust_flags & CERTDB_TRUSTED_CA) == CERTDB_TRUSTED_CA) {
106 *out_trust = CertificateTrust::ForTrustAnchor();
107 return;
108 }
109
110 // Trusted server certs (CERTDB_TERMINAL_RECORD + CERTDB_TRUSTED) are
111 // intentionally treated as unspecified. See https://crbug.com/814994.
112
113 *out_trust = CertificateTrust::ForUnspecified();
114 return;
115}
116
117} // namespace net