summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/PSMContentListener.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /security/manager/ssl/PSMContentListener.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'security/manager/ssl/PSMContentListener.cpp')
-rw-r--r--security/manager/ssl/PSMContentListener.cpp454
1 files changed, 454 insertions, 0 deletions
diff --git a/security/manager/ssl/PSMContentListener.cpp b/security/manager/ssl/PSMContentListener.cpp
new file mode 100644
index 000000000..688e2c18c
--- /dev/null
+++ b/security/manager/ssl/PSMContentListener.cpp
@@ -0,0 +1,454 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set sw=2 sts=2 ts=2 et tw=80:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "PSMContentListener.h"
+
+#include "nsIDivertableChannel.h"
+#include "nsIStreamListener.h"
+#include "nsIX509CertDB.h"
+#include "nsIXULAppInfo.h"
+
+#include "mozilla/Casting.h"
+#include "mozilla/Services.h"
+#include "mozilla/Unused.h"
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/net/ChannelDiverterParent.h"
+#include "mozilla/net/ChannelDiverterChild.h"
+
+#include "nsCRT.h"
+#include "nsNetUtil.h"
+#include "nsIChannel.h"
+#include "nsIInputStream.h"
+#include "nsIURI.h"
+#include "nsNSSHelper.h"
+
+#include "mozilla/Logging.h"
+
+extern mozilla::LazyLogModule gPIPNSSLog;
+
+namespace mozilla { namespace psm {
+
+namespace {
+
+const int32_t kDefaultCertAllocLength = 2048;
+
+enum {
+ UNKNOWN_TYPE = 0,
+ X509_CA_CERT = 1,
+ X509_USER_CERT = 2,
+ X509_EMAIL_CERT = 3,
+ X509_SERVER_CERT = 4
+};
+
+/* other mime types that we should handle sometime:
+
+ application/x-pkcs7-mime
+ application/pkcs7-signature
+ application/pre-encrypted
+
+*/
+
+uint32_t
+getPSMContentType(const char* aContentType)
+{
+ // Don't forget to update the registration of content listeners in nsNSSModule.cpp
+ // for every supported content type.
+
+ if (!nsCRT::strcasecmp(aContentType, "application/x-x509-ca-cert"))
+ return X509_CA_CERT;
+ if (!nsCRT::strcasecmp(aContentType, "application/x-x509-server-cert"))
+ return X509_SERVER_CERT;
+ if (!nsCRT::strcasecmp(aContentType, "application/x-x509-user-cert"))
+ return X509_USER_CERT;
+ if (!nsCRT::strcasecmp(aContentType, "application/x-x509-email-cert"))
+ return X509_EMAIL_CERT;
+
+ return UNKNOWN_TYPE;
+}
+
+int64_t
+ComputeContentLength(nsIRequest* request)
+{
+ nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
+ if (!channel) {
+ return -1;
+ }
+
+ int64_t contentLength;
+ nsresult rv = channel->GetContentLength(&contentLength);
+ if (NS_FAILED(rv) || contentLength <= 0) {
+ return kDefaultCertAllocLength;
+ }
+
+ if (contentLength > INT32_MAX) {
+ return -1;
+ }
+
+ return contentLength;
+}
+
+} // unnamed namespace
+
+/* ------------------------
+ * PSMContentStreamListener
+ * ------------------------ */
+
+PSMContentStreamListener::PSMContentStreamListener(uint32_t type)
+ : mType(type)
+{
+}
+
+PSMContentStreamListener::~PSMContentStreamListener()
+{
+}
+
+NS_IMPL_ISUPPORTS(PSMContentStreamListener, nsIStreamListener, nsIRequestObserver)
+
+NS_IMETHODIMP
+PSMContentStreamListener::OnStartRequest(nsIRequest* request, nsISupports* context)
+{
+ MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CertDownloader::OnStartRequest\n"));
+
+ int64_t contentLength = ComputeContentLength(request);
+ if (contentLength < 0) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mByteData.SetCapacity(contentLength);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+PSMContentStreamListener::OnDataAvailable(nsIRequest* request,
+ nsISupports* context,
+ nsIInputStream* aIStream,
+ uint64_t aSourceOffset,
+ uint32_t aLength)
+{
+ MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CertDownloader::OnDataAvailable\n"));
+
+ nsCString chunk;
+ nsresult rv = NS_ReadInputStreamToString(aIStream, chunk, aLength);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ mByteData.Append(chunk);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+PSMContentStreamListener::OnStopRequest(nsIRequest* request,
+ nsISupports* context,
+ nsresult aStatus)
+{
+ MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CertDownloader::OnStopRequest\n"));
+
+ // Because importing the cert can spin the event loop (via alerts), we can't
+ // do it here. Do it off the event loop instead.
+ nsCOMPtr<nsIRunnable> r =
+ NewRunnableMethod(this, &PSMContentStreamListener::ImportCertificate);
+ MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
+
+ return NS_OK;
+}
+
+void
+PSMContentStreamListener::ImportCertificate()
+{
+ nsCOMPtr<nsIX509CertDB> certdb;
+
+ nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
+
+ switch (mType) {
+ case X509_CA_CERT:
+ case X509_USER_CERT:
+ case X509_EMAIL_CERT:
+ certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
+ break;
+
+ default:
+ break;
+ }
+
+ if (!certdb) {
+ return;
+ }
+
+ switch (mType) {
+ case X509_CA_CERT:
+ certdb->ImportCertificates(BitwiseCast<uint8_t*, char*>(
+ mByteData.BeginWriting()),
+ mByteData.Length(), mType, ctx);
+ break;
+
+ case X509_USER_CERT:
+ certdb->ImportUserCertificate(BitwiseCast<uint8_t*, char*>(
+ mByteData.BeginWriting()),
+ mByteData.Length(), ctx);
+ break;
+
+ case X509_EMAIL_CERT:
+ certdb->ImportEmailCertificate(BitwiseCast<uint8_t*, char*>(
+ mByteData.BeginWriting()),
+ mByteData.Length(), ctx);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* ------------------------
+ * PSMContentDownloaderParent
+ * ------------------------ */
+
+PSMContentDownloaderParent::PSMContentDownloaderParent(uint32_t type)
+ : PSMContentStreamListener(type)
+ , mIPCOpen(true)
+{
+}
+
+PSMContentDownloaderParent::~PSMContentDownloaderParent()
+{
+}
+
+bool
+PSMContentDownloaderParent::RecvOnStartRequest(const uint32_t& contentLength)
+{
+ mByteData.SetCapacity(contentLength);
+ return true;
+}
+
+bool
+PSMContentDownloaderParent::RecvOnDataAvailable(const nsCString& data,
+ const uint64_t& offset,
+ const uint32_t& count)
+{
+ mByteData.Append(data);
+ return true;
+}
+
+bool
+PSMContentDownloaderParent::RecvOnStopRequest(const nsresult& code)
+{
+ if (NS_SUCCEEDED(code)) {
+ // See also PSMContentStreamListener::OnStopRequest. In this case, we don't
+ // have to dispatch ImportCertificate off of an event because we don't have
+ // to worry about Necko sending "clean up" events and destroying us if
+ // ImportCertificate spins the event loop.
+ ImportCertificate();
+ }
+
+ if (mIPCOpen) {
+ mozilla::Unused << Send__delete__(this);
+ }
+ return true;
+}
+
+NS_IMETHODIMP
+PSMContentDownloaderParent::OnStopRequest(nsIRequest* request, nsISupports* context, nsresult code)
+{
+ nsresult rv = PSMContentStreamListener::OnStopRequest(request, context, code);
+
+ if (mIPCOpen) {
+ mozilla::Unused << Send__delete__(this);
+ }
+ return rv;
+}
+
+bool
+PSMContentDownloaderParent::RecvDivertToParentUsing(mozilla::net::PChannelDiverterParent* diverter)
+{
+ MOZ_ASSERT(diverter);
+ auto p = static_cast<mozilla::net::ChannelDiverterParent*>(diverter);
+ p->DivertTo(this);
+ mozilla::Unused << p->Send__delete__(p);
+ return true;
+}
+
+void
+PSMContentDownloaderParent::ActorDestroy(ActorDestroyReason why)
+{
+ mIPCOpen = false;
+}
+
+/* ------------------------
+ * PSMContentDownloaderChild
+ * ------------------------ */
+
+NS_IMPL_ISUPPORTS(PSMContentDownloaderChild, nsIStreamListener)
+
+PSMContentDownloaderChild::PSMContentDownloaderChild()
+{
+}
+
+PSMContentDownloaderChild::~PSMContentDownloaderChild()
+{
+}
+
+NS_IMETHODIMP
+PSMContentDownloaderChild::OnStartRequest(nsIRequest* request, nsISupports* context)
+{
+ nsCOMPtr<nsIDivertableChannel> divertable = do_QueryInterface(request);
+ if (divertable) {
+ mozilla::net::ChannelDiverterChild* diverter = nullptr;
+ nsresult rv = divertable->DivertToParent(&diverter);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ MOZ_ASSERT(diverter);
+
+ return SendDivertToParentUsing(diverter) ? NS_OK : NS_ERROR_FAILURE;
+ }
+
+ int64_t contentLength = ComputeContentLength(request);
+ if (contentLength < 0) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mozilla::Unused << SendOnStartRequest(contentLength);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+PSMContentDownloaderChild::OnDataAvailable(nsIRequest* request,
+ nsISupports* context,
+ nsIInputStream* aIStream,
+ uint64_t aSourceOffset,
+ uint32_t aLength)
+{
+ nsCString chunk;
+ nsresult rv = NS_ReadInputStreamToString(aIStream, chunk, aLength);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ mozilla::Unused << SendOnDataAvailable(chunk, aSourceOffset, aLength);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+PSMContentDownloaderChild::OnStopRequest(nsIRequest* request,
+ nsISupports* context,
+ nsresult aStatus)
+{
+ mozilla::Unused << SendOnStopRequest(aStatus);
+ return NS_OK;
+}
+
+/* ------------------------
+ * PSMContentListener
+ * ------------------------ */
+
+NS_IMPL_ISUPPORTS(PSMContentListener,
+ nsIURIContentListener,
+ nsISupportsWeakReference)
+
+PSMContentListener::PSMContentListener()
+{
+ mLoadCookie = nullptr;
+ mParentContentListener = nullptr;
+}
+
+PSMContentListener::~PSMContentListener()
+{
+}
+
+nsresult
+PSMContentListener::init()
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+PSMContentListener::OnStartURIOpen(nsIURI* aURI, bool* aAbortOpen)
+{
+ //if we don't want to handle the URI, return true in
+ //*aAbortOpen
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+PSMContentListener::IsPreferred(const char* aContentType,
+ char** aDesiredContentType,
+ bool* aCanHandleContent)
+{
+ return CanHandleContent(aContentType, true,
+ aDesiredContentType, aCanHandleContent);
+}
+
+NS_IMETHODIMP
+PSMContentListener::CanHandleContent(const char* aContentType,
+ bool aIsContentPreferred,
+ char** aDesiredContentType,
+ bool* aCanHandleContent)
+{
+ uint32_t type = getPSMContentType(aContentType);
+ *aCanHandleContent = (type != UNKNOWN_TYPE);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+PSMContentListener::DoContent(const nsACString& aContentType,
+ bool aIsContentPreferred,
+ nsIRequest* aRequest,
+ nsIStreamListener** aContentHandler,
+ bool* aAbortProcess)
+{
+ uint32_t type;
+ type = getPSMContentType(PromiseFlatCString(aContentType).get());
+ if (gPIPNSSLog) {
+ MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("PSMContentListener::DoContent\n"));
+ }
+ if (type != UNKNOWN_TYPE) {
+ nsCOMPtr<nsIStreamListener> downloader;
+ if (XRE_IsParentProcess()) {
+ downloader = new PSMContentStreamListener(type);
+ } else {
+ downloader = static_cast<PSMContentDownloaderChild*>(
+ dom::ContentChild::GetSingleton()->SendPPSMContentDownloaderConstructor(type));
+ }
+
+ downloader.forget(aContentHandler);
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+PSMContentListener::GetLoadCookie(nsISupports** aLoadCookie)
+{
+ nsCOMPtr<nsISupports> loadCookie(mLoadCookie);
+ loadCookie.forget(aLoadCookie);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+PSMContentListener::SetLoadCookie(nsISupports* aLoadCookie)
+{
+ mLoadCookie = aLoadCookie;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+PSMContentListener::GetParentContentListener(nsIURIContentListener** aContentListener)
+{
+ nsCOMPtr<nsIURIContentListener> listener(mParentContentListener);
+ listener.forget(aContentListener);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+PSMContentListener::SetParentContentListener(nsIURIContentListener* aContentListener)
+{
+ mParentContentListener = aContentListener;
+ return NS_OK;
+}
+
+} } // namespace mozilla::psm