Files
android/libwvdrmengine/mediacrypto/test/WVCryptoPlugin_test.cpp
Jeff Tinker 3a28eeeb68 Part of Qualcomm L1 OEMCrypto integration on mako
bug: 8621521

This fixes a problem where insecure audio buffers were being
passed incorrectly as secure buffers to the trusted
environment's OEMCrypto_DecryptCTR.

This is a merge of the following changes from the widevine
git repository to android git repository:

https://widevine-internal-review.googlesource.com/#/c/5163/2
Allow selection of secure/non-secure buffers

https://widevine-internal-review.googlesource.com/#/c/5164/
Pass Secure Buffer Request to CDM

Change-Id: Iec1192a216305c6cf92c359b15b148eccc6ce6ce
2013-04-22 17:50:38 -07:00

235 lines
8.1 KiB
C++

//
// Copyright 2013 Google Inc. All Rights Reserved.
//
#include <stdio.h>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "media/stagefright/foundation/ABase.h"
#include "media/stagefright/foundation/AString.h"
#include "wv_cdm_constants.h"
#include "wv_cdm_types.h"
#include "wv_content_decryption_module.h"
#include "WVCryptoPlugin.h"
using namespace android;
using namespace std;
using namespace testing;
using namespace wvcdm;
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_METHOD1(QueryStatus, CdmResponseType(CdmQueryMap*));
};
class WVCryptoPluginTest : public Test {
protected:
static const uint32_t kSessionIdSize = 16;
uint8_t sessionId[kSessionIdSize];
virtual void SetUp() {
FILE* fp = fopen("/dev/urandom", "r");
fread(sessionId, sizeof(uint8_t), kSessionIdSize, fp);
fclose(fp);
// Set default CdmResponseType value for gMock
DefaultValue<CdmResponseType>::Set(wvcdm::NO_ERROR);
}
};
TEST_F(WVCryptoPluginTest, CorrectlyReportsSecureBuffers) {
MockCDM cdm;
WVCryptoPlugin plugin(sessionId, kSessionIdSize, &cdm);
CdmQueryMap l1Map;
l1Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1;
CdmQueryMap l3Map;
l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3;
EXPECT_CALL(cdm, QueryStatus(_))
.WillOnce(DoAll(SetArgPointee<0>(l1Map),
Return(wvcdm::NO_ERROR)))
.WillOnce(DoAll(SetArgPointee<0>(l3Map),
Return(wvcdm::NO_ERROR)));
EXPECT_TRUE(plugin.requiresSecureDecoderComponent("video/mp4")) <<
"WVCryptoPlugin incorrectly allows an insecure video decoder on L1";
EXPECT_FALSE(plugin.requiresSecureDecoderComponent("video/mp4")) <<
"WVCryptoPlugin incorrectly expects a secure video decoder on L3";
EXPECT_FALSE(plugin.requiresSecureDecoderComponent("audio/aac")) <<
"WVCryptoPlugin incorrectly expects a secure audio decoder";
}
TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
MockCDM cdm;
WVCryptoPlugin plugin(sessionId, kSessionIdSize, &cdm);
uint8_t keyId[KEY_ID_SIZE];
uint8_t baseIv[KEY_IV_SIZE];
static const size_t kDataSize = 185;
uint8_t in[kDataSize];
uint8_t out[kDataSize];
FILE* fp = fopen("/dev/urandom", "r");
fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp);
fread(baseIv, sizeof(uint8_t), KEY_IV_SIZE, fp);
fread(in, sizeof(uint8_t), kDataSize, fp);
fclose(fp);
static const size_t kSubSampleCount = 6;
CryptoPlugin::SubSample subSamples[kSubSampleCount];
memset(subSamples, 0, sizeof(subSamples));
subSamples[0].mNumBytesOfEncryptedData = 16;
subSamples[1].mNumBytesOfClearData = 16;
subSamples[1].mNumBytesOfEncryptedData = 16;
subSamples[2].mNumBytesOfEncryptedData = 8;
subSamples[3].mNumBytesOfClearData = 29;
subSamples[3].mNumBytesOfEncryptedData = 24;
subSamples[4].mNumBytesOfEncryptedData = 60;
subSamples[5].mNumBytesOfEncryptedData = 16;
uint8_t iv[5][KEY_IV_SIZE];
memcpy(iv[0], baseIv, sizeof(baseIv));
iv[0][15] = 0;
memcpy(iv[1], baseIv, sizeof(baseIv));
iv[1][15] = 1;
memcpy(iv[2], baseIv, sizeof(baseIv));
iv[2][15] = 2;
memcpy(iv[3], baseIv, sizeof(baseIv));
iv[3][15] = 4;
memcpy(iv[4], baseIv, sizeof(baseIv));
iv[4][15] = 7;
{
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))
.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))
.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))
.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))
.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))
.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))
.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))
.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))
.Times(1);
}
AString errorDetailMessage;
ssize_t res = plugin.decrypt(false, keyId, iv[0], CryptoPlugin::kMode_AES_CTR,
in, subSamples, kSubSampleCount, out,
&errorDetailMessage);
EXPECT_EQ(static_cast<ssize_t>(kDataSize), res) <<
"WVCryptoPlugin decrypted the wrong number of bytes";
EXPECT_EQ(0u, errorDetailMessage.size()) <<
"WVCryptoPlugin reported a detailed error message.";
}
TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
MockCDM cdm;
WVCryptoPlugin plugin(sessionId, kSessionIdSize, &cdm);
uint8_t keyId[KEY_ID_SIZE];
uint8_t iv[KEY_IV_SIZE];
static const size_t kDataSize = 32;
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 subSamples[kSubSampleCount];
memset(subSamples, 0, sizeof(subSamples));
subSamples[0].mNumBytesOfClearData = 16;
subSamples[0].mNumBytesOfEncryptedData = 16;
// Specify the expected calls to Decrypt
{
InSequence calls;
EXPECT_CALL(cdm, Decrypt(_, _, false, _, _, _, _, _, _, _))
.Times(2);
EXPECT_CALL(cdm, Decrypt(_, _, true, _, _, _, _, _, _, _))
.Times(2);
}
AString errorDetailMessage;
ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
in, subSamples, 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(true, keyId, iv, CryptoPlugin::kMode_AES_CTR, in,
subSamples, kSubSampleCount, out, &errorDetailMessage);
ASSERT_GE(res, 0) <<
"WVCryptoPlugin returned an error";
EXPECT_EQ(0u, errorDetailMessage.size()) <<
"WVCryptoPlugin reported a detailed error message.";
}