Regular sync.

Changes include:
1. Fix refreshkeys when handling renewal response.
2. Change ECM start detect method.
3. Fix signing key truncation.
4. Reformat C++ code.
5. Return license_id in LICENSE_CAS_READY payload.
6. Expose OEMCrypto API version in the license request.
7. Add support for newly added widevine cas ids.
8. Store content iv and encryption mode info to entitled key.
9. Upgrade ODK library to 16.4.
This commit is contained in:
huihli
2020-10-21 11:16:23 -07:00
parent 0f6db6f751
commit 2feec02df2
39 changed files with 703 additions and 546 deletions

View File

@@ -2,13 +2,14 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "cas_license.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <openssl/sha.h>
#include <memory>
#include "cas_license.h"
#include "cas_status.h"
#include "cas_util.h"
#include "crypto_key.h"
@@ -348,6 +349,10 @@ TEST_F(CasLicenseTest, GenerateEntitlementRequest) {
EXPECT_CALL(*strict_mock_, GetOEMPublicCertificate(_, _))
.WillOnce(Return(wvcas::CasStatusCode::kCryptoSessionError));
EXPECT_CALL(*strict_mock_, APIVersion(_))
.WillOnce(Return(wvcas::CasStatusCode::kNoError));
EXPECT_CALL(*strict_mock_, GenerateNonce(_))
.WillOnce(Return(wvcas::CasStatusCode::kNoError));
EXPECT_CALL(*strict_mock_,
@@ -373,6 +378,9 @@ TEST_F(CasLicenseTest, HandleEntitlementResponse) {
EXPECT_CALL(*strict_mock_, GetOEMPublicCertificate(_, _))
.WillOnce(Return(wvcas::CasStatusCode::kCryptoSessionError));
EXPECT_CALL(*strict_mock_, APIVersion(_))
.WillOnce(Return(wvcas::CasStatusCode::kNoError));
EXPECT_CALL(*strict_mock_, GenerateNonce(_))
.WillOnce(Return(wvcas::CasStatusCode::kNoError));
EXPECT_CALL(*strict_mock_,

View File

@@ -1,5 +1,6 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <memory>
#include "widevine_cas_session.h"

View File

@@ -90,10 +90,10 @@ MATCHER_P2(IsValidInputStreamParamsWithCollectSizeT, container, expected, "") {
}
MATCHER_P(IsValidOutBytes, expected, "") {
if(nullptr == arg) {
if (nullptr == arg) {
return false;
}
if (*arg != *expected){
if (*arg != *expected) {
return false;
}
return true;
@@ -189,6 +189,7 @@ class MockedOEMCrypto : public wvcas::OEMCryptoInterface {
OEMCryptoResult(OEMCrypto_SESSION));
MOCK_CONST_METHOD0(OEMCrypto_GetProvisioningMethod,
OEMCrypto_ProvisioningMethod());
MOCK_CONST_METHOD0(OEMCrypto_APIVersion, uint32_t());
MOCK_CONST_METHOD2(OEMCrypto_GetKeyData,
OEMCryptoResult(uint8_t* keyData, size_t* keyDataLength));
MOCK_CONST_METHOD0(OEMCrypto_SupportedCertificates, uint32_t());
@@ -458,6 +459,36 @@ TEST_F(CryptoSessionTest, GetKeyData) {
EXPECT_EQ(size_t(0x4321), size);
}
TEST_F(CryptoSessionTest, GetApiVersion) {
EXPECT_CALL(nice_oemcrypto_interface_, OEMCrypto_OpenSession(_))
.WillOnce(
DoAll(SetArgPointee<0>(kOemcSessionId), Return(OEMCrypto_SUCCESS)));
TestCryptoSession<NiceMock<MockedOEMCrypto> > crypto_session(
nice_oemcrypto_interface_);
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
crypto_session.initialize().status_code());
uint32_t api_version = 0;
EXPECT_CALL(nice_oemcrypto_interface_, OEMCrypto_APIVersion())
.WillOnce(Return(16))
.WillOnce(Return(15))
.WillOnce(Return(14));
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
crypto_session.APIVersion(&api_version).status_code());
EXPECT_EQ(api_version, 16);
api_version = 0;
EXPECT_EQ(wvcas::CasStatusCode::kOEMCryptoVersionMismatch,
crypto_session.APIVersion(&api_version).status_code());
EXPECT_EQ(api_version, 0);
EXPECT_EQ(wvcas::CasStatusCode::kOEMCryptoVersionMismatch,
crypto_session.APIVersion(&api_version).status_code());
EXPECT_EQ(api_version, 0);
}
TEST_F(CryptoSessionTest, GetSupportedCertificates) {
EXPECT_CALL(nice_oemcrypto_interface_, OEMCrypto_OpenSession(_))
.WillOnce(

View File

@@ -7,59 +7,68 @@
#include <arpa/inet.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <bitset>
#include <tuple>
namespace {
static constexpr int kCaIdSizeBytes = 2;
static constexpr int kModeSizeBytes = 1;
static constexpr int kVersionSizeBytes = 1;
static constexpr int kIVFlagsSizeBytes = 1;
static constexpr int kEntitlementKeyIDSizeBytes = 16;
static constexpr int kContentKeyIDSizeBytes = 16;
static constexpr int kContentKeyDataSize = 16;
static constexpr int kWrappedKeyIVSizeBytes = 16;
constexpr int kCasIdSizeBytes = 2;
constexpr int kModeSizeBytes = 1;
constexpr int kVersionSizeBytes = 1;
constexpr int kIVFlagsSizeBytes = 1;
constexpr int kEntitlementKeyIDSizeBytes = 16;
constexpr int kContentKeyIDSizeBytes = 16;
constexpr int kContentKeyDataSize = 16;
constexpr int kWrappedKeyIVSizeBytes = 16;
static constexpr int kEcmDescriptorSizeBytes =
kCaIdSizeBytes + kModeSizeBytes + kVersionSizeBytes + kIVFlagsSizeBytes;
constexpr int kEcmDescriptorSizeBytes =
kCasIdSizeBytes + kModeSizeBytes + kVersionSizeBytes + kIVFlagsSizeBytes;
static constexpr int kECMVersion = 2;
constexpr int kECMVersion = 2;
// The cipher mode flags field in the ECM V2 is 4 bits.
static constexpr uint8_t kAESCBCCryptoModeFlagsVal = (0x0 << 1);
static constexpr uint8_t kAESCTRCryptoModeFlagsVal = (0x1 << 1);
static constexpr uint8_t kDvbCsa2CryptoModeFlagsVal = (0x2 << 1);
static constexpr uint8_t kDvbCsa3CryptoModeFlagsVal = (0x3 << 1);
static constexpr uint8_t kDvbOFBCryptoModeFlagsVal = (0x4 << 1);
static constexpr uint8_t kDvbSCTECryptoModeFlagsVal = (0x5 << 1);
static constexpr uint8_t kRotationFlag = (0x1 << 0);
static constexpr uint8_t kContentIVSizeFlag = (0x1 << 6);
constexpr uint8_t kAESCBCCryptoModeFlagsVal = (0x0 << 1);
constexpr uint8_t kAESCTRCryptoModeFlagsVal = (0x1 << 1);
constexpr uint8_t kDvbCsa2CryptoModeFlagsVal = (0x2 << 1);
constexpr uint8_t kDvbCsa3CryptoModeFlagsVal = (0x3 << 1);
constexpr uint8_t kDvbOFBCryptoModeFlagsVal = (0x4 << 1);
constexpr uint8_t kDvbSCTECryptoModeFlagsVal = (0x5 << 1);
constexpr uint8_t kRotationFlag = (0x1 << 0);
constexpr uint8_t kContentIVSizeFlag = (0x1 << 6);
static constexpr uint8_t kEntitlementKeyIDFill = '1';
static constexpr uint8_t kEvenContentKeyIDFill = '2';
static constexpr uint8_t kEvenContentKeyDataFill = '3';
static constexpr uint8_t kEvenWrappedKeyIVFill = '4';
static constexpr uint8_t kEvenContentKeyIVFill = '5';
static constexpr uint8_t kOddContentKeyIDFill = '6';
static constexpr uint8_t kOddContentKeyDataFill = '7';
static constexpr uint8_t kOddWrappedKeyIVFill = '8';
static constexpr uint8_t kOddContentKeyIVFill = '9';
constexpr uint8_t kEntitlementKeyIDFill = '1';
constexpr uint8_t kEvenContentKeyIDFill = '2';
constexpr uint8_t kEvenContentKeyDataFill = '3';
constexpr uint8_t kEvenWrappedKeyIVFill = '4';
constexpr uint8_t kEvenContentKeyIVFill = '5';
constexpr uint8_t kOddContentKeyIDFill = '6';
constexpr uint8_t kOddContentKeyDataFill = '7';
constexpr uint8_t kOddWrappedKeyIVFill = '8';
constexpr uint8_t kOddContentKeyIVFill = '9';
static constexpr size_t kMaxEcmSizeBytes = 184;
constexpr size_t kMaxEcmSizeBytes = 184;
static constexpr uint16_t kSectionHeader1 = 0x80;
static constexpr uint16_t kSectionHeader2 = 0x81;
static constexpr size_t kSectionHeaderSize = 4;
constexpr uint16_t kSectionHeader1 = 0x80;
constexpr uint16_t kSectionHeader2 = 0x81;
constexpr uint8_t kPointerFieldZero = 0x00;
constexpr uint16_t kWidevineCasId = 0x4AD4;
// New Widevine CAS IDs 0x56C0 to 0x56C9 (all inclusive).
constexpr uint16_t kWidevineNewCasIdLowerBound = 0x56C0;
constexpr uint16_t kWidevineNewCasIdUpperBound = 0x56C9;
} // namespace
class EcmParserTest : public testing::Test {
public:
void SetUp() { BuildEcm(); }
protected:
void SetUp() {
BuildEcm(kWidevineCasId, /*with_rotation=*/true, /*content_iv_flag=*/false);
}
size_t ContentKeyIVSize(bool content_iv_flag);
size_t CalculateEcmSize(bool with_rotation, bool content_iv_flag = false);
std::vector<uint8_t> ecm_data_;
void BuildEcm(uint16_t cas_id, bool with_rotation, bool content_iv_flag);
private:
void BuildEcm(bool with_rotation = true, bool content_iv_flag = false);
std::vector<uint8_t> ecm_data_;
std::unique_ptr<const wvcas::EcmParser> parser_;
};
size_t EcmParserTest::ContentKeyIVSize(bool content_iv_flag) {
@@ -76,12 +85,13 @@ size_t EcmParserTest::CalculateEcmSize(bool with_rotation,
return kEcmDescriptorSizeBytes + ecm_key_data_size * (with_rotation ? 2 : 1);
}
void EcmParserTest::BuildEcm(bool with_rotation, bool content_iv_flag) {
void EcmParserTest::BuildEcm(uint16_t cas_id, bool with_rotation,
bool content_iv_flag) {
ecm_data_.clear();
ecm_data_.reserve(CalculateEcmSize(with_rotation, content_iv_flag));
ecm_data_.resize(kCaIdSizeBytes, 0);
ecm_data_[0] = 0x4A;
ecm_data_[1] = 0xD4;
ecm_data_.resize(kCasIdSizeBytes, 0);
ecm_data_[0] = cas_id >> 8;
ecm_data_[1] = cas_id & 0xff;
ecm_data_.resize(ecm_data_.size() + kVersionSizeBytes, kECMVersion);
ecm_data_.resize(ecm_data_.size() + kModeSizeBytes,
kAESCBCCryptoModeFlagsVal);
@@ -121,172 +131,207 @@ void EcmParserTest::BuildEcm(bool with_rotation, bool content_iv_flag) {
TEST_F(EcmParserTest, FieldsWithoutKeyRotation) {
bool content_key_iv_16b = false;
ecm_data_.resize(CalculateEcmSize(false, content_key_iv_16b));
std::unique_ptr<const wvcas::EcmParser> parser;
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
ASSERT_FALSE(parser->rotation_enabled());
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
ASSERT_FALSE(parser_->rotation_enabled());
std::vector<uint8_t> test_data;
test_data.resize(kEntitlementKeyIDSizeBytes, kEntitlementKeyIDFill);
EXPECT_EQ(test_data,
parser->entitlement_key_id(wvcas::KeySlotId::kEvenKeySlot));
parser_->entitlement_key_id(wvcas::KeySlotId::kEvenKeySlot));
test_data.clear();
test_data.resize(kContentKeyIDSizeBytes, kEvenContentKeyIDFill);
EXPECT_EQ(test_data, parser->content_key_id(wvcas::KeySlotId::kEvenKeySlot));
EXPECT_EQ(test_data, parser_->content_key_id(wvcas::KeySlotId::kEvenKeySlot));
test_data.clear();
test_data.resize(kContentKeyIDSizeBytes, kEvenContentKeyDataFill);
EXPECT_EQ(test_data,
parser->wrapped_key_data(wvcas::KeySlotId::kEvenKeySlot));
parser_->wrapped_key_data(wvcas::KeySlotId::kEvenKeySlot));
test_data.clear();
test_data.resize(kWrappedKeyIVSizeBytes, kEvenWrappedKeyIVFill);
EXPECT_EQ(test_data, parser->wrapped_key_iv(wvcas::KeySlotId::kEvenKeySlot));
EXPECT_EQ(test_data, parser_->wrapped_key_iv(wvcas::KeySlotId::kEvenKeySlot));
test_data.clear();
test_data.resize(ContentKeyIVSize(content_key_iv_16b), kEvenContentKeyIVFill);
EXPECT_EQ(test_data, parser->content_iv(wvcas::KeySlotId::kEvenKeySlot));
EXPECT_EQ(test_data, parser_->content_iv(wvcas::KeySlotId::kEvenKeySlot));
EXPECT_TRUE(parser->content_key_id(wvcas::KeySlotId::kOddKeySlot).empty());
EXPECT_TRUE(parser->wrapped_key_data(wvcas::KeySlotId::kOddKeySlot).empty());
EXPECT_TRUE(parser->wrapped_key_iv(wvcas::KeySlotId::kOddKeySlot).empty());
EXPECT_TRUE(parser->content_iv(wvcas::KeySlotId::kOddKeySlot).empty());
EXPECT_TRUE(parser_->content_key_id(wvcas::KeySlotId::kOddKeySlot).empty());
EXPECT_TRUE(parser_->wrapped_key_data(wvcas::KeySlotId::kOddKeySlot).empty());
EXPECT_TRUE(parser_->wrapped_key_iv(wvcas::KeySlotId::kOddKeySlot).empty());
EXPECT_TRUE(parser_->content_iv(wvcas::KeySlotId::kOddKeySlot).empty());
}
TEST_F(EcmParserTest, FieldsWithKeyRotation) {
ecm_data_[3] |= kRotationFlag;
std::unique_ptr<const wvcas::EcmParser> parser;
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
ASSERT_TRUE(parser->rotation_enabled());
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
ASSERT_TRUE(parser_->rotation_enabled());
std::vector<uint8_t> test_data;
test_data.resize(kEntitlementKeyIDSizeBytes, kEntitlementKeyIDFill);
EXPECT_EQ(test_data,
parser->entitlement_key_id(wvcas::KeySlotId::kEvenKeySlot));
parser_->entitlement_key_id(wvcas::KeySlotId::kEvenKeySlot));
test_data.clear();
test_data.resize(kContentKeyIDSizeBytes, kEvenContentKeyIDFill);
EXPECT_EQ(test_data, parser->content_key_id(wvcas::KeySlotId::kEvenKeySlot));
EXPECT_EQ(test_data, parser_->content_key_id(wvcas::KeySlotId::kEvenKeySlot));
test_data.clear();
test_data.resize(kContentKeyIDSizeBytes, kEvenContentKeyDataFill);
EXPECT_EQ(test_data,
parser->wrapped_key_data(wvcas::KeySlotId::kEvenKeySlot));
parser_->wrapped_key_data(wvcas::KeySlotId::kEvenKeySlot));
test_data.clear();
test_data.resize(kWrappedKeyIVSizeBytes, kEvenWrappedKeyIVFill);
EXPECT_EQ(test_data, parser->wrapped_key_iv(wvcas::KeySlotId::kEvenKeySlot));
EXPECT_EQ(test_data, parser_->wrapped_key_iv(wvcas::KeySlotId::kEvenKeySlot));
test_data.clear();
bool content_key_iv_16b = false;
test_data.resize(ContentKeyIVSize(content_key_iv_16b), kEvenContentKeyIVFill);
EXPECT_EQ(test_data, parser->content_iv(wvcas::KeySlotId::kEvenKeySlot));
EXPECT_EQ(test_data, parser_->content_iv(wvcas::KeySlotId::kEvenKeySlot));
test_data.clear();
test_data.resize(kContentKeyIDSizeBytes, kOddContentKeyIDFill);
EXPECT_EQ(test_data, parser->content_key_id(wvcas::KeySlotId::kOddKeySlot));
EXPECT_EQ(test_data, parser_->content_key_id(wvcas::KeySlotId::kOddKeySlot));
test_data.clear();
test_data.resize(kContentKeyIDSizeBytes, kOddContentKeyDataFill);
EXPECT_EQ(test_data, parser->wrapped_key_data(wvcas::KeySlotId::kOddKeySlot));
EXPECT_EQ(test_data,
parser_->wrapped_key_data(wvcas::KeySlotId::kOddKeySlot));
test_data.clear();
test_data.resize(kWrappedKeyIVSizeBytes, kOddWrappedKeyIVFill);
EXPECT_EQ(test_data, parser->wrapped_key_iv(wvcas::KeySlotId::kOddKeySlot));
EXPECT_EQ(test_data, parser_->wrapped_key_iv(wvcas::KeySlotId::kOddKeySlot));
test_data.clear();
test_data.resize(ContentKeyIVSize(content_key_iv_16b), kOddContentKeyIVFill);
EXPECT_EQ(test_data, parser->content_iv(wvcas::KeySlotId::kOddKeySlot));
EXPECT_EQ(test_data, parser_->content_iv(wvcas::KeySlotId::kOddKeySlot));
}
TEST_F(EcmParserTest, create) {
std::unique_ptr<const wvcas::EcmParser> parser;
EXPECT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
ecm_data_.resize(4);
EXPECT_FALSE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_FALSE(wvcas::EcmParser::create(ecm_data_, &parser_));
ecm_data_.resize(4 + CalculateEcmSize(false));
EXPECT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
ecm_data_.resize(kMaxEcmSizeBytes);
EXPECT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
ecm_data_.resize(CalculateEcmSize(true));
EXPECT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_FALSE(wvcas::EcmParser::create(ecm_data_, nullptr));
ecm_data_.resize(CalculateEcmSize(true));
EXPECT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_FALSE(wvcas::EcmParser::create(ecm_data_, nullptr));
}
TEST_F(EcmParserTest, crypto_mode) {
std::unique_ptr<const wvcas::EcmParser> parser;
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_EQ(parser->crypto_mode(), wvcas::CryptoMode::kAesCBC);
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_EQ(parser_->crypto_mode(), wvcas::CryptoMode::kAesCBC);
ecm_data_[3] = kAESCTRCryptoModeFlagsVal;
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_EQ(parser->crypto_mode(), wvcas::CryptoMode::kAesCTR);
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_EQ(parser_->crypto_mode(), wvcas::CryptoMode::kAesCTR);
ecm_data_[3] = kDvbCsa2CryptoModeFlagsVal;
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_EQ(parser->crypto_mode(), wvcas::CryptoMode::kDvbCsa2);
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_EQ(parser_->crypto_mode(), wvcas::CryptoMode::kDvbCsa2);
ecm_data_[3] = kDvbCsa3CryptoModeFlagsVal;
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_EQ(parser->crypto_mode(), wvcas::CryptoMode::kDvbCsa3);
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_EQ(parser_->crypto_mode(), wvcas::CryptoMode::kDvbCsa3);
ecm_data_[3] = kDvbOFBCryptoModeFlagsVal;
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_EQ(parser->crypto_mode(), wvcas::CryptoMode::kAesOFB);
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_EQ(parser_->crypto_mode(), wvcas::CryptoMode::kAesOFB);
ecm_data_[3] = kDvbSCTECryptoModeFlagsVal;
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_EQ(parser->crypto_mode(), wvcas::CryptoMode::kAesSCTE);
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_EQ(parser_->crypto_mode(), wvcas::CryptoMode::kAesSCTE);
}
TEST_F(EcmParserTest, ContentKeyIVSizes) {
std::unique_ptr<const wvcas::EcmParser> parser;
bool with_rotation = true;
bool iv_flag = false;
ecm_data_.resize(CalculateEcmSize(with_rotation, iv_flag));
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_EQ(parser->content_iv_size(), ContentKeyIVSize(iv_flag));
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_EQ(parser_->content_iv_size(), ContentKeyIVSize(iv_flag));
iv_flag = true;
ecm_data_[4] = kContentIVSizeFlag;
ecm_data_.resize(CalculateEcmSize(with_rotation, iv_flag));
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_EQ(parser->content_iv_size(), ContentKeyIVSize(iv_flag));
}
TEST_F(EcmParserTest, EcmWithSectionHeader) {
std::unique_ptr<const wvcas::EcmParser> parser;
std::vector<uint8_t> section_header;
section_header.resize(kSectionHeaderSize);
*reinterpret_cast<uint32_t*>(section_header.data()) = htons(kSectionHeader1);
// If ECM is prepended with section header, parsing must still work.
ecm_data_.insert(ecm_data_.begin(), section_header.begin(),
section_header.end());
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
*((uint16_t*)ecm_data_.data()) = htons(kSectionHeader2);
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
// Change header size, parsing should still work
ecm_data_.erase(ecm_data_.begin());
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_EQ(parser_->content_iv_size(), ContentKeyIVSize(iv_flag));
}
TEST_F(EcmParserTest, AgeRestriction) {
std::unique_ptr<const wvcas::EcmParser> parser;
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_EQ(0, parser->age_restriction());
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_EQ(0, parser_->age_restriction());
uint8_t age_restriction = 16;
ecm_data_[4] |= age_restriction << 1;
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser));
EXPECT_EQ(age_restriction, parser->age_restriction());
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
EXPECT_EQ(age_restriction, parser_->age_restriction());
}
// Verifies CAS ID returned by the parser must be expected ones.
class EcmParserCasIdTest
: public EcmParserTest,
public ::testing::WithParamInterface<::testing::tuple<uint16_t, bool>> {
protected:
void SetUp() override {
const uint16_t cas_id = ::testing::get<0>(GetParam());
BuildEcm(cas_id, /*with_rotation=*/true, /*content_iv_flag=*/false);
}
};
TEST_P(EcmParserCasIdTest, ValidateCasIds) {
bool expected_result = ::testing::get<1>(GetParam());
ASSERT_EQ(wvcas::EcmParser::create(ecm_data_, &parser_), expected_result);
}
INSTANTIATE_TEST_SUITE_P(EcmWithLegacyCasId, EcmParserCasIdTest,
::testing::Values(std::make_tuple(kWidevineCasId,
true)));
INSTANTIATE_TEST_SUITE_P(
EcmWithNewCasId, EcmParserCasIdTest,
::testing::Combine(
::testing::Range(static_cast<uint16_t>(kWidevineNewCasIdLowerBound),
static_cast<uint16_t>(kWidevineNewCasIdUpperBound +
1)),
::testing::Values(true)));
INSTANTIATE_TEST_SUITE_P(
EcmWithInvalidCasId, EcmParserCasIdTest,
::testing::Combine(::testing::Values(0, kWidevineCasId - 1,
kWidevineCasId + 1,
kWidevineNewCasIdLowerBound - 1,
kWidevineNewCasIdUpperBound + 1),
::testing::Values(false)));
// Verifies Section header and pointer field may be prepended to ECM.
class EcmParserSectionHeaderTest
: public EcmParserTest,
public ::testing::WithParamInterface<uint8_t> {};
TEST_P(EcmParserSectionHeaderTest, EcmWithSectionHeaderOnly) {
const std::vector<uint8_t> section_header = {GetParam(), 0, 0};
ecm_data_.insert(ecm_data_.begin(), section_header.begin(),
section_header.end());
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
}
TEST_P(EcmParserSectionHeaderTest, EcmWithSectionHeaderAndPointerField) {
const std::vector<uint8_t> section_header = {kPointerFieldZero, GetParam(), 0,
0};
ecm_data_.insert(ecm_data_.begin(), section_header.begin(),
section_header.end());
ASSERT_TRUE(wvcas::EcmParser::create(ecm_data_, &parser_));
}
INSTANTIATE_TEST_SUITE_P(EcmWithSectionHeader, EcmParserSectionHeaderTest,
::testing::Values(kSectionHeader1, kSectionHeader2));

View File

@@ -2,11 +2,14 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "license_key_status.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <vector>
#include "cas_types.h"
#include "license_key_status.h"
namespace wvcas {

View File

@@ -27,20 +27,30 @@ TEST(IntegrationTests, TestCasFactoryCreation) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestCasFactoryCreation"));
}
TEST(IntegrationTests, TestDescramblerFactoryCreation) {
EXPECT_EQ(kIntegrationTestPassed,
RunNamedTest("TestDescramblerFactoryCreation"));
}
TEST(IntegrationTests, TestCreateCasPlugin) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestCreateCasPlugin"));
}
TEST(IntegrationTests, TestCreateCasPluginWithNewCasIds) {
EXPECT_EQ(kIntegrationTestPassed,
RunNamedTest("TestCreateCasPluginWithNewCasIds"));
}
TEST(IntegrationTests, TestCreateCasPluginWithInvalidCasIds) {
EXPECT_EQ(kIntegrationTestPassed,
RunNamedTest("TestCreateCasPluginWithInvalidCasIds"));
}
TEST(IntegrationTests, TestCreateCasPluginWithSessionEvent) {
EXPECT_EQ(kIntegrationTestPassed,
RunNamedTest("TestCreateCasPluginWithSessionEvent"));
}
TEST(IntegrationTests, TestCreateCasPluginWithSessionEventWithNewCasIds) {
EXPECT_EQ(kIntegrationTestPassed,
RunNamedTest("TestCreateCasPluginWithSessionEventWithNewCasIds"));
}
TEST(IntegrationTests, TestCasPluginEventPassing) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestCasPluginEventPassing"));
}
@@ -63,11 +73,6 @@ TEST(IntegrationTests, TestCasEmmRequestWithPrivateData) {
RunNamedTest("TestCasEmmRequestWithPrivateData"));
}
TEST(IntegrationTests, TestCasPrivateDataWithGroupLicense) {
EXPECT_EQ(kIntegrationTestPassed,
RunNamedTest("TestCasPrivateDataWithGroupLicense"));
}
TEST(IntegrationTests, TestCasWithOfflineEMM) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestCasWithOfflineEMM"));
}
@@ -81,41 +86,17 @@ TEST(IntegrationTests, TestCasCanNotStoreOfflineEMM) {
RunNamedTest("TestCasCanNotStoreOfflineEMM"));
}
TEST(IntegrationTests, TestDescrambler) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestDescrambler"));
}
TEST(IntegrationTests, TestSession) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestSession"));
}
TEST(IntegrationTests, TestPESDecrypt) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestPESDecrypt"));
}
TEST(IntegrationTests, TestConcatentatedPESDecrypt) {
EXPECT_EQ(kIntegrationTestPassed,
RunNamedTest("TestConcatentatedPESDecrypt"));
}
TEST(IntegrationTests, TestPlaybackDecrypt) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestPlaybackDecrypt"));
}
TEST(IntegrationTests, TestCasRenewal) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestCasRenewal"));
}
TEST(IntegrationTests, TestRestoreRenewalAndExpiredLicense) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestRestoreRenewalAndExpiredLicense"));
}
TEST(IntegrationTests, TestPesHeaderDecrypt) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestPesHeaderDecrypt"));
}
TEST(IntegrationTests, TestPesHeaderDecryptInTSPacket) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestPesHeaderDecryptInTSPacket"));
EXPECT_EQ(kIntegrationTestPassed,
RunNamedTest("TestRestoreRenewalAndExpiredLicense"));
}
TEST(IntegrationTests, TestLicenseExpiration) {
@@ -134,10 +115,3 @@ TEST(IntegrationTests, TestSessionEventPassing) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestSessionEventPassing"));
}
TEST(IntegrationTests, TestTSDecrypt) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestTSDecrypt"));
}
TEST(IntegrationTests, TestTSDecryptWithKeyRotation) {
EXPECT_EQ(kIntegrationTestPassed, RunNamedTest("TestTSDecryptWithKeyRotation"));
}

View File

@@ -22,6 +22,7 @@ class MockCryptoSession : public wvcas::CryptoSession {
MOCK_METHOD2(GetKeyData,
wvcas::CasStatus(uint8_t* keyData, size_t* keyDataLength));
MOCK_METHOD0(supported_certificates, wvcas::SupportedCertificates());
MOCK_METHOD1(APIVersion, wvcas::CasStatus(uint32_t* api_version));
MOCK_METHOD1(GenerateNonce, wvcas::CasStatus(uint32_t* nonce));
MOCK_METHOD4(GenerateDerivedKeys,
wvcas::CasStatus(const uint8_t* mac_key_context,

View File

@@ -296,7 +296,8 @@ TEST_F(PolicyEngineTest, RenewalEvents) {
video_widevine::License_Policy* policy = license_.mutable_policy();
policy->set_license_duration_seconds(kLowDuration);
policy->set_can_renew(true);
policy->set_renewal_delay_seconds(kLicenseRenewalPeriod);;
policy->set_renewal_delay_seconds(kLicenseRenewalPeriod);
;
policy->set_renewal_retry_interval_seconds(kLicenseRenewalRetryInterval);
{
@@ -344,8 +345,7 @@ TEST_F(PolicyEngineTest, RenewalEvents) {
TEST_F(PolicyEngineTest, RenewalUrl) {
EXPECT_CALL(*policy_engine_.license_keys_, SetFromLicense(_));
EXPECT_CALL(*policy_engine_.clock_, GetCurrentTime());
EXPECT_CALL(*policy_engine_.license_keys_,
ApplyStatusChange(_, NotNull()));
EXPECT_CALL(*policy_engine_.license_keys_, ApplyStatusChange(_, NotNull()));
EXPECT_CALL(event_listener_, OnExpirationUpdate(_));
EXPECT_CALL(event_listener_,
OnNewRenewalServerUrl(::testing::StrEq(kRenewalServerUrl)));

View File

@@ -2,11 +2,12 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "timer.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "clock.h"
#include "timer.h"
class TimerTest : public wvutil::TimerHandler, public ::testing::Test {
public:

View File

@@ -2,17 +2,19 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "widevine_cas_api.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <memory>
#include <openssl/sha.h>
#include "cas_util.h"
#include <memory>
#include "cas_license.h"
#include "cas_util.h"
#include "ecm_parser.h"
#include "mock_crypto_session.h"
#include "string_conversions.h"
#include "widevine_cas_api.h"
#include "widevine_cas_session_map.h"
using ::testing::_;
@@ -22,6 +24,22 @@ using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::StrictMock;
namespace {
constexpr char kBasePathPrefix[] = "/data/vendor/mediacas/IDM/widevine/";
constexpr char kLicenseFileNameSuffix[] = ".lic";
// Generate mocked license filename.
std::string GenerateTestLicenseFileName(const std::string& mocked_file_name) {
std::string hash;
hash.resize(SHA256_DIGEST_LENGTH);
const auto* input =
reinterpret_cast<const unsigned char*>(mocked_file_name.data());
auto* output = reinterpret_cast<unsigned char*>(&hash[0]);
SHA256(input, mocked_file_name.size(), output);
return kBasePathPrefix + wvutil::b2a_hex(hash) + kLicenseFileNameSuffix;
}
} // namespace
typedef StrictMock<MockCryptoSession> StrictMockCryptoSession;
class MockLicense : public wvcas::CasLicense {
@@ -224,18 +242,20 @@ TEST_F(WidevineCasTest, generateEntitlementRequest) {
cas_api.initialize(nullptr).status_code());
// Invalid parameter.
std::string request, init_data;
EXPECT_NE(
wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest(init_data, nullptr).status_code());
std::string request, init_data, license_id;
EXPECT_EQ(wvcas::CasStatusCode::kInvalidParameter,
cas_api.generateEntitlementRequest(init_data, nullptr, license_id)
.status_code());
EXPECT_TRUE(license_id.empty());
// GenerateEntitlementRequest returns an error.
EXPECT_CALL(*cas_api.license_, GenerateEntitlementRequest(_, _, _, _, _))
.WillRepeatedly(Return(wvcas::CasStatus(
wvcas::CasStatusCode::kCasLicenseError, "forced failure")));
EXPECT_NE(
wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest(init_data, &request).status_code());
EXPECT_EQ(wvcas::CasStatusCode::kCasLicenseError,
cas_api.generateEntitlementRequest(init_data, &request, license_id)
.status_code());
EXPECT_TRUE(license_id.empty());
// HandleStoredLicense returns an error.
// Call to Open will return a unique_ptr, freeing this mock_file object.
@@ -252,13 +272,14 @@ TEST_F(WidevineCasTest, generateEntitlementRequest) {
EXPECT_CALL(*cas_api.license_, HandleStoredLicense(_, _))
.WillRepeatedly(Return(wvcas::CasStatus(
wvcas::CasStatusCode::kCasLicenseError, "forced failure")));
EXPECT_NE(
wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest(init_data, &request).status_code());
EXPECT_EQ(wvcas::CasStatusCode::kCasLicenseError,
cas_api.generateEntitlementRequest(init_data, &request, license_id)
.status_code());
EXPECT_TRUE(license_id.empty());
mock_file = new MockFile();
EXPECT_CALL(*cas_api.file_system_,
DoOpen(_, _)).WillRepeatedly(Return(mock_file));
EXPECT_CALL(*cas_api.file_system_, DoOpen(_, _))
.WillRepeatedly(Return(mock_file));
EXPECT_CALL(*mock_file, Read(_, _)).WillRepeatedly(Return(mock_filesize));
// For expired license file, remove it successfully
// and return CasLicenseError.
@@ -267,43 +288,54 @@ TEST_F(WidevineCasTest, generateEntitlementRequest) {
EXPECT_CALL(*cas_api.license_, IsExpired()).WillRepeatedly(Return(true));
EXPECT_CALL(*cas_api.file_system_, Remove(_)).WillRepeatedly(Return(true));
EXPECT_EQ(
wvcas::CasStatusCode::kCasLicenseError,
cas_api.generateEntitlementRequest(init_data, &request).status_code());
EXPECT_EQ(wvcas::CasStatusCode::kCasLicenseError,
cas_api.generateEntitlementRequest(init_data, &request, license_id)
.status_code());
EXPECT_TRUE(license_id.empty());
// Unable to remove the expired license file, return InvalidLicenseFile error.
mock_file = new MockFile();
EXPECT_CALL(*cas_api.file_system_,
DoOpen(_, _)).WillRepeatedly(Return(mock_file));
EXPECT_CALL(*cas_api.file_system_, DoOpen(_, _))
.WillRepeatedly(Return(mock_file));
EXPECT_CALL(*mock_file, Read(_, _)).WillRepeatedly(Return(mock_filesize));
// Unable to remove the expired license file, return InvalidLicenseFile error
EXPECT_CALL(*cas_api.file_system_, Remove(_)).WillOnce(Return(false));
EXPECT_EQ(
wvcas::CasStatusCode::kInvalidLicenseFile,
cas_api.generateEntitlementRequest(init_data, &request).status_code());
EXPECT_EQ(wvcas::CasStatusCode::kInvalidLicenseFile,
cas_api.generateEntitlementRequest(init_data, &request, license_id)
.status_code());
EXPECT_TRUE(license_id.empty());
// For stored license file not expired, return valid response.
mock_file = new MockFile();
EXPECT_CALL(*cas_api.file_system_,
DoOpen(_, _)).WillRepeatedly(Return(mock_file));
EXPECT_CALL(*cas_api.file_system_, DoOpen(_, _))
.WillRepeatedly(Return(mock_file));
EXPECT_CALL(*mock_file, Read(_, _)).WillRepeatedly(Return(mock_filesize));
// For stored license file not expired, return valid response
EXPECT_CALL(*cas_api.license_, IsExpired()).WillRepeatedly(Return(false));
EXPECT_EQ(
wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest(init_data, &request).status_code());
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest(init_data, &request, license_id)
.status_code());
// For existing license, license_id should be returned.
std::string full_filename =
GenerateTestLicenseFileName(/*mocked_file_name=*/"");
EXPECT_EQ(full_filename.substr(
0, full_filename.size() - strlen(kLicenseFileNameSuffix)),
license_id);
// Valid response for new request.
mock_file = new MockFile();
EXPECT_CALL(*cas_api.file_system_,
DoOpen(_, _)).WillRepeatedly(Return(mock_file));
EXPECT_CALL(*cas_api.file_system_, DoOpen(_, _))
.WillRepeatedly(Return(mock_file));
// Valid response for new request
license_id.clear();
EXPECT_CALL(*cas_api.file_system_, Exists(_)).WillRepeatedly(Return(false));
EXPECT_CALL(*cas_api.license_, GenerateEntitlementRequest(_, _, _, _, _))
.WillRepeatedly(Return(wvcas::CasStatus::OkStatus()));
EXPECT_EQ(
wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest(init_data, &request).status_code());
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest(init_data, &request, license_id)
.status_code());
// For the first time license request, the license_id will be returned empty.
EXPECT_TRUE(license_id.empty());
}
TEST_F(WidevineCasTest, GenerateLicenseRenewal) {
@@ -343,13 +375,15 @@ TEST_F(WidevineCasTest, EntitlementRenewalResponse) {
// Empty response.
std::string init_data;
EXPECT_EQ(wvcas::CasStatusCode::kCasLicenseError,
cas_api.handleEntitlementRenewalResponse("", init_data).status_code());
EXPECT_EQ(
wvcas::CasStatusCode::kCasLicenseError,
cas_api.handleEntitlementRenewalResponse("", init_data).status_code());
// Valid.
EXPECT_CALL(*cas_api.license_, HandleEntitlementRenewalResponse(_, _));
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
cas_api.handleEntitlementRenewalResponse("response", init_data).status_code());
cas_api.handleEntitlementRenewalResponse("response", init_data)
.status_code());
}
TEST_F(WidevineCasTest, RemoveExpiredLicenseInTimerEvent) {
@@ -370,18 +404,20 @@ TEST_F(WidevineCasTest, RemoveExpiredLicenseInTimerEvent) {
EXPECT_CALL(*cas_api.license_, GenerateEntitlementRequest(_, _, _, _, _))
.WillRepeatedly(Return(wvcas::CasStatus::OkStatus()));
std::string request, init_data;
EXPECT_EQ(
wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest(init_data, &request).status_code());
std::string request, init_data, license_id;
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest(init_data, &request, license_id)
.status_code());
// Valid: License is expired then start to remove.
EXPECT_TRUE(license_id.empty());
EXPECT_CALL(*cas_api.license_, IsExpired()).WillOnce(Return(true));
EXPECT_CALL(*cas_api.file_system_, Exists(_)).WillRepeatedly(Return(true));
EXPECT_CALL(*cas_api.file_system_, Remove(_)).WillOnce(Return(true));
cas_api.OnTimerEvent();
// Valid: License is expired but now it does not exist on file system.
EXPECT_TRUE(license_id.empty());
EXPECT_CALL(*cas_api.license_, IsExpired()).WillOnce(Return(true));
EXPECT_CALL(*cas_api.file_system_, Exists(_)).WillOnce(Return(false));
EXPECT_CALL(*cas_api.file_system_, Remove(_)).Times(0);
@@ -462,29 +498,36 @@ TEST_P(WidevineCasTest, ECMProcessing) {
.Times(expected_begin_decryption_calls);
if (test_stored_license) {
std::string request;
std::string file("license_file");
std::string request, license_id;
std::string file_data("license_file");
EXPECT_CALL(*cas_api.file_system_, Exists(_)).WillOnce(Return(true));
EXPECT_CALL(*cas_api.file_system_, FileSize(_))
.WillOnce(Return(file.size()));
.WillOnce(Return(file_data.size()));
auto* file_handle = new NiceMock<MockFile>;
EXPECT_CALL(*cas_api.file_system_, DoOpen(_, _))
.WillOnce(Return(file_handle));
EXPECT_CALL(*file_handle, Read(_, _)).WillOnce(Return(file.size()));
EXPECT_CALL(*file_handle, Read(_, _)).WillOnce(Return(file_data.size()));
EXPECT_CALL(*cas_api.license_, HandleStoredLicense(_, _));
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest("init_data", &request)
.status_code());
EXPECT_EQ(
wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest("init_data", &request, license_id)
.status_code());
// For existing license, license_id should be returned.
std::string full_filename =
GenerateTestLicenseFileName(/*mocked_file_name=*/"");
EXPECT_EQ(full_filename.substr(
0, full_filename.size() - strlen(kLicenseFileNameSuffix)),
license_id);
} else {
// Empty response.
std::string init_data;
EXPECT_CALL(*cas_api.license_, HandleEntitlementResponse(_, _))
.WillOnce(Return(wvcas::CasStatusCode::kNoError));
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
cas_api.handleEntitlementResponse("response", init_data)
.status_code());
EXPECT_EQ(
wvcas::CasStatusCode::kNoError,
cas_api.handleEntitlementResponse("response", init_data).status_code());
}
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
@@ -506,23 +549,25 @@ TEST_F(WidevineCasTest, RemoveLicense) {
TestWidevineCas cas_api;
EXPECT_CALL(*cas_api.crypto_session_, initialize())
.WillOnce(Return(wvcas::CasStatus::OkStatus()));
.WillOnce(Return(wvcas::CasStatus::OkStatus()));
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
cas_api.initialize(nullptr).status_code());
cas_api.initialize(nullptr).status_code());
// mediaId is not initialized.
std::string mocked_file_name;
EXPECT_EQ(wvcas::CasStatusCode::kCasLicenseError,
cas_api.RemoveLicense(mocked_file_name).status_code());
cas_api.RemoveLicense(mocked_file_name).status_code());
// CasMediaId has been initialized.
EXPECT_CALL(*cas_api.file_system_, Exists(_)).WillOnce(Return(false));
EXPECT_CALL(*cas_api.license_, GenerateEntitlementRequest(_, _, _, _, _))
.WillRepeatedly(Return(wvcas::CasStatus::OkStatus()));
std::string request, init_data;
std::string request, init_data, license_id;
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
cas_api.generateEntitlementRequest(init_data, &request)
.status_code());
cas_api.generateEntitlementRequest(init_data, &request, license_id)
.status_code());
// For the first time license request, the license_id will be returned empty.
EXPECT_TRUE(license_id.empty());
// Unable to remove license file, return InvalidLicenseFile error.
EXPECT_CALL(*cas_api.file_system_, Exists(_)).WillOnce(Return(true));
@@ -535,15 +580,17 @@ TEST_F(WidevineCasTest, RemoveLicense) {
MockFile mock_file;
size_t mock_filesize = 10;
EXPECT_CALL(*cas_api.file_system_, Exists(_)).WillRepeatedly(Return(true));
EXPECT_CALL(*cas_api.file_system_, FileSize(_)).WillRepeatedly(Return(mock_filesize));
EXPECT_CALL(*cas_api.file_system_, DoOpen(_, _)).WillRepeatedly(Return(&mock_file));
EXPECT_CALL(*cas_api.file_system_, FileSize(_))
.WillRepeatedly(Return(mock_filesize));
EXPECT_CALL(*cas_api.file_system_, DoOpen(_, _))
.WillRepeatedly(Return(&mock_file));
EXPECT_CALL(mock_file, Read(_, _)).WillRepeatedly(Return(mock_filesize));
EXPECT_CALL(mock_file, Close()).WillRepeatedly(Return());
EXPECT_CALL(*cas_api.file_system_, Remove(_)).WillRepeatedly(Return(true));
EXPECT_CALL(*cas_api.license_, UpdateLicenseForLicenseRemove()).Times(0);
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
cas_api.RemoveLicense(mocked_file_name).status_code());
cas_api.RemoveLicense(mocked_file_name).status_code());
// Happy case: remove the in used license file
std::string hash;
@@ -553,10 +600,8 @@ TEST_F(WidevineCasTest, RemoveLicense) {
reinterpret_cast<const unsigned char*>(mocked_file_name.data());
auto* output = reinterpret_cast<unsigned char*>(&hash[0]);
SHA256(input, mocked_file_name.size(), output);
std::string full_file_name = kBasePathPrefix + wvutil::b2a_hex(hash)
+ std::string(".lic");
std::string full_filename = GenerateTestLicenseFileName(mocked_file_name);
EXPECT_CALL(*cas_api.license_, UpdateLicenseForLicenseRemove()).Times(1);
EXPECT_EQ(wvcas::CasStatusCode::kNoError,
cas_api.RemoveLicense(full_file_name).status_code());
cas_api.RemoveLicense(full_filename).status_code());
}

View File

@@ -2,6 +2,8 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "widevine_cas_session.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -12,7 +14,6 @@
#include "cas_util.h"
#include "mock_crypto_session.h"
#include "string_conversions.h"
#include "widevine_cas_session.h"
using ::testing::_;
using ::testing::DoAll;
@@ -202,8 +203,8 @@ std::unique_ptr<const wvcas::EcmParser> TestCasSession::getEcmParser(
std::unique_ptr<NiceMock<MockEcmParser>> mock_ecm_parser(
new NiceMock<MockEcmParser>);
ON_CALL(*mock_ecm_parser, sequence_count()).WillByDefault(Return(0));
ON_CALL(*mock_ecm_parser, age_restriction()).WillByDefault(Return(
age_restriction_));
ON_CALL(*mock_ecm_parser, age_restriction())
.WillByDefault(Return(age_restriction_));
ON_CALL(*mock_ecm_parser, crypto_mode())
.WillByDefault(Return(wvcas::CryptoMode::kAesCTR));
ON_CALL(*mock_ecm_parser, rotation_enabled()).WillByDefault(Return(true));
@@ -234,9 +235,8 @@ TEST_F(CasSessionTest, processEcm) {
EXPECT_EQ(session_id, kEntitledKeySessionId);
wvcas::CasEcm ecm(184);
EXPECT_CALL(*mock,
LoadCasECMKeys(session_id, IsValidKeyEvenSlotData(),
IsValidKeyOddSlotData()));
EXPECT_CALL(*mock, LoadCasECMKeys(session_id, IsValidKeyEvenSlotData(),
IsValidKeyOddSlotData()));
session.processEcm(ecm, 0);
EXPECT_CALL(*mock, RemoveEntitledKeySession(session_id));
}
@@ -256,7 +256,7 @@ TEST_F(CasSessionTest, parentalControl) {
EXPECT_CALL(*mock, LoadCasECMKeys(session_id, IsValidKeyEvenSlotData(),
IsValidKeyOddSlotData()));
wvcas::CasEcm ecm(184);
session.set_age_restriction(0); // No restriction.
session.set_age_restriction(0); // No restriction.
// Different Ecm to make sure processEcm() processes this ecm.
std::generate(ecm.begin(), ecm.end(), std::rand);
ASSERT_EQ(wvcas::CasStatusCode::kNoError,

View File

@@ -3,6 +3,7 @@
// License Agreement.
#include <gtest/gtest.h>
#include <iostream>
#include "OEMCryptoCAS.h"