Squashed commit of the following CDM changes:
* Add additional parameters to CDM decryption API https://widevine-internal-review.googlesource.com/#/c/6500/ * Pass Length and Flags Parameters to Decrypt() https://widevine-internal-review.googlesource.com/#/c/6740/ * Remove core files from oemcrypto/mock https://widevine-internal-review.googlesource.com/#/c/6853/ Change-Id: I1c73f5454da20da99130b161543fb990e16e7130
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "media/stagefright/foundation/ABase.h"
|
||||
#include "media/stagefright/foundation/AString.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "wv_cdm_types.h"
|
||||
#include "wv_content_decryption_module.h"
|
||||
@@ -23,10 +24,8 @@ using namespace wvdrm;
|
||||
|
||||
class MockCDM : public WvContentDecryptionModule {
|
||||
public:
|
||||
MOCK_METHOD10(Decrypt, CdmResponseType(const CdmSessionId&, bool, bool,
|
||||
const KeyId&, const uint8_t*, size_t,
|
||||
const std::vector<uint8_t>&, size_t,
|
||||
void*, size_t));
|
||||
MOCK_METHOD2(Decrypt, CdmResponseType(const CdmSessionId&,
|
||||
const CdmDecryptionParameters&));
|
||||
|
||||
MOCK_METHOD1(QueryStatus, CdmResponseType(CdmQueryMap*));
|
||||
};
|
||||
@@ -70,6 +69,74 @@ TEST_F(WVCryptoPluginTest, CorrectlyReportsSecureBuffers) {
|
||||
"WVCryptoPlugin incorrectly expects a secure audio decoder";
|
||||
}
|
||||
|
||||
// Factory for matchers that perform deep matching of values against a
|
||||
// CdmDecryptionParameters struct. For use in the test AttemptsToDecrypt.
|
||||
class CDPMatcherFactory {
|
||||
public:
|
||||
// Some values do not change over the course of the test. To avoid having
|
||||
// to re-specify them at every call site, we pass them into the factory
|
||||
// constructor.
|
||||
CDPMatcherFactory(bool isSecure, uint8_t* keyId, void* out, size_t outLen)
|
||||
: mIsSecure(isSecure), mKeyId(keyId), mOut(out), mOutLen(outLen) {}
|
||||
|
||||
Matcher<const CdmDecryptionParameters&> operator()(bool isEncrypted,
|
||||
uint8_t* in,
|
||||
size_t inLen,
|
||||
uint8_t* iv,
|
||||
size_t blockOffset,
|
||||
size_t outOffset,
|
||||
uint8_t flags) const {
|
||||
return Truly(CDPMatcher(mIsSecure, mKeyId, mOut, mOutLen, isEncrypted,
|
||||
in, inLen, iv, blockOffset, outOffset, flags));
|
||||
}
|
||||
|
||||
private:
|
||||
// Predicate that validates that the fields of a passed-in
|
||||
// CdmDecryptionParameters match the values it was given at construction
|
||||
// time.
|
||||
class CDPMatcher {
|
||||
public:
|
||||
CDPMatcher(bool isSecure, uint8_t* keyId, void* out, size_t outLen,
|
||||
bool isEncrypted, uint8_t* in, size_t inLen, uint8_t* iv,
|
||||
size_t blockOffset, size_t outOffset, uint8_t flags)
|
||||
: mIsSecure(isSecure), mKeyId(keyId), mOut(out), mOutLen(outLen),
|
||||
mIsEncrypted(isEncrypted), mIn(in), mInLen(inLen), mIv(iv),
|
||||
mBlockOffset(blockOffset), mOutOffset(outOffset), mFlags(flags) {}
|
||||
|
||||
bool operator()(const CdmDecryptionParameters& params) const {
|
||||
return params.is_secure == mIsSecure &&
|
||||
Value(*params.key_id, ElementsAreArray(mKeyId, KEY_ID_SIZE)) &&
|
||||
params.decrypt_buffer == mOut &&
|
||||
params.decrypt_buffer_length == mOutLen &&
|
||||
params.is_encrypted == mIsEncrypted &&
|
||||
params.encrypt_buffer == mIn &&
|
||||
params.encrypt_length == mInLen &&
|
||||
Value(*params.iv, ElementsAreArray(mIv, KEY_IV_SIZE)) &&
|
||||
params.block_offset == mBlockOffset &&
|
||||
params.decrypt_buffer_offset == mOutOffset &&
|
||||
params.subsample_flags == mFlags;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mIsSecure;
|
||||
uint8_t* mKeyId;
|
||||
void* mOut;
|
||||
size_t mOutLen;
|
||||
bool mIsEncrypted;
|
||||
uint8_t* mIn;
|
||||
size_t mInLen;
|
||||
uint8_t* mIv;
|
||||
size_t mBlockOffset;
|
||||
size_t mOutOffset;
|
||||
uint8_t mFlags;
|
||||
};
|
||||
|
||||
bool mIsSecure;
|
||||
uint8_t* mKeyId;
|
||||
void* mOut;
|
||||
size_t mOutLen;
|
||||
};
|
||||
|
||||
TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
||||
StrictMock<MockCDM> cdm;
|
||||
WVCryptoPlugin plugin(sessionId, kSessionIdSize, &cdm);
|
||||
@@ -111,61 +178,49 @@ TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
||||
memcpy(iv[4], baseIv, sizeof(baseIv));
|
||||
iv[4][15] = 7;
|
||||
|
||||
CDPMatcherFactory ParamsAre = CDPMatcherFactory(false, keyId, out, kDataSize);
|
||||
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
// SubSample 0
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
||||
in, 16, ElementsAreArray(iv[0], KEY_IV_SIZE),
|
||||
0, out, 0))
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
ParamsAre(true, in, 16, iv[0], 0, 0,
|
||||
OEMCrypto_FirstSubsample)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 1
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), false,
|
||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
||||
in + 16, 16, ElementsAreArray(iv[1], KEY_IV_SIZE),
|
||||
0, out, 16))
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
ParamsAre(false, in + 16, 16, iv[1], 0, 16, 0)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
||||
in + 32, 16, ElementsAreArray(iv[1], KEY_IV_SIZE),
|
||||
0, out, 32))
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
ParamsAre(true, in + 32, 16, iv[1], 0, 32, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 2
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
||||
in + 48, 8, ElementsAreArray(iv[2], KEY_IV_SIZE),
|
||||
0, out, 48))
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
ParamsAre(true, in + 48, 8, iv[2], 0, 48, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 3
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), false,
|
||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
||||
in + 56, 29, ElementsAreArray(iv[2], KEY_IV_SIZE),
|
||||
0, out, 56))
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
ParamsAre(false, in + 56, 29, iv[2], 0, 56, 0)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
||||
in + 85, 24, ElementsAreArray(iv[2], KEY_IV_SIZE),
|
||||
8, out, 85))
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
ParamsAre(true, in + 85, 24, iv[2], 8, 85, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 4
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
||||
in + 109, 60, ElementsAreArray(iv[3], KEY_IV_SIZE),
|
||||
0, out, 109))
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
ParamsAre(true, in + 109, 60, iv[3], 0, 109, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 5
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
||||
in + 169, 16, ElementsAreArray(iv[4], KEY_IV_SIZE),
|
||||
12, out, 169))
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
ParamsAre(true, in + 169, 16, iv[4], 12, 169,
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
@@ -208,10 +263,12 @@ TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, _, false, _, _, _, _, _, _, _))
|
||||
typedef CdmDecryptionParameters CDP;
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::is_secure, false)))
|
||||
.Times(2);
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, _, true, _, _, _, _, _, _, _))
|
||||
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::is_secure, true)))
|
||||
.Times(2);
|
||||
}
|
||||
|
||||
@@ -232,3 +289,81 @@ TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
}
|
||||
|
||||
TEST_F(WVCryptoPluginTest, SetsFlagsForMinimumSubsampleRuns) {
|
||||
MockCDM cdm;
|
||||
WVCryptoPlugin plugin(sessionId, kSessionIdSize, &cdm);
|
||||
|
||||
uint8_t keyId[KEY_ID_SIZE];
|
||||
uint8_t iv[KEY_IV_SIZE];
|
||||
|
||||
static const size_t kDataSize = 16;
|
||||
uint8_t in[kDataSize];
|
||||
uint8_t out[kDataSize];
|
||||
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp);
|
||||
fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp);
|
||||
fread(in, sizeof(uint8_t), kDataSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
static const uint32_t kSubSampleCount = 1;
|
||||
CryptoPlugin::SubSample clearSubSamples[kSubSampleCount];
|
||||
memset(clearSubSamples, 0, sizeof(clearSubSamples));
|
||||
clearSubSamples[0].mNumBytesOfClearData = 16;
|
||||
|
||||
CryptoPlugin::SubSample encryptedSubSamples[kSubSampleCount];
|
||||
memset(encryptedSubSamples, 0, sizeof(encryptedSubSamples));
|
||||
encryptedSubSamples[0].mNumBytesOfEncryptedData = 16;
|
||||
|
||||
CryptoPlugin::SubSample mixedSubSamples[kSubSampleCount];
|
||||
memset(mixedSubSamples, 0, sizeof(mixedSubSamples));
|
||||
mixedSubSamples[0].mNumBytesOfClearData = 8;
|
||||
mixedSubSamples[0].mNumBytesOfEncryptedData = 8;
|
||||
|
||||
// Specify the expected calls to Decrypt
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
typedef CdmDecryptionParameters CDP;
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_FirstSubsample |
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(2);
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_FirstSubsample)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
AString errorDetailMessage;
|
||||
|
||||
ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
in, clearSubSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
|
||||
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR, in,
|
||||
encryptedSubSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
|
||||
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR, in,
|
||||
mixedSubSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user