Bug 1634436 - Make DecryptingInputStream implement nsIIPCSerializableInputStream. r=baku

Differential Revision: https://phabricator.services.mozilla.com/D75913
This commit is contained in:
Simon Giesecke 2020-06-25 13:23:06 +00:00
parent ea360db963
commit 43fe271d3f
7 changed files with 168 additions and 15 deletions

View File

@ -17,12 +17,22 @@ NS_INTERFACE_MAP_BEGIN(DecryptingInputStreamBase)
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
mBaseCloneableInputStream || !mBaseStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(
nsIIPCSerializableInputStream,
mBaseIPCSerializableInputStream || !mBaseStream)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
NS_INTERFACE_MAP_END
DecryptingInputStreamBase::DecryptingInputStreamBase(
MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream, size_t aBlockSize)
: mBaseStream(std::move(aBaseStream)), mBlockSize(aBlockSize) {
MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream, size_t aBlockSize) {
Init(std::move(aBaseStream), aBlockSize);
}
void DecryptingInputStreamBase::Init(
MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream, size_t aBlockSize) {
mBlockSize.init(aBlockSize);
mBaseStream.init(std::move(aBaseStream));
const nsCOMPtr<nsISeekableStream> seekableStream =
do_QueryInterface(mBaseStream->get());
MOZ_ASSERT(seekableStream &&
@ -35,6 +45,14 @@ DecryptingInputStreamBase::DecryptingInputStreamBase(
SameCOMIdentity(mBaseStream->get(), cloneableInputStream)) {
mBaseCloneableInputStream.init(WrapNotNullUnchecked(cloneableInputStream));
}
const nsCOMPtr<nsIIPCSerializableInputStream> ipcSerializeInputStream =
do_QueryInterface(mBaseStream->get());
if (ipcSerializeInputStream &&
SameCOMIdentity(mBaseStream->get(), ipcSerializeInputStream)) {
mBaseIPCSerializableInputStream.init(
WrapNotNullUnchecked(ipcSerializeInputStream));
}
}
NS_IMETHODIMP DecryptingInputStreamBase::Read(char* aBuf, uint32_t aCount,
@ -58,13 +76,21 @@ NS_IMETHODIMP DecryptingInputStreamBase::GetCloneable(bool* aCloneable) {
return NS_OK;
}
void DecryptingInputStreamBase::Serialize(
mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed,
mozilla::ipc::ChildToParentStreamActorManager* aManager) {
MOZ_CRASH("Not implemented");
}
size_t DecryptingInputStreamBase::PlainLength() const {
MOZ_ASSERT(mNextByte <= mPlainBytes);
return mPlainBytes - mNextByte;
}
size_t DecryptingInputStreamBase::EncryptedBufferLength() const {
return mBlockSize;
return *mBlockSize;
}
} // namespace mozilla::dom::quota

View File

@ -11,6 +11,7 @@
#include "nsCOMPtr.h"
#include "nsICloneableInputStream.h"
#include "nsIInputStream.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsISeekableStream.h"
#include "EncryptedBlock.h"
@ -19,7 +20,8 @@ namespace mozilla::dom::quota {
class DecryptingInputStreamBase : public nsIInputStream,
public nsISeekableStream,
public nsICloneableInputStream {
public nsICloneableInputStream,
public nsIIPCSerializableInputStream {
public:
NS_DECL_THREADSAFE_ISUPPORTS
@ -31,22 +33,37 @@ class DecryptingInputStreamBase : public nsIInputStream,
using nsICloneableInputStream::GetCloneable;
NS_IMETHOD GetCloneable(bool* aCloneable) final;
using nsIIPCSerializableInputStream::Serialize;
void Serialize(mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed,
mozilla::ipc::ChildToParentStreamActorManager* aManager) final;
protected:
DecryptingInputStreamBase(MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream,
size_t aBlockSize);
// For deserialization only.
DecryptingInputStreamBase() = default;
virtual ~DecryptingInputStreamBase() = default;
void Init(MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream,
size_t aBlockSize);
// Convenience routine to determine how many bytes of plain data
// we currently have in our buffer.
size_t PlainLength() const;
size_t EncryptedBufferLength() const;
InitializedOnce<const NotNull<nsCOMPtr<nsIInputStream>>> mBaseStream;
LazyInitializedOnceEarlyDestructible<const NotNull<nsCOMPtr<nsIInputStream>>>
mBaseStream;
LazyInitializedOnce<const NotNull<nsISeekableStream*>> mBaseSeekableStream;
LazyInitializedOnce<const NotNull<nsICloneableInputStream*>>
mBaseCloneableInputStream;
LazyInitializedOnce<const NotNull<nsIIPCSerializableInputStream*>>
mBaseIPCSerializableInputStream;
// Number of bytes of plain data in mBuffer.
size_t mPlainBytes = 0;
@ -54,7 +71,7 @@ class DecryptingInputStreamBase : public nsIInputStream,
// Next byte of mBuffer to return in ReadSegments().
size_t mNextByte = 0;
const size_t mBlockSize;
LazyInitializedOnceNotNull<const size_t> mBlockSize;
size_t mLastBlockLength = 0;
};
@ -72,6 +89,9 @@ class DecryptingInputStream final : public DecryptingInputStreamBase {
size_t aBlockSize, CipherStrategy aCipherStrategy,
typename CipherStrategy::KeyType aKey);
// For deserialization only.
explicit DecryptingInputStream(CipherStrategy aCipherStrategy);
NS_IMETHOD Close() override;
NS_IMETHOD Available(uint64_t* _retval) override;
NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
@ -83,6 +103,16 @@ class DecryptingInputStream final : public DecryptingInputStreamBase {
NS_IMETHOD Clone(nsIInputStream** _retval) override;
using DecryptingInputStreamBase::Serialize;
void Serialize(
mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed,
mozilla::ipc::ParentToChildStreamActorManager* aManager) override;
bool Deserialize(const mozilla::ipc::InputStreamParams& aParams,
const FileDescriptorArray& aFileDescriptors) override;
private:
~DecryptingInputStream();
@ -108,7 +138,7 @@ class DecryptingInputStream final : public DecryptingInputStreamBase {
bool EnsureBuffers();
const CipherStrategy mCipherStrategy;
const typename CipherStrategy::KeyType mKey;
LazyInitializedOnce<const typename CipherStrategy::KeyType> mKey;
// Buffer to hold encrypted data. Must copy here since we need a
// flat buffer to run the decryption process on.

View File

@ -11,6 +11,8 @@
#include "CipherStrategy.h"
#include "mozilla/ipc/InputStreamParams.h"
#include "nsFileStreams.h"
#include "nsIAsyncInputStream.h"
#include "nsStreamUtils.h"
@ -38,6 +40,12 @@ DecryptingInputStream<CipherStrategy>::~DecryptingInputStream() {
Close();
}
template <typename CipherStrategy>
DecryptingInputStream<CipherStrategy>::DecryptingInputStream(
CipherStrategy aCipherStrategy)
: DecryptingInputStreamBase{},
mCipherStrategy(std::move(aCipherStrategy)) {}
template <typename CipherStrategy>
NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Close() {
if (!mBaseStream) {
@ -183,7 +191,7 @@ nsresult DecryptingInputStream<CipherStrategy>::ParseNextChunk(
// XXX Do we need to know the actual decrypted size?
rv = mCipherStrategy.Cipher(
CipherMode::Decrypt, mKey, mEncryptedBlock->MutableCipherPrefix(),
CipherMode::Decrypt, *mKey, mEncryptedBlock->MutableCipherPrefix(),
mEncryptedBlock->Payload(), AsWritableBytes(Span{mPlainBuffer}));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -238,7 +246,7 @@ bool DecryptingInputStream<CipherStrategy>::EnsureBuffers() {
// until the stream is closed.
if (!mEncryptedBlock) {
// XXX Do we need to do this fallible (as the comment above suggests)?
mEncryptedBlock.emplace(mBlockSize);
mEncryptedBlock.emplace(*mBlockSize);
MOZ_ASSERT(mPlainBuffer.IsEmpty());
if (NS_WARN_IF(!mPlainBuffer.SetLength(mEncryptedBlock->MaxPayloadLength(),
@ -269,8 +277,8 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Tell(
return rv;
}
const auto fullBlocks = basePosition / mBlockSize;
MOZ_ASSERT(0 == basePosition % mBlockSize);
const auto fullBlocks = basePosition / *mBlockSize;
MOZ_ASSERT(0 == basePosition % *mBlockSize);
*aRetval = (fullBlocks - ((mPlainBytes || mLastBlockLength) ? 1 : 0)) *
mEncryptedBlock->MaxPayloadLength() +
@ -331,7 +339,7 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Seek(const int32_t aWhence,
nsresult rv =
(*mBaseSeekableStream)
->Seek(NS_SEEK_END, -static_cast<int64_t>(mBlockSize));
->Seek(NS_SEEK_END, -static_cast<int64_t>(*mBlockSize));
if (NS_WARN_IF(NS_FAILED(rv))) {
return Err(rv);
}
@ -377,7 +385,7 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Seek(const int32_t aWhence,
// XXX If we remain in the same block as before, we can skip this.
nsresult rv =
(*mBaseSeekableStream)->Seek(NS_SEEK_SET, baseBlocksOffset * mBlockSize);
(*mBaseSeekableStream)->Seek(NS_SEEK_SET, baseBlocksOffset * *mBlockSize);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -400,7 +408,7 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Seek(const int32_t aWhence,
return aOffset == 0 ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
}
nsresult rv = (*mBaseSeekableStream)->Seek(NS_SEEK_CUR, -mBlockSize);
nsresult rv = (*mBaseSeekableStream)->Seek(NS_SEEK_CUR, -*mBlockSize);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -438,12 +446,65 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Clone(
*_retval =
MakeAndAddRef<DecryptingInputStream>(WrapNotNull(std::move(clonedStream)),
mBlockSize, mCipherStrategy, mKey)
*mBlockSize, mCipherStrategy, *mKey)
.take();
return NS_OK;
}
template <typename CipherStrategy>
void DecryptingInputStream<CipherStrategy>::Serialize(
mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed,
mozilla::ipc::ParentToChildStreamActorManager* aManager) {
MOZ_ASSERT(mBaseStream);
MOZ_ASSERT(mBaseIPCSerializableInputStream);
mozilla::ipc::InputStreamParams baseStreamParams;
(*mBaseIPCSerializableInputStream)
->Serialize(baseStreamParams, aFileDescriptors, aDelayedStart, aMaxSize,
aSizeUsed, aManager);
MOZ_ASSERT(baseStreamParams.type() ==
mozilla::ipc::InputStreamParams::TFileInputStreamParams);
mozilla::ipc::EncryptedFileInputStreamParams encryptedFileInputStreamParams;
encryptedFileInputStreamParams.fileInputStreamParams() =
std::move(baseStreamParams);
encryptedFileInputStreamParams.key().AppendElements(
mCipherStrategy.SerializeKey(*mKey));
encryptedFileInputStreamParams.blockSize() = *mBlockSize;
aParams = std::move(encryptedFileInputStreamParams);
}
template <typename CipherStrategy>
bool DecryptingInputStream<CipherStrategy>::Deserialize(
const mozilla::ipc::InputStreamParams& aParams,
const FileDescriptorArray& aFileDescriptors) {
MOZ_ASSERT(aParams.type() ==
mozilla::ipc::InputStreamParams::TEncryptedFileInputStreamParams);
const auto& params = aParams.get_EncryptedFileInputStreamParams();
nsCOMPtr<nsIFileInputStream> stream;
nsFileInputStream::Create(nullptr, NS_GET_IID(nsIFileInputStream),
getter_AddRefs(stream));
nsCOMPtr<nsIIPCSerializableInputStream> baseSerializable =
do_QueryInterface(stream);
if (NS_WARN_IF(!baseSerializable->Deserialize(params.fileInputStreamParams(),
aFileDescriptors))) {
return false;
}
Init(WrapNotNull<nsCOMPtr<nsIInputStream>>(std::move(stream)),
params.blockSize());
mKey.init(mCipherStrategy.DeserializeKey(params.key()));
return true;
}
} // namespace mozilla::dom::quota
#endif

View File

@ -0,0 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#ifndef mozilla_dom_quota_IPCStreamCipherStrategy_h
#define mozilla_dom_quota_IPCStreamCipherStrategy_h
#include "mozilla/dom/quota/DummyCipherStrategy.h"
namespace mozilla::dom::quota {
using IPCStreamCipherStrategy = DummyCipherStrategy;
}
#endif

View File

@ -35,6 +35,7 @@ EXPORTS.mozilla.dom.quota += [
'EncryptingOutputStream_impl.h',
'FileStreams.h',
'InitializationTypes.h',
'IPCStreamCipherStrategy.h',
'MemoryOutputStream.h',
'OriginScope.h',
'PersistenceType.h',

View File

@ -92,6 +92,14 @@ union InputStreamParams
IPCBlobInputStreamParams;
InputStreamLengthWrapperParams;
IPCRemoteStreamParams;
EncryptedFileInputStreamParams;
};
struct EncryptedFileInputStreamParams
{
FileInputStreamParams fileInputStreamParams;
uint8_t[] key;
uint32_t blockSize;
};
struct BufferedInputStreamParams

View File

@ -13,6 +13,8 @@
#include "mozilla/dom/IPCBlobInputStream.h"
#include "mozilla/dom/IPCBlobInputStreamChild.h"
#include "mozilla/dom/IPCBlobInputStreamStorage.h"
#include "mozilla/dom/quota/DecryptingInputStream_impl.h"
#include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
#include "mozilla/ipc/IPCStreamDestination.h"
#include "mozilla/ipc/IPCStreamSource.h"
#include "mozilla/InputStreamLengthHelper.h"
@ -249,6 +251,9 @@ void InputStreamHelper::PostSerializationActivation(InputStreamParams& aParams,
case InputStreamParams::TIPCBlobInputStreamParams:
break;
case InputStreamParams::TEncryptedFileInputStreamParams:
break;
default:
MOZ_CRASH(
"A new stream? Should decide if it must be processed recursively or "
@ -361,6 +366,12 @@ already_AddRefed<nsIInputStream> InputStreamHelper::DeserializeInputStream(
serializable = new InputStreamLengthWrapper();
break;
case InputStreamParams::TEncryptedFileInputStreamParams:
serializable = new dom::quota::DecryptingInputStream<
dom::quota::IPCStreamCipherStrategy>(
dom::quota::IPCStreamCipherStrategy{});
break;
default:
MOZ_ASSERT(false, "Unknown params!");
return nullptr;