mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 23:38:38 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
230
dom/security/ContentVerifier.cpp
Normal file
230
dom/security/ContentVerifier.cpp
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "ContentVerifier.h"
|
||||
|
||||
#include "mozilla/fallible.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIRequest.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStringStream.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static LazyLogModule gContentVerifierPRLog("ContentVerifier");
|
||||
#define CSV_LOG(args) MOZ_LOG(gContentVerifierPRLog, LogLevel::Debug, args)
|
||||
|
||||
NS_IMPL_ISUPPORTS(ContentVerifier,
|
||||
nsIContentSignatureReceiverCallback,
|
||||
nsIStreamListener);
|
||||
|
||||
nsresult
|
||||
ContentVerifier::Init(const nsACString& aContentSignatureHeader,
|
||||
nsIRequest* aRequest, nsISupports* aContext)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (aContentSignatureHeader.IsEmpty()) {
|
||||
CSV_LOG(("Content-Signature header must not be empty!\n"));
|
||||
return NS_ERROR_INVALID_SIGNATURE;
|
||||
}
|
||||
|
||||
// initialise the content signature "service"
|
||||
nsresult rv;
|
||||
mVerifier =
|
||||
do_CreateInstance("@mozilla.org/security/contentsignatureverifier;1", &rv);
|
||||
if (NS_FAILED(rv) || !mVerifier) {
|
||||
return NS_ERROR_INVALID_SIGNATURE;
|
||||
}
|
||||
|
||||
// Keep references to the request and context. We need them in FinishSignature
|
||||
// and the ContextCreated callback.
|
||||
mContentRequest = aRequest;
|
||||
mContentContext = aContext;
|
||||
|
||||
rv = mVerifier->CreateContextWithoutCertChain(
|
||||
this, aContentSignatureHeader,
|
||||
NS_LITERAL_CSTRING("remotenewtab.content-signature.mozilla.org"));
|
||||
if (NS_FAILED(rv)){
|
||||
mVerifier = nullptr;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement nsIStreamListener
|
||||
* We buffer the entire content here and kick off verification
|
||||
*/
|
||||
nsresult
|
||||
AppendNextSegment(nsIInputStream* aInputStream, void* aClosure,
|
||||
const char* aRawSegment, uint32_t aToOffset, uint32_t aCount,
|
||||
uint32_t* outWrittenCount)
|
||||
{
|
||||
FallibleTArray<nsCString>* decodedData =
|
||||
static_cast<FallibleTArray<nsCString>*>(aClosure);
|
||||
nsDependentCSubstring segment(aRawSegment, aCount);
|
||||
if (!decodedData->AppendElement(segment, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
*outWrittenCount = aCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ContentVerifier::FinishSignature()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIStreamListener> nextListener;
|
||||
nextListener.swap(mNextListener);
|
||||
|
||||
// Verify the content:
|
||||
// If this fails, we return an invalid signature error to load a fallback page.
|
||||
// If everthing is good, we return a new stream to the next listener and kick
|
||||
// that one off.
|
||||
bool verified = false;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// If the content signature check fails, stop the load
|
||||
// and return a signature error. NSS resources are freed by the
|
||||
// ContentSignatureVerifier on destruction.
|
||||
if (NS_FAILED(mVerifier->End(&verified)) || !verified) {
|
||||
CSV_LOG(("failed to verify content\n"));
|
||||
(void)nextListener->OnStopRequest(mContentRequest, mContentContext,
|
||||
NS_ERROR_INVALID_SIGNATURE);
|
||||
return;
|
||||
}
|
||||
CSV_LOG(("Successfully verified content signature.\n"));
|
||||
|
||||
// We emptied the input stream so we have to create a new one from mContent
|
||||
// to hand it to the consuming listener.
|
||||
uint64_t offset = 0;
|
||||
for (uint32_t i = 0; i < mContent.Length(); ++i) {
|
||||
nsCOMPtr<nsIInputStream> oInStr;
|
||||
rv = NS_NewCStringInputStream(getter_AddRefs(oInStr), mContent[i]);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
// let the next listener know that there is data in oInStr
|
||||
rv = nextListener->OnDataAvailable(mContentRequest, mContentContext, oInStr,
|
||||
offset, mContent[i].Length());
|
||||
offset += mContent[i].Length();
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// propagate OnStopRequest and return
|
||||
nextListener->OnStopRequest(mContentRequest, mContentContext, rv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentVerifier::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||
{
|
||||
MOZ_CRASH("This OnStartRequest should've never been called!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentVerifier::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
|
||||
nsresult aStatus)
|
||||
{
|
||||
// If we don't have a next listener, we handed off this request already.
|
||||
// Return, there's nothing to do here.
|
||||
if (!mNextListener) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_FAILED(aStatus)) {
|
||||
CSV_LOG(("Stream failed\n"));
|
||||
nsCOMPtr<nsIStreamListener> nextListener;
|
||||
nextListener.swap(mNextListener);
|
||||
return nextListener->OnStopRequest(aRequest, aContext, aStatus);
|
||||
}
|
||||
|
||||
mContentRead = true;
|
||||
|
||||
// If the ContentSignatureVerifier is initialised, finish the verification.
|
||||
if (mContextCreated) {
|
||||
FinishSignature();
|
||||
return aStatus;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentVerifier::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
|
||||
nsIInputStream* aInputStream, uint64_t aOffset,
|
||||
uint32_t aCount)
|
||||
{
|
||||
// buffer the entire stream
|
||||
uint32_t read;
|
||||
nsresult rv = aInputStream->ReadSegments(AppendNextSegment, &mContent, aCount,
|
||||
&read);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Update the signature verifier if the context has been created.
|
||||
if (mContextCreated) {
|
||||
return mVerifier->Update(mContent.LastElement());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentVerifier::ContextCreated(bool successful)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!successful) {
|
||||
// If we don't have a next listener, the request has been handed off already.
|
||||
if (!mNextListener) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Get local reference to mNextListener and null it to ensure that we don't
|
||||
// call it twice.
|
||||
nsCOMPtr<nsIStreamListener> nextListener;
|
||||
nextListener.swap(mNextListener);
|
||||
|
||||
// Make sure that OnStartRequest was called and we have a request.
|
||||
MOZ_ASSERT(mContentRequest);
|
||||
|
||||
// In this case something went wrong with the cert. Let's stop this load.
|
||||
CSV_LOG(("failed to get a valid cert chain\n"));
|
||||
if (mContentRequest && nextListener) {
|
||||
mContentRequest->Cancel(NS_ERROR_INVALID_SIGNATURE);
|
||||
nsresult rv = nextListener->OnStopRequest(mContentRequest, mContentContext,
|
||||
NS_ERROR_INVALID_SIGNATURE);
|
||||
mContentRequest = nullptr;
|
||||
mContentContext = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We should never get here!
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"ContentVerifier was used without getting OnStartRequest!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// In this case the content verifier is initialised and we have to feed it
|
||||
// the buffered content.
|
||||
mContextCreated = true;
|
||||
for (size_t i = 0; i < mContent.Length(); ++i) {
|
||||
if (NS_FAILED(mVerifier->Update(mContent[i]))) {
|
||||
// Bail out if this fails. We can't return an error here, but if this
|
||||
// failed, NS_ERROR_INVALID_SIGNATURE is returned in FinishSignature.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We read all content, let's verify the signature.
|
||||
if (mContentRead) {
|
||||
FinishSignature();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue