Source code
Revision control
Copy as Markdown
Other Tools
/* 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 <gtest/gtest.h>
#include <mfidl.h>
#include <string>
#include <windows.h>
#include <wrl.h>
#include "RefCounted.h"
#include "content_decryption_module.h"
// Define the include guard of WMFClearKeyCDM.h before including
// WMFClearKeySession.cpp so the preprocessor skips the real header when
// WMFClearKeySession.cpp includes it from its own directory. This allows the
// session source to compile without pulling in the full CDM stack.
#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDM_H
namespace mozilla {
class WMFClearKeySession;
class SessionManagerWrapper : public RefCounted {
public:
HRESULT GenerateRequest(cdm::InitDataType, const BYTE*, DWORD,
cdm::SessionType, WMFClearKeySession*, std::string&) {
return E_NOTIMPL;
}
HRESULT UpdateSession(const std::string&, const BYTE*, DWORD) {
return E_NOTIMPL;
}
HRESULT CloseSession(const std::string&) { return E_NOTIMPL; }
HRESULT RemoveSession(const std::string&) { return E_NOTIMPL; }
void Shutdown() {}
bool IsShutdown() { return false; }
private:
~SessionManagerWrapper() override = default;
};
} // namespace mozilla
#include "../WMFClearKeySession.cpp"
using namespace Microsoft::WRL;
using namespace mozilla;
namespace {
class WMFClearKeySessionTest : public ::testing::Test {
protected:
void SetUp() override {
ASSERT_HRESULT_SUCCEEDED(
MakeAndInitialize<MockSessionCallbacks>(&mCallbacks));
// Assign from a raw pointer so RefPtr::operator=(T*) runs and correctly
// AddRefs the object (avoids a UAF with this RefPtr impl, as this is not
// Mozilla's standard RefPtr).
SessionManagerWrapper* mgr = new SessionManagerWrapper();
mMgr = mgr;
ASSERT_HRESULT_SUCCEEDED(MakeAndInitialize<WMFClearKeySession>(
&mSession, MF_MEDIAKEYSESSION_TYPE_TEMPORARY, mCallbacks.Get(), mgr));
mSession->SetSessionIdForTesting("test-session");
}
class MockSessionCallbacks
: public RuntimeClass<RuntimeClassFlags<ClassicCom>,
IMFContentDecryptionModuleSessionCallbacks> {
public:
STDMETHODIMP KeyMessage(MF_MEDIAKEYSESSION_MESSAGETYPE, const BYTE*, DWORD,
LPCWSTR) override {
return S_OK;
}
STDMETHODIMP KeyStatusChanged() override { return S_OK; }
};
static void ExpectSingleKeyStatusEquals(WMFClearKeySession* session,
const uint8_t* keyId,
size_t keyIdSize) {
cdm::KeyInformation keyInfo;
keyInfo.key_id = keyId;
keyInfo.key_id_size = static_cast<uint32_t>(keyIdSize);
keyInfo.status = cdm::KeyStatus::kUsable;
keyInfo.system_code = 0;
session->OnKeyStatusChanged(&keyInfo, 1);
MFMediaKeyStatus* statuses = nullptr;
UINT count = 0;
ASSERT_HRESULT_SUCCEEDED(session->GetKeyStatuses(&statuses, &count));
ASSERT_NE(statuses, nullptr);
ASSERT_EQ(count, 1u);
EXPECT_EQ(statuses[0].cbKeyId, keyIdSize);
ASSERT_NE(statuses[0].pbKeyId, nullptr);
EXPECT_EQ(memcmp(statuses[0].pbKeyId, keyId, keyIdSize), 0);
CoTaskMemFree(statuses[0].pbKeyId);
CoTaskMemFree(statuses);
}
ComPtr<MockSessionCallbacks> mCallbacks;
RefPtr<SessionManagerWrapper> mMgr;
ComPtr<WMFClearKeySession> mSession;
};
} // namespace
TEST_F(WMFClearKeySessionTest, GetKeyStatusesSixteenByteKeyId) {
const uint8_t kKeyId[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
ExpectSingleKeyStatusEquals(mSession.Get(), kKeyId, sizeof(kKeyId));
}
TEST_F(WMFClearKeySessionTest, GetKeyStatusesEightByteKeyId) {
const uint8_t kKeyId[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
ExpectSingleKeyStatusEquals(mSession.Get(), kKeyId, sizeof(kKeyId));
}
TEST_F(WMFClearKeySessionTest, GetKeyStatusesThirtyTwoByteKeyId) {
const uint8_t kKeyId[32] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
ExpectSingleKeyStatusEquals(mSession.Get(), kKeyId, sizeof(kKeyId));
}