Index: net/cert/internal/trust_store_nss.cc |
diff --git a/net/cert/internal/trust_store_nss.cc b/net/cert/internal/trust_store_nss.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6bfed35708ae7c3625509cec774ab7ddbf9faa8c |
--- /dev/null |
+++ b/net/cert/internal/trust_store_nss.cc |
@@ -0,0 +1,203 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/cert/internal/trust_store_nss.h" |
+ |
+#include <cert.h> |
+#include <certdb.h> |
+ |
+#include "base/callback_helpers.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/memory/weak_ptr.h" |
+#include "base/task_runner.h" |
+#include "base/task_runner_util.h" |
+#include "crypto/nss_util.h" |
+#include "net/cert/internal/parsed_certificate.h" |
+#include "net/cert/scoped_nss_types.h" |
+ |
+// XXX structure so that supporting chromeos stuff is doable ( |
+// TrustStoreChromeOS which uses net::NSSProfileFilterChromeOS.. similar to |
+// CertVerifyProcChromeOS ) |
+ |
+namespace net { |
+ |
+namespace { |
+ |
+bool CheckTrust(scoped_refptr<ParsedCertificate> cert) { |
+ SECItem der_cert; |
+ der_cert.data = const_cast<uint8_t*>(cert->der_cert().UnsafeData()); |
+ der_cert.len = base::checked_cast<unsigned>(cert->der_cert().Length()); |
+ der_cert.type = siDERCertBuffer; |
+ |
+ // XXX Is this an acceptable way to get the cert for checking trust? Should it |
+ // use CERT_NewTempCertificate instead? Or is there a way to get a trust value |
+ // directly without going through CERT_GetCertTrust? |
+ ScopedCERTCertificate nss_cert( |
+ CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), &der_cert)); |
+ if (!nss_cert) |
+ return false; |
+ |
+ CERTCertTrust trust; |
+ if (CERT_GetCertTrust(nss_cert.get(), &trust) != SECSuccess) |
+ return false; |
+ |
+ // TODO(mattm): handle explicit distrust (blacklisting)? |
+ const int ca_trust = CERTDB_TRUSTED_CA; |
+ return (trust.sslFlags & ca_trust) == ca_trust; |
+} |
+ |
+class CheckTrustRequest : public TrustStore::Request { |
+ public: |
+ explicit CheckTrustRequest(const TrustStore::TrustCallback& callback); |
+ // Destruction of the Request cancels it. CheckTrust will still run, but the |
+ // callback will not be called since the WeakPtr will be invalidated. |
+ ~CheckTrustRequest() override = default; |
+ |
+ void Start(scoped_refptr<ParsedCertificate> cert, |
+ base::TaskRunner* task_runner); |
+ |
+ private: |
+ void HandleCheckTrust(bool trusted); |
+ |
+ scoped_refptr<ParsedCertificate> cert_; |
+ TrustStore::TrustCallback callback_; |
+ base::WeakPtrFactory<CheckTrustRequest> weak_ptr_factory_; |
+}; |
+ |
+CheckTrustRequest::CheckTrustRequest(const TrustStore::TrustCallback& callback) |
+ : callback_(callback), weak_ptr_factory_(this) {} |
+ |
+void CheckTrustRequest::Start(scoped_refptr<ParsedCertificate> cert, |
+ base::TaskRunner* task_runner) { |
+ base::PostTaskAndReplyWithResult( |
+ task_runner, FROM_HERE, base::Bind(&CheckTrust, cert), |
+ base::Bind(&CheckTrustRequest::HandleCheckTrust, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void CheckTrustRequest::HandleCheckTrust(bool trusted) { |
+ base::ResetAndReturn(&callback_).Run(trusted); |
+ // |this| may be deleted here. |
+} |
+ |
+std::unique_ptr<ParsedCertificateList> GetIssuers( |
+ scoped_refptr<ParsedCertificate> cert) { |
+ std::unique_ptr<ParsedCertificateList> result(new ParsedCertificateList); |
+ SECItem name; |
+ name.len = cert->tbs().issuer_tlv.Length(); |
+ name.data = const_cast<uint8_t*>(cert->tbs().issuer_tlv.UnsafeData()); |
+ //name.len = cert->normalized_issuer().Length(); |
+ //name.data = const_cast<uint8_t*>(cert->normalized_issuer().UnsafeData()); |
+ // XXX NSS doesn't seem to do normalization here ... |
+ CERTCertList* found_certs = CERT_CreateSubjectCertList( |
+ nullptr, CERT_GetDefaultCertDB(), &name, PR_Now() /* sorttime */, |
+ PR_FALSE /* validOnly */); |
+ if (!found_certs) { |
+ return result; |
+ } |
+ |
+ for (CERTCertListNode* node = CERT_LIST_HEAD(found_certs); |
+ !CERT_LIST_END(node, found_certs); node = CERT_LIST_NEXT(node)) { |
+ if (!ParsedCertificate::CreateAndAddToVector( |
+ node->cert->derCert.data, node->cert->derCert.len, |
+ ParsedCertificate::DataSource::INTERNAL_COPY, {}, result.get())) { |
+ // TODO(mattm): return errors better. |
+ LOG(ERROR) << "error parsing issuer certificate"; |
+ } |
+ // TODO(mattm): check trust of cert here, cache it in the TrustStoreNSS so |
+ // that IsTrustedCertificate can be synchronous. (Assuming cache only |
+ // applies to one verification.) |
+ } |
+ CERT_DestroyCertList(found_certs); |
+ return result; |
+} |
+ |
+class GetIssuersRequest : public CertIssuerSource::Request { |
+ public: |
+ explicit GetIssuersRequest(const CertIssuerSource::IssuerCallback& callback); |
+ // Destruction of the Request cancels it. CheckTrust will still run, but the |
+ // callback will not be called since the WeakPtr will be invalidated. |
+ ~GetIssuersRequest() override = default; |
+ |
+ void Start(scoped_refptr<ParsedCertificate> cert, |
+ base::TaskRunner* task_runner); |
+ |
+ // CertIssuerSource::Request implementation: |
+ CompletionStatus GetNext(scoped_refptr<ParsedCertificate>* out_cert) override; |
+ |
+ private: |
+ void HandleGetIssuers(std::unique_ptr<ParsedCertificateList> issuers_list); |
+ |
+ scoped_refptr<ParsedCertificate> cert_; |
+ std::unique_ptr<ParsedCertificateList> issuers_; |
+ size_t current_result_ = 0; |
+ CertIssuerSource::IssuerCallback callback_; |
+ base::WeakPtrFactory<GetIssuersRequest> weak_ptr_factory_; |
+}; |
+ |
+GetIssuersRequest::GetIssuersRequest( |
+ const CertIssuerSource::IssuerCallback& callback) |
+ : callback_(callback), weak_ptr_factory_(this) {} |
+ |
+void GetIssuersRequest::Start(scoped_refptr<ParsedCertificate> cert, |
+ base::TaskRunner* task_runner) { |
+ base::PostTaskAndReplyWithResult( |
+ task_runner, FROM_HERE, base::Bind(&GetIssuers, cert), |
+ base::Bind(&GetIssuersRequest::HandleGetIssuers, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+CompletionStatus GetIssuersRequest::GetNext( |
+ scoped_refptr<ParsedCertificate>* out_cert) { |
+ DCHECK(issuers_); |
+ if (current_result_ < issuers_->size()) |
+ *out_cert = std::move((*issuers_)[current_result_++]); |
+ else |
+ *out_cert = nullptr; |
+ return CompletionStatus::SYNC; |
+} |
+ |
+void GetIssuersRequest::HandleGetIssuers( |
+ std::unique_ptr<ParsedCertificateList> issuers_list) { |
+ issuers_ = std::move(issuers_list); |
+ base::ResetAndReturn(&callback_).Run(this); |
+ // |this| may be deleted here. |
+} |
+ |
+} // namespace |
+ |
+TrustStoreNSS::TrustStoreNSS(scoped_refptr<base::TaskRunner> nss_task_runner) |
+ : nss_task_runner_(std::move(nss_task_runner)) { |
+ crypto::EnsureNSSInit(); |
+} |
+ |
+TrustStoreNSS::~TrustStoreNSS() = default; |
+ |
+void TrustStoreNSS::IsTrustedCertificate( |
+ scoped_refptr<ParsedCertificate> cert, |
+ const TrustCallback& callback, |
+ bool* out_trusted, |
+ std::unique_ptr<TrustStore::Request>* out_req) const { |
+ std::unique_ptr<CheckTrustRequest> req; |
+ req = base::WrapUnique(new CheckTrustRequest(callback)); |
+ req->Start(std::move(cert), nss_task_runner_.get()); |
+ *out_req = std::move(req); |
+} |
+ |
+void TrustStoreNSS::SyncGetIssuersOf(const ParsedCertificate* cert, |
+ ParsedCertificateList* issuers) { |
+ // TrustStoreNSS never returns synchronous issuer results. |
+} |
+ |
+void TrustStoreNSS::AsyncGetIssuersOf( |
+ scoped_refptr<ParsedCertificate> cert, |
+ const IssuerCallback& callback, |
+ std::unique_ptr<CertIssuerSource::Request>* out_req) { |
+ std::unique_ptr<GetIssuersRequest> req; |
+ req = base::WrapUnique(new GetIssuersRequest(callback)); |
+ req->Start(std::move(cert), nss_task_runner_.get()); |
+ *out_req = std::move(req); |
+} |
+ |
+} // namespace net |