Source release 16.3.0

This commit is contained in:
John W. Bruce
2020-07-24 14:30:03 -07:00
parent b830b1d1fb
commit 160df9f57a
74 changed files with 4632 additions and 2561 deletions

View File

@@ -38,6 +38,8 @@ class MockCdmClientPropertySet : public CdmClientPropertySet {
MOCK_CONST_METHOD0(is_session_sharing_enabled, bool());
MOCK_CONST_METHOD0(session_sharing_id, uint32_t());
MOCK_METHOD1(set_session_sharing_id, void(uint32_t));
MOCK_CONST_METHOD0(use_atsc_mode, bool());
MOCK_METHOD1(set_use_atsc_mode, void(bool));
MOCK_CONST_METHOD0(app_id, const std::string&());
};
@@ -76,13 +78,13 @@ class MockCdmEngineImpl : public CdmEngine {
MOCK_METHOD1(RemoveKeys, CdmResponseType(const CdmSessionId&));
MOCK_METHOD2(QueryKeyStatus,
CdmResponseType(const CdmSessionId&, CdmQueryMap*));
MOCK_METHOD5(GetProvisioningRequest,
MOCK_METHOD6(GetProvisioningRequest,
CdmResponseType(CdmCertificateType, const std::string&,
const std::string&, CdmProvisioningRequest*,
std::string*));
MOCK_METHOD3(HandleProvisioningResponse,
CdmResponseType(const CdmProvisioningResponse&, std::string*,
std::string*));
const std::string&, SecurityLevel,
CdmProvisioningRequest*, std::string*));
MOCK_METHOD4(HandleProvisioningResponse,
CdmResponseType(const CdmProvisioningResponse&, SecurityLevel,
std::string*, std::string*));
MOCK_METHOD1(Unprovision, CdmResponseType(CdmSecurityLevel));
MOCK_METHOD4(ListUsageIds,
CdmResponseType(const std::string&, CdmSecurityLevel,
@@ -311,16 +313,17 @@ TEST_F(WvCdmEngineMetricsImplTest, GetProvisioningRequest) {
std::string default_url;
EXPECT_CALL(*test_cdm_metrics_engine_,
GetProvisioningRequest(Eq(kCertificateX509),
Eq("fake certificate authority"),
Eq("fake service certificate"),
Eq(&request), Eq(&default_url)))
GetProvisioningRequest(
Eq(kCertificateX509), Eq("fake certificate authority"),
Eq("fake service certificate"), Eq(wvcdm::kLevelDefault),
Eq(&request), Eq(&default_url)))
.WillOnce(Return(wvcdm::UNKNOWN_ERROR));
ASSERT_EQ(wvcdm::UNKNOWN_ERROR,
test_cdm_metrics_engine_->GetProvisioningRequest(
kCertificateX509, "fake certificate authority",
"fake service certificate", &request, &default_url));
"fake service certificate", wvcdm::kLevelDefault, &request,
&default_url));
drm_metrics::WvCdmMetrics metrics_proto;
test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto);
@@ -340,12 +343,14 @@ TEST_F(WvCdmEngineMetricsImplTest, HandleProvisioningResponse) {
EXPECT_CALL(*test_cdm_metrics_engine_,
HandleProvisioningResponse(Eq("fake provisioning response"),
Eq(&cert), Eq(&wrapped_key)))
Eq(wvcdm::kLevelDefault), Eq(&cert),
Eq(&wrapped_key)))
.WillOnce(Return(wvcdm::UNKNOWN_ERROR));
ASSERT_EQ(wvcdm::UNKNOWN_ERROR,
test_cdm_metrics_engine_->HandleProvisioningResponse(
"fake provisioning response", &cert, &wrapped_key));
"fake provisioning response", wvcdm::kLevelDefault, &cert,
&wrapped_key));
drm_metrics::WvCdmMetrics metrics_proto;
test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto);

View File

@@ -114,8 +114,8 @@ class MockDeviceFiles : public DeviceFiles {
MockDeviceFiles() : DeviceFiles(nullptr) {}
MOCK_METHOD1(Init, bool(CdmSecurityLevel));
MOCK_METHOD4(RetrieveCertificate,
bool(std::string*, std::string*, std::string*, uint32_t*));
MOCK_METHOD5(RetrieveCertificate,
bool(bool, std::string*, std::string*, std::string*, uint32_t*));
};
class MockUsageTableHeader : public UsageTableHeader {
@@ -217,8 +217,8 @@ TEST_F(CdmSessionTest, InitWithBuiltInCertificate) {
EXPECT_CALL(*crypto_session_, GetPreProvisionTokenType())
.WillOnce(Return(kClientTokenDrmCert));
EXPECT_CALL(*file_handle_,
RetrieveCertificate(NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
Return(true)));
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
.InSequence(crypto_session_seq)
@@ -245,8 +245,8 @@ TEST_F(CdmSessionTest, InitWithCertificate) {
.WillOnce(Return(kClientTokenKeybox));
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
EXPECT_CALL(*file_handle_,
RetrieveCertificate(NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
Return(true)));
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
.InSequence(crypto_session_seq)
@@ -272,8 +272,8 @@ TEST_F(CdmSessionTest, ReInitFail) {
.WillOnce(Return(kClientTokenKeybox));
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
EXPECT_CALL(*file_handle_,
RetrieveCertificate(NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
Return(true)));
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
.InSequence(crypto_session_seq)
@@ -307,7 +307,7 @@ TEST_F(CdmSessionTest, InitNeedsProvisioning) {
.WillOnce(Return(kClientTokenKeybox));
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
EXPECT_CALL(*file_handle_,
RetrieveCertificate(NotNull(), NotNull(), NotNull(), _))
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
.WillOnce(Return(false));
ASSERT_EQ(NEED_PROVISIONING, cdm_session_->Init(nullptr));
@@ -327,8 +327,8 @@ TEST_F(CdmSessionTest, UpdateUsageEntry) {
.WillOnce(Return(kClientTokenKeybox));
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
EXPECT_CALL(*file_handle_,
RetrieveCertificate(NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
Return(true)));
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
.InSequence(crypto_session_seq)

View File

@@ -40,16 +40,19 @@ class MockCryptoSession : public TestCryptoSession {
MockCryptoSession(metrics::CryptoMetrics* metrics)
: TestCryptoSession(metrics) {}
MOCK_METHOD1(Open, CdmResponseType(SecurityLevel));
MOCK_METHOD1(LoadUsageTableHeader,
CdmResponseType(const CdmUsageTableHeader&));
MOCK_METHOD1(CreateUsageTableHeader, CdmResponseType(CdmUsageTableHeader*));
// Usage Table Header.
MOCK_METHOD2(CreateUsageTableHeader,
CdmResponseType(SecurityLevel, CdmUsageTableHeader*));
MOCK_METHOD2(LoadUsageTableHeader,
CdmResponseType(SecurityLevel, const CdmUsageTableHeader&));
MOCK_METHOD3(ShrinkUsageTableHeader,
CdmResponseType(SecurityLevel, uint32_t, CdmUsageTableHeader*));
// Usage Entry.
MOCK_METHOD1(CreateUsageEntry, CdmResponseType(uint32_t*));
MOCK_METHOD2(LoadUsageEntry, CdmResponseType(uint32_t, const CdmUsageEntry&));
MOCK_METHOD2(UpdateUsageEntry,
CdmResponseType(CdmUsageTableHeader*, CdmUsageEntry*));
MOCK_METHOD1(MoveUsageEntry, CdmResponseType(uint32_t));
MOCK_METHOD2(ShrinkUsageTableHeader,
CdmResponseType(uint32_t, CdmUsageTableHeader*));
};
class TestStubCryptoSessionFactory : public CryptoSessionFactory {
@@ -62,18 +65,19 @@ class TestStubCryptoSessionFactory : public CryptoSessionFactory {
using ::testing::_;
class CertificateProvisioningTest : public WvCdmTestBase {
public:
protected:
void SetUp() override {
WvCdmTestBase::SetUp();
CryptoSession::SetCryptoSessionFactory(new TestStubCryptoSessionFactory());
metrics_.reset(new metrics::CryptoMetrics());
certificate_provisioning_.reset(
new CertificateProvisioning(new metrics::CryptoMetrics()));
new CertificateProvisioning(metrics_.get()));
}
void TearDown() override {}
std::unique_ptr<metrics::CryptoMetrics> metrics_;
std::unique_ptr<CertificateProvisioning> certificate_provisioning_;
};

View File

@@ -316,8 +316,6 @@ TEST_F(CryptoSessionMetricsTest, OpenSessionValidMetrics) {
EXPECT_EQ(OEMCrypto_Keybox,
metrics_proto.oemcrypto_provisioning_method().int_value());
EXPECT_EQ(1, metrics_proto.oemcrypto_get_key_data_time_us().size());
EXPECT_EQ(
1u, metrics_proto.oemcrypto_get_key_data_time_us(0).operation_count());
} else if (token_type == kClientTokenOemCert) {
// Recent devices all have a system id between 1k and 6 or 7k. Errors
// we are trying to catch are 0, byte swapped 32 bit numbers, or
@@ -365,8 +363,6 @@ TEST_F(CryptoSessionMetricsTest, GetProvisioningTokenValidMetrics) {
uint32_t system_id = FindKeyboxSystemID();
EXPECT_EQ(system_id, metrics_proto.crypto_session_system_id().int_value());
EXPECT_EQ(1, metrics_proto.oemcrypto_get_key_data_time_us().size());
EXPECT_EQ(
2u, metrics_proto.oemcrypto_get_key_data_time_us(0).operation_count());
} else if (token_type == kClientTokenOemCert) {
// Recent devices all have a system id between 1k and 6 or 7k. Errors
// we are trying to catch are 0, byte swapped 32 bit numbers, or

View File

@@ -9,6 +9,7 @@
#include <memory>
#include <string>
#include <vector>
#include "arraysize.h"
#include "cdm_random.h"
@@ -25,34 +26,31 @@ namespace {
const uint32_t kCertificateLen = 700;
const uint32_t kWrappedKeyLen = 500;
const uint32_t kProtobufEstimatedOverhead = 200;
const std::string kEmptyString;
// Structurally valid test certificate.
// The data elements in this module are used to test the storage and
// retrieval of certificates and licenses
const std::string kTestCertificate =
"124B035F3D256A656F0E505A085E7A6C482B61035E0C4A540F7803137F4C3B45206B7F33"
"347F4D7A005E56400F0955011F4E07072D0D46781817460974326A516E3944385760280E"
"4F166B380F033D045231201E6146041C3A6F01345C59300D32592732192C0F2310586306"
"7B31467B1477010D6F1D1944272509572A26217E1E6F7B666F46153E7749106E48760468"
"19467E164A731773155B3236537D5128682014174D125063380E48356A370B5015416A7F"
"672F132E37364E154B41540F440E47092775531508495F1E55576F363C0C190C3A332179"
"415B343905563E37645E68007053315A1A20286E7C3B4320424A5F7F36635558686C3565"
"762122237D344A411C0F00342135776753461D105C21111E5024434E5E0F275D12061658"
"4435410F210E5228532D214F505D0F0B3C34032C7C597F6159665E664C682C5A6C03212E"
"71333C3A642D796A65642E151827086E2D671C130B172C43192C792D294440630163526D"
"0658537A073E0F32231E7426593230692A4468386D3511542F1A6F71440128466E510445"
"294F4465113D1B1A711D4D67691363093B680854322B041C2F72524A513E5F0E407C6233"
"1728520E6C0C09107C26737B78287231661952283619647A6241391940297D2067036D44"
"3C64766918236C51175A636F000A2E5A4C5B725D5500652B1C39283037723F0255092976"
"6F2D204F0E616F1233206B75661B0F755E1E3807491079663A191C0B2D5E363B3768663A"
"4E222A1D32015D3D783E5148313F05713B140347231C59243648313C23770F554E012715"
"3350597775274A580306202E65265957291F490F642A2E7C6700716400617C7E6A303266"
"523B102906195E003C2D111A7D4740122C6941003726602B59263B5C09473D4E025E3541"
"701B122D340A3D145436137002687E4C470D2F6F4C357A3245384D737B734E2274301179"
"402473486311156E5A0C78644C593273";
const std::string kTestCertificate = a2bs_hex(
"0A98030802120D73657269616C5F6E756D62657218B4B2CDE00422E8024D49494243674B43"
"415145412B78475A2F77637A39756746705030374E73706F365531376C3059684669467078"
"78553470546B334C69667A3952337A734973754552777461372B66574966784F6F32303865"
"74742F6A68736B69566F645345743351424768345842697079576F704B775A393348486144"
"565A41414C692F32412B785442745764456F37584755756A4B447643322F615A4B756B666A"
"704F6955493841684C41666A6D6C63442F555A31515068306D4873676C524E436D7043776D"
"7753584139564E6D687A2B5069422B446D6C3457576E4B572F56486F32756A54587871372B"
"65664D55344832666E79335365334B594F73465046475A31544E5153596C46755368577248"
"5074694C6D5564506F50364356326D4D4C31746B2B6C3744494971587251684C554B444143"
"654D35726F4D78306B4C6855574238502B30756A31434E6C4E4E344A525A6C433778466671"
"694D62465255395A344E3659774944415141422899203A11746573742E7769646576696E65"
"2E636F6D128202307836353063396632653637303165336665373364333035343930346139"
"61346262646239363733336631633463373433656635373361643661633134633561336266"
"38613437333166366536323736666165613532343733303336373766623864626466323466"
"66373865353363323530353263646361383765656366656538353437366263623861303563"
"62396131656665663763623837646436383232336531313763653830306163343631373731"
"37323534343735376134383762653332663561623866653038373966613861646437386265"
"34363565613866386435616366393737653966316165333664346434373831366561366564"
"343133373262");
// A Wrapped Private Key
// The data elements in this module are used to test the storage and
@@ -76,42 +74,54 @@ const std::string kTestWrappedPrivateKey =
// The test certificate in file storage format.
// The data elements in this module are used to test the storage and
// retrieval of certificates and licenses
const std::string kTestCertificateFileData =
"0ABD09080110011AB6090ABC05124B035F3D256A656F0E505A085E7A6C482B61035E0C4A"
"540F7803137F4C3B45206B7F33347F4D7A005E56400F0955011F4E07072D0D4678181746"
"0974326A516E3944385760280E4F166B380F033D045231201E6146041C3A6F01345C5930"
"0D32592732192C0F23105863067B31467B1477010D6F1D1944272509572A26217E1E6F7B"
"666F46153E7749106E4876046819467E164A731773155B3236537D5128682014174D1250"
"63380E48356A370B5015416A7F672F132E37364E154B41540F440E47092775531508495F"
"1E55576F363C0C190C3A332179415B343905563E37645E68007053315A1A20286E7C3B43"
"20424A5F7F36635558686C3565762122237D344A411C0F00342135776753461D105C2111"
"1E5024434E5E0F275D120616584435410F210E5228532D214F505D0F0B3C34032C7C597F"
"6159665E664C682C5A6C03212E71333C3A642D796A65642E151827086E2D671C130B172C"
"43192C792D294440630163526D0658537A073E0F32231E7426593230692A4468386D3511"
"542F1A6F71440128466E510445294F4465113D1B1A711D4D67691363093B680854322B04"
"1C2F72524A513E5F0E407C62331728520E6C0C09107C26737B7828723166195228361964"
"7A6241391940297D2067036D443C64766918236C51175A636F000A2E5A4C5B725D550065"
"2B1C39283037723F02550929766F2D204F0E616F1233206B75661B0F755E1E3807491079"
"663A191C0B2D5E363B3768663A4E222A1D32015D3D783E5148313F05713B140347231C59"
"243648313C23770F554E0127153350597775274A580306202E65265957291F490F642A2E"
"7C6700716400617C7E6A303266523B102906195E003C2D111A7D4740122C694100372660"
"2B59263B5C09473D4E025E3541701B122D340A3D145436137002687E4C470D2F6F4C357A"
"3245384D737B734E2274301179402473486311156E5A0C78644C59327312F4034F724B06"
"5326371A2F5F6F51467C2E26555C453B5C7C1B4F2738454B782E3E7B5340435A66374D06"
"12052C521A233D7A67194871751C78575E5177070130264C4F037633320E667B1A491929"
"24491338693D106E6113014A733A241A1A033E28352178146B4F543D38104A5919120325"
"502C31365506096D59585E08774B5B567A7B5D03451E6B11633E52672C226103104B3E4C"
"031A6403050F3A574D2C501711773802741F7F3A0D364757101D02181C7D4D3520716750"
"6A424C094E4A72316F791F162D76657D2B5D3C2D7B273A2869277175613165187E552824"
"30491467086425432347701C3116446D21645C756B2D3D0F797C3220322D622A254D0B7D"
"4F1D5D0C0A36755D1246741A34783C45157247091C78232B7D2E0E1F637A2A3739085D76"
"166747034350613969072F5B5C5B21657E470C7E513B3F091D74455A3A0737057B7E3B53"
"37191D4E7536087C334B6028530F3F5B23380B6A076031294501003D6D1F240F63053D5D"
"0B271B6A0F26185650731308660B0447566041684F584C22216E567D3B7755695F7F3D6B"
"64525E7227165948101540243C19495C4C702F37490F2661335379782562414326304302"
"0E1E6760123D51056F2F1E482F2E3D021B27677D3E7E3C0C11757C3448275E08382E1112"
"63644C6D224714706D760A054A586E17505C3429575A41043F1842091220F8D0A23D4B1B"
"C7B23A38B921BC1EA8938D1FD22FF9A389B58DA856A3E2625F27";
const std::string kTestCertificateFileData = a2bs_hex(
"0A950D080110011A8E0D0AA0050A98030802120D73657269616C5F6E756D62657218B4B2CD"
"E00422E8024D49494243674B43415145412B78475A2F77637A39756746705030374E73706F"
"365531376C305968466946707878553470546B334C69667A3952337A734973754552777461"
"372B66574966784F6F3230386574742F6A68736B69566F6453457433514247683458426970"
"79576F704B775A393348486144565A41414C692F32412B785442745764456F37584755756A"
"4B447643322F615A4B756B666A704F6955493841684C41666A6D6C63442F555A3151506830"
"6D4873676C524E436D7043776D7753584139564E6D687A2B5069422B446D6C3457576E4B57"
"2F56486F32756A54587871372B65664D55344832666E79335365334B594F73465046475A31"
"544E5153596C467553685772485074694C6D5564506F50364356326D4D4C31746B2B6C3744"
"494971587251684C554B444143654D35726F4D78306B4C6855574238502B30756A31434E6C"
"4E4E344A525A6C433778466671694D62465255395A344E3659774944415141422899203A11"
"746573742E7769646576696E652E636F6D1282023078363530633966326536373031653366"
"65373364333035343930346139613462626462393637333366316334633734336566353733"
"61643661633134633561336266386134373331663665363237366661656135323437333033"
"36373766623864626466323466663738653533633235303532636463613837656563666565"
"38353437366263623861303563623961316566656637636238376464363832323365313137"
"63653830306163343631373731373235343437353761343837626533326635616238666530"
"38373966613861646437386265343635656138663864356163663937376539663161653336"
"6434643437383136656136656434313337326212E807344637323442303635333236333731"
"41324635463646353134363743324532363535354334353342354337433142344632373338"
"34353442373832453345374235333430343335413636333734443036313230353243353231"
"41323333443741363731393438373137353143373835373545353137373037303133303236"
"34433446303337363333333230453636374231413439313932393234343931333338363933"
"44313036453631313330313441373333413234314131413033334532383335323137383134"
"36423446353433443338313034413539313931323033323535303243333133363535303630"
"39364435393538354530383737344235423536374137423544303334353145364231313633"
"33453532363732433232363130333130344233453443303331413634303330353046334135"
"37344432433530313731313737333830323734314637463341304433363437353731303144"
"30323138314337443444333532303731363735303641343234433039344534413732333136"
"46373931463136324437363635374432423544334332443742323733413238363932373731"
"37353631333136353138374535353238323433303439313436373038363432353433323334"
"37373031433331313634343644323136343543373536423244334430463739374333323230"
"33323244363232413235344430423744344631443544304330413336373535443132343637"
"34314133343738334334353135373234373039314337383233324237443245304531463633"
"37413241333733393038354437363136363734373033343335303631333936393037324635"
"42354335423231363537453437304337453531334233463039314437343435354133413037"
"33373035374237453342353333373139314434453735333630383743333334423630323835"
"33304633463542323333383042364130373630333132393435303130303344364431463234"
"30463633303533443544304232373142364130463236313835363530373331333038363630"
"42303434373536363034313638344635383443323232313645353637443342373735353639"
"35463746334436423634353235453732323731363539343831303135343032343343313934"
"39354334433730324633373439304632363631333335333739373832353632343134333236"
"33303433303230453145363736303132334435313035364632463145343832463245334430"
"32314232373637374433453745334330433131373537433334343832373545303833383245"
"31313132363336343443364432323437313437303644373630413035344135383645313735"
"303543333432393537354134313034334631383432303912205C6993E9656F73A41739773A"
"0FCBA8AE232CD8856ACE585FF6BFB2A09C20061E");
struct LicenseInfo {
std::string key_set_id;
@@ -2014,6 +2024,7 @@ class MockFileSystem : public FileSystem {
// gmock methods
using ::testing::_;
using ::testing::AllArgs;
using ::testing::AllOf;
using ::testing::DoAll;
using ::testing::Eq;
@@ -2075,9 +2086,9 @@ class DeviceFilesTest : public ::testing::Test {
class DeviceFilesStoreTest : public DeviceFilesTest,
public ::testing::WithParamInterface<bool> {};
class DeviceCertificateStoreTest : public DeviceFilesTest {};
class DeviceCertificateTest : public DeviceFilesTest {};
class DeviceCertificateTest
: public DeviceFilesTest,
public ::testing::WithParamInterface<bool /* atsc mode */> {};
class DeviceFilesSecurityLevelTest
: public DeviceFilesTest,
@@ -2102,103 +2113,35 @@ class DeviceFilesDeleteMultipleUsageInfoTest
public ::testing::WithParamInterface<int> {};
MATCHER(IsCreateFileFlagSet, "") { return FileSystem::kCreate & arg; }
MATCHER_P(IsStrEq, str, "") {
// Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1
return memcmp(arg, str.c_str(), str.size()) == 0;
MATCHER_P(StrAndLenEq, str, "") {
const std::string data(std::get<0>(arg), std::get<1>(arg));
return data == str;
}
MATCHER_P(ContainsAllElementsInVector, str_vector, "") {
// Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1
size_t str_length = 0;
for (size_t i = 0; i < str_vector.size(); ++i) {
str_length += str_vector[i].size();
}
std::string data(arg, str_length + kProtobufEstimatedOverhead);
bool all_entries_found = true;
for (size_t i = 0; i < str_vector.size(); ++i) {
if (data.find(str_vector[i]) == std::string::npos) {
all_entries_found = false;
MATCHER_P(StrAndLenContains, str_vector, "") {
const std::string data(std::get<0>(arg), std::get<1>(arg));
for (const std::string& str : str_vector) {
if (data.find(str) == std::string::npos) {
return false;
}
}
return all_entries_found;
}
MATCHER_P2(Contains, str1, size, "") {
// Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1
std::string data(arg, size + str1.size() + kProtobufEstimatedOverhead);
return (data.find(str1) != std::string::npos);
}
MATCHER_P3(Contains, str1, str2, size, "") {
// Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1
std::string data(
arg, size + str1.size() + str2.size() + kProtobufEstimatedOverhead);
return (data.find(str1) != std::string::npos &&
data.find(str2) != std::string::npos);
}
MATCHER_P4(Contains, str1, str2, str3, size, "") {
// Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1
std::string data(arg, size + str1.size() + str2.size() + str3.size() +
kProtobufEstimatedOverhead);
return (data.find(str1) != std::string::npos &&
data.find(str2) != std::string::npos &&
data.find(str3) != std::string::npos);
}
MATCHER_P6(Contains, str1, str2, str3, str4, str5, size, "") {
// Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1
std::string data(arg, size + str1.size() + str2.size() + str3.size() +
str4.size() + str5.size() +
kProtobufEstimatedOverhead);
return (data.find(str1) != std::string::npos &&
data.find(str2) != std::string::npos &&
data.find(str3) != std::string::npos &&
data.find(str4) != std::string::npos &&
data.find(str5) != std::string::npos);
}
MATCHER_P8(Contains, str1, str2, str3, str4, str5, str6, map7, str8, "") {
// Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1
size_t map7_len = 0;
CdmAppParameterMap::const_iterator itr = map7.begin();
for (itr = map7.begin(); itr != map7.end(); ++itr) {
map7_len += itr->first.length();
map7_len += itr->second.length();
}
std::string data(arg, str1.size() + str2.size() + str3.size() + str4.size() +
str5.size() + str6.size() + map7_len + str8.size() +
kProtobufEstimatedOverhead);
bool map7_entries_present = true;
for (itr = map7.begin(); itr != map7.end(); ++itr) {
map7_entries_present = map7_entries_present &&
data.find(itr->first) != std::string::npos &&
data.find(itr->second) != std::string::npos;
}
return (data.find(str1) != std::string::npos &&
data.find(str2) != std::string::npos &&
data.find(str3) != std::string::npos &&
data.find(str4) != std::string::npos &&
data.find(str5) != std::string::npos &&
data.find(str6) != std::string::npos && map7_entries_present &&
data.find(str8) != std::string::npos);
return true;
}
TEST_F(DeviceCertificateStoreTest, StoreCertificate) {
TEST_F(DeviceCertificateTest, StoreCertificate) {
MockFileSystem file_system;
std::string certificate(CdmRandom::RandomData(kCertificateLen));
std::string wrapped_private_key(CdmRandom::RandomData(kWrappedKeyLen));
std::string device_certificate_path =
device_base_path_ + DeviceFiles::GetCertificateFileName();
device_base_path_ + DeviceFiles::GetCertificateFileName(false);
// Call to Open will return a unique_ptr, freeing this object.
MockFile* file = new MockFile();
EXPECT_CALL(file_system,
DoOpen(StrEq(device_certificate_path), IsCreateFileFlagSet()))
.WillOnce(Return(file));
EXPECT_CALL(*file, Write(Contains(certificate, wrapped_private_key, 0),
Gt(certificate.size() + wrapped_private_key.size())))
EXPECT_CALL(*file, Write(_, _))
.With(AllArgs(StrAndLenContains(
std::vector<std::string>{certificate, wrapped_private_key})))
.WillOnce(ReturnArg<1>());
EXPECT_CALL(*file, Read(_, _)).Times(0);
@@ -2207,17 +2150,18 @@ TEST_F(DeviceCertificateStoreTest, StoreCertificate) {
EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key));
}
// TODO(tinskip): Fix. kTestCertificateFileData appears to be incorect.
TEST_F(DeviceCertificateTest, DISABLED_ReadCertificate) {
TEST_P(DeviceCertificateTest, ReadCertificate) {
MockFileSystem file_system;
const bool atsc_mode = GetParam();
std::string device_certificate_path =
device_base_path_ + DeviceFiles::GetCertificateFileName();
std::string data = a2bs_hex(kTestCertificateFileData);
device_base_path_ + DeviceFiles::GetCertificateFileName(atsc_mode);
std::string data = kTestCertificateFileData;
// Call to Open will return a unique_ptr, freeing this object.
MockFile* file = new MockFile();
EXPECT_CALL(file_system, Exists(StrEq(device_certificate_path)))
.WillOnce(Return(true));
.Times(2)
.WillRepeatedly(Return(true));
EXPECT_CALL(file_system, FileSize(StrEq(device_certificate_path)))
.WillOnce(Return(data.size()));
EXPECT_CALL(file_system, DoOpen(StrEq(device_certificate_path), _))
@@ -2233,16 +2177,18 @@ TEST_F(DeviceCertificateTest, DISABLED_ReadCertificate) {
std::string certificate, wrapped_private_key;
std::string serial_number;
uint32_t system_id = 0;
ASSERT_TRUE(device_files.RetrieveCertificate(
&certificate, &wrapped_private_key, &serial_number, &system_id));
EXPECT_EQ(kTestCertificate, b2a_hex(certificate));
EXPECT_EQ(kTestWrappedPrivateKey, b2a_hex(wrapped_private_key));
ASSERT_TRUE(device_files.RetrieveCertificate(atsc_mode, &certificate,
&wrapped_private_key,
&serial_number, &system_id));
EXPECT_EQ(kTestCertificate, certificate);
EXPECT_EQ(kTestWrappedPrivateKey, wrapped_private_key);
}
TEST_F(DeviceCertificateTest, HasCertificate) {
TEST_P(DeviceCertificateTest, HasCertificate) {
MockFileSystem file_system;
bool atsc_mode = GetParam();
std::string device_certificate_path =
device_base_path_ + DeviceFiles::GetCertificateFileName();
device_base_path_ + DeviceFiles::GetCertificateFileName(atsc_mode);
EXPECT_CALL(file_system, Exists(StrEq(device_certificate_path)))
.WillOnce(Return(false))
@@ -2253,11 +2199,14 @@ TEST_F(DeviceCertificateTest, HasCertificate) {
ASSERT_TRUE(device_files.Init(kSecurityLevelL1));
// MockFile returns false.
EXPECT_FALSE(device_files.HasCertificate());
EXPECT_FALSE(device_files.HasCertificate(atsc_mode));
// MockFile returns true.
EXPECT_TRUE(device_files.HasCertificate());
EXPECT_TRUE(device_files.HasCertificate(atsc_mode));
}
INSTANTIATE_TEST_CASE_P(AtscMode, DeviceCertificateTest,
::testing::Values(false, true));
TEST_P(DeviceFilesSecurityLevelTest, SecurityLevel) {
MockFileSystem file_system;
std::string certificate(CdmRandom::RandomData(kCertificateLen));
@@ -2268,15 +2217,16 @@ TEST_P(DeviceFilesSecurityLevelTest, SecurityLevel) {
ASSERT_TRUE(
Properties::GetDeviceFilesBasePath(security_level, &device_base_path));
std::string device_certificate_path =
device_base_path + DeviceFiles::GetCertificateFileName();
device_base_path + DeviceFiles::GetCertificateFileName(false);
// Call to Open will return a unique_ptr, freeing this object.
MockFile* file = new MockFile();
EXPECT_CALL(file_system,
DoOpen(StrEq(device_certificate_path), IsCreateFileFlagSet()))
.WillOnce(Return(file));
EXPECT_CALL(*file, Write(Contains(certificate, wrapped_private_key, 0),
Gt(certificate.size() + wrapped_private_key.size())))
EXPECT_CALL(*file, Write(_, _))
.With(AllArgs(StrAndLenContains(
std::vector<std::string>{certificate, wrapped_private_key})))
.WillOnce(ReturnArg<1>());
EXPECT_CALL(*file, Read(_, _)).Times(0);
@@ -2298,20 +2248,26 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) {
CdmAppParameterMap app_parameters =
GetAppParameters(kLicenseTestData[license_num].app_parameters);
std::vector<std::string> expected_substrings{
kLicenseTestData[license_num].pssh_data,
kLicenseTestData[license_num].key_request,
kLicenseTestData[license_num].key_response,
kLicenseTestData[license_num].key_renewal_request,
kLicenseTestData[license_num].key_renewal_response,
kLicenseTestData[license_num].key_release_url,
kLicenseTestData[license_num].usage_entry,
};
for (const auto& iter : app_parameters) {
expected_substrings.push_back(iter.first);
expected_substrings.push_back(iter.second);
}
// Call to Open will return a unique_ptr, freeing this object.
MockFile* file = new MockFile();
EXPECT_CALL(file_system, DoOpen(StrEq(license_path), IsCreateFileFlagSet()))
.WillOnce(Return(file));
EXPECT_CALL(
*file,
Write(Contains(kLicenseTestData[license_num].pssh_data,
kLicenseTestData[license_num].key_request,
kLicenseTestData[license_num].key_response,
kLicenseTestData[license_num].key_renewal_request,
kLicenseTestData[license_num].key_renewal_response,
kLicenseTestData[license_num].key_release_url,
app_parameters, kLicenseTestData[license_num].usage_entry),
Gt(GetLicenseDataSize(kLicenseTestData[license_num]))))
EXPECT_CALL(*file, Write(_, _))
.With(AllArgs(StrAndLenContains(expected_substrings)))
.WillOnce(ReturnArg<1>());
EXPECT_CALL(*file, Read(_, _)).Times(0);
@@ -2350,20 +2306,27 @@ TEST_F(DeviceFilesTest, StoreLicenses) {
CdmAppParameterMap app_parameters =
GetAppParameters(kLicenseTestData[i].app_parameters);
std::vector<std::string> expected_substrings{
kLicenseTestData[i].pssh_data,
kLicenseTestData[i].key_request,
kLicenseTestData[i].key_response,
kLicenseTestData[i].key_renewal_request,
kLicenseTestData[i].key_renewal_response,
kLicenseTestData[i].key_release_url,
kLicenseTestData[i].usage_entry,
};
for (const auto& iter : app_parameters) {
expected_substrings.push_back(iter.first);
expected_substrings.push_back(iter.second);
}
// Call to Open will return a unique_ptr, freeing this object.
MockFile* file = new MockFile();
EXPECT_CALL(file_system, DoOpen(StrEq(license_path), IsCreateFileFlagSet()))
.WillOnce(Return(file));
EXPECT_CALL(*file,
Write(Contains(kLicenseTestData[i].pssh_data,
kLicenseTestData[i].key_request,
kLicenseTestData[i].key_response,
kLicenseTestData[i].key_renewal_request,
kLicenseTestData[i].key_renewal_response,
kLicenseTestData[i].key_release_url,
app_parameters, kLicenseTestData[i].usage_entry),
Gt(GetLicenseDataSize(kLicenseTestData[i]))))
EXPECT_CALL(*file, Write(_, _))
.With(AllArgs(StrAndLenContains(expected_substrings)))
.WillOnce(ReturnArg<1>());
EXPECT_CALL(*file, Read(_, _)).Times(0);
}
@@ -2523,8 +2486,8 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) {
MockFile* file = new MockFile();
EXPECT_CALL(file_system, DoOpen(StrEq(license_path), IsCreateFileFlagSet()))
.WillOnce(Return(file));
EXPECT_CALL(*file, Write(IsStrEq(kLicenseUpdateTestData[i].file_data),
Eq(kLicenseUpdateTestData[i].file_data.size())))
EXPECT_CALL(*file, Write(_, _))
.With(AllArgs(StrAndLenEq(kLicenseUpdateTestData[i].file_data)))
.WillOnce(ReturnArg<1>());
EXPECT_CALL(*file, Read(_, _)).Times(0);
DeviceFiles::CdmLicenseData license_data{
@@ -2955,7 +2918,6 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
std::string file_name = DeviceFiles::GetUsageInfoFileName(app_id);
std::string path = device_base_path_ + file_name;
size_t usage_data_fields_length = 0;
std::vector<std::string> usage_data_fields;
std::vector<DeviceFiles::CdmUsageData> usage_data_list;
@@ -2969,18 +2931,12 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
usage_data_fields.push_back(kUsageInfoTestData[i].usage_data.license);
usage_data_fields.push_back(kUsageInfoTestData[i].usage_data.key_set_id);
usage_data_fields.push_back(kUsageInfoTestData[i].usage_data.usage_entry);
usage_data_fields_length +=
kUsageInfoTestData[i].usage_data.provider_session_token.size() +
kUsageInfoTestData[i].usage_data.license_request.size() +
kUsageInfoTestData[i].usage_data.license.size() +
kUsageInfoTestData[i].usage_data.key_set_id.size() +
kUsageInfoTestData[i].usage_data.usage_entry.size();
}
}
EXPECT_CALL(file_system, DoOpen(StrEq(path), _)).WillOnce(Return(file));
EXPECT_CALL(*file, Write(ContainsAllElementsInVector(usage_data_fields),
Gt(usage_data_fields_length)))
EXPECT_CALL(*file, Write(_, _))
.With(AllArgs(StrAndLenContains(usage_data_fields)))
.WillOnce(ReturnArg<1>());
DeviceFiles device_files(&file_system);
@@ -3222,7 +3178,6 @@ TEST_P(DeviceFilesUsageInfoTest, UpdateUsageInfo) {
std::string file_name = DeviceFiles::GetUsageInfoFileName(app_id);
std::string path = device_base_path_ + file_name;
size_t usage_data_fields_length = 0;
std::vector<std::string> usage_data_fields;
size_t max_index_by_app_id = 0;
@@ -3240,12 +3195,6 @@ TEST_P(DeviceFilesUsageInfoTest, UpdateUsageInfo) {
kUsageInfoTestData[i].usage_data.key_set_id);
usage_data_fields.push_back(
kUsageInfoTestData[i].usage_data.usage_entry);
usage_data_fields_length +=
kUsageInfoTestData[i].usage_data.provider_session_token.size() +
kUsageInfoTestData[i].usage_data.license_request.size() +
kUsageInfoTestData[i].usage_data.license.size() +
kUsageInfoTestData[i].usage_data.key_set_id.size() +
kUsageInfoTestData[i].usage_data.usage_entry.size();
}
}
}
@@ -3257,12 +3206,6 @@ TEST_P(DeviceFilesUsageInfoTest, UpdateUsageInfo) {
usage_data_fields.push_back(kUsageInfoUpdateTestData.license);
usage_data_fields.push_back(kUsageInfoUpdateTestData.key_set_id);
usage_data_fields.push_back(kUsageInfoUpdateTestData.usage_entry);
usage_data_fields_length +=
kUsageInfoTestData[index].usage_data.provider_session_token.size() +
kUsageInfoUpdateTestData.license_request.size() +
kUsageInfoUpdateTestData.license.size() +
kUsageInfoUpdateTestData.key_set_id.size() +
kUsageInfoUpdateTestData.usage_entry.size();
}
std::string file_data =
@@ -3289,14 +3232,14 @@ TEST_P(DeviceFilesUsageInfoTest, UpdateUsageInfo) {
.Times(2)
.WillOnce(Return(file))
.WillOnce(Return(next_file));
ON_CALL(*file, Write(ContainsAllElementsInVector(usage_data_fields),
Gt(usage_data_fields_length)))
ON_CALL(*file, Write(_, _))
.With(AllArgs(StrAndLenContains(usage_data_fields)))
.WillByDefault(DoAll(InvokeWithoutArgs([&write_called]() -> void {
write_called = true;
}),
ReturnArg<1>()));
ON_CALL(*next_file, Write(ContainsAllElementsInVector(usage_data_fields),
Gt(usage_data_fields_length)))
ON_CALL(*next_file, Write(_, _))
.With(AllArgs(StrAndLenContains(usage_data_fields)))
.WillByDefault(DoAll(InvokeWithoutArgs([&write_called]() -> void {
write_called = true;
}),
@@ -3358,8 +3301,9 @@ TEST_P(DeviceFilesHlsAttributesTest, Store) {
EXPECT_CALL(file_system, Exists(StrEq(path))).WillRepeatedly(Return(true));
EXPECT_CALL(file_system, DoOpen(StrEq(path), _)).WillOnce(Return(file));
EXPECT_CALL(*file, Write(Contains(param->media_segment_iv, 0),
Gt(param->media_segment_iv.size())))
EXPECT_CALL(*file, Write(_, _))
.With(AllArgs(
StrAndLenContains(std::vector<std::string>{param->media_segment_iv})))
.WillOnce(ReturnArg<1>());
EXPECT_CALL(*file, Read(_, _)).Times(0);
@@ -3394,7 +3338,6 @@ TEST_P(DeviceFilesUsageTableTest, Store) {
MockFile* file = new MockFile();
int index = GetParam();
size_t entry_data_length = 0;
std::vector<std::string> entry_data;
std::vector<CdmUsageEntryInfo> usage_entry_info;
usage_entry_info.resize(index + 1);
@@ -3402,18 +3345,15 @@ TEST_P(DeviceFilesUsageTableTest, Store) {
usage_entry_info[i] = kUsageEntriesTestData[i];
entry_data.push_back(kUsageEntriesTestData[i].key_set_id);
entry_data.push_back(kUsageEntriesTestData[i].usage_info_file_name);
entry_data_length += kUsageEntriesTestData[i].key_set_id.size() +
kUsageEntriesTestData[i].usage_info_file_name.size();
}
entry_data.push_back(kUsageTableInfoTestData[index].usage_table_header);
entry_data_length += kUsageTableInfoTestData[index].usage_table_header.size();
std::string path = device_base_path_ + DeviceFiles::GetUsageTableFileName();
EXPECT_CALL(file_system, Exists(StrEq(path))).WillRepeatedly(Return(true));
EXPECT_CALL(file_system, DoOpen(StrEq(path), _)).WillOnce(Return(file));
EXPECT_CALL(*file, Write(ContainsAllElementsInVector(entry_data),
Gt(entry_data_length)))
EXPECT_CALL(*file, Write(_, _))
.With(AllArgs(StrAndLenContains(entry_data)))
.WillOnce(ReturnArg<1>());
EXPECT_CALL(*file, Read(_, _)).Times(0);

View File

@@ -8,7 +8,8 @@
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <cstring>
#include <mutex>
#ifdef _WIN32
# include "winsock2.h"
@@ -33,6 +34,11 @@ namespace wvcdm {
namespace {
// Number of attempts to identify an Internet host and a service should the
// host's nameserver be temporarily unavailable. See getaddrinfo(3) for
// more info.
constexpr size_t kMaxNameserverAttempts = 2;
// Helper function to tokenize a string. This makes it easier to avoid silly
// parsing bugs that creep in easily when each part of the string is parsed
// with its own piece of code.
@@ -71,6 +77,17 @@ bool IsRetryableSslError(int ssl_error) {
ssl_error != SSL_ERROR_SSL;
}
// Ensures that the SSL library is only initialized once.
void InitSslLibrary() {
static bool ssl_initialized = false;
static std::mutex ssl_init_mutex;
std::lock_guard<std::mutex> guard(ssl_init_mutex);
if (!ssl_initialized) {
SSL_library_init();
ssl_initialized = true;
}
}
#if 0
// unused, may be useful for debugging SSL-related issues.
void ShowServerCertificate(const SSL* ssl) {
@@ -211,7 +228,7 @@ HttpSocket::HttpSocket(const std::string& url)
: socket_fd_(-1), ssl_(nullptr), ssl_ctx_(nullptr) {
valid_url_ = ParseUrl(url, &scheme_, &secure_connect_, &domain_name_, &port_,
&resource_path_);
SSL_library_init();
InitSslLibrary();
}
HttpSocket::~HttpSocket() { CloseSocket(); }
@@ -237,6 +254,12 @@ void HttpSocket::CloseSocket() {
bool HttpSocket::Connect(int timeout_in_ms) {
if (!valid_url_) {
LOGE("URL is invalid");
return false;
}
if (socket_fd_ != -1) {
LOGE("Socket already connected");
return false;
}
@@ -259,24 +282,42 @@ bool HttpSocket::Connect(int timeout_in_ms) {
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
struct addrinfo* addr_info = nullptr;
int ret =
getaddrinfo(domain_name_.c_str(), port_.c_str(), &hints, &addr_info);
int ret = EAI_AGAIN;
for (size_t attempt = 1;
attempt <= kMaxNameserverAttempts && ret == EAI_AGAIN; ++attempt) {
if (attempt > 1) {
LOGW(
"Nameserver is temporarily unavailable, waiting to try again: "
"attempt = %zu",
attempt);
sleep(1);
}
ret = getaddrinfo(domain_name_.c_str(), port_.c_str(), &hints, &addr_info);
}
if (ret != 0) {
LOGE("getaddrinfo failed, errno = %d", ret);
if (ret == EAI_SYSTEM) {
// EAI_SYSTEM implies an underlying system issue. Error is
// specified by |errno|.
LOGE("getaddrinfo failed due to system error: errno = %d", GetError());
} else {
// Error is specified by return value.
LOGE("getaddrinfo failed: ret = %d", ret);
}
return false;
}
// get a socket
// Open a socket.
socket_fd_ = socket(addr_info->ai_family, addr_info->ai_socktype,
addr_info->ai_protocol);
if (socket_fd_ < 0) {
LOGE("cannot open socket, errno = %d", GetError());
LOGE("Cannot open socket: errno = %d", GetError());
return false;
}
// set the socket in non-blocking mode
// Set the socket in non-blocking mode.
#ifdef _WIN32
u_long mode = 1; // Non-blocking mode.
if (ioctlsocket(socket_fd_, FIONBIO, &mode) != 0) {
@@ -285,7 +326,7 @@ bool HttpSocket::Connect(int timeout_in_ms) {
return false;
}
#else
int original_flags = fcntl(socket_fd_, F_GETFL, 0);
const int original_flags = fcntl(socket_fd_, F_GETFL, 0);
if (original_flags == -1) {
LOGE("fcntl error, errno = %d", errno);
CloseSocket();
@@ -301,9 +342,10 @@ bool HttpSocket::Connect(int timeout_in_ms) {
// connect to the server
ret = connect(socket_fd_, addr_info->ai_addr, addr_info->ai_addrlen);
freeaddrinfo(addr_info);
addr_info = nullptr;
if (ret == 0) {
// connected right away.
// Connected right away.
} else {
if (GetError() != ERROR_ASYNC_COMPLETE) {
// failed right away.
@@ -336,6 +378,8 @@ bool HttpSocket::Connect(int timeout_in_ms) {
return false;
}
// |BIO_NOCLOSE| prevents closing the socket from being closed when
// the BIO is freed.
BIO* a_bio = BIO_new_socket(socket_fd_, BIO_NOCLOSE);
if (!a_bio) {
LOGE("BIO_new_socket error");
@@ -354,9 +398,9 @@ bool HttpSocket::Connect(int timeout_in_ms) {
CloseSocket();
return false;
}
bool for_read = ssl_err == SSL_ERROR_WANT_READ;
const bool for_read = (ssl_err == SSL_ERROR_WANT_READ);
if (!SocketWait(socket_fd_, for_read, timeout_in_ms)) {
LOGE("cannot connect to %s", domain_name_.c_str());
LOGE("Cannot connect securely to %s", domain_name_.c_str());
CloseSocket();
return false;
}

View File

@@ -15,8 +15,8 @@ namespace wvcdm {
// Google license servers.
class LicenseRequest {
public:
LicenseRequest() {};
~LicenseRequest() {};
LicenseRequest() {}
~LicenseRequest() {}
void GetDrmMessage(const std::string& response, std::string& drm_msg);

View File

@@ -6,7 +6,6 @@
// would, but in parallel, attempting to create as many collisions in the CDM
// code as possible.
#include <algorithm>
#include <chrono>
#include <future>
#include <string>
@@ -41,6 +40,12 @@ constexpr const auto kMinimumWait = std::chrono::nanoseconds(1);
constexpr const int kRepetitions = 10;
constexpr const int kThreadCount = 24;
// Number of attempts to request a license key from the license server
// before failing.
constexpr size_t kMaxKeyRequestAttempts = 5;
// Wait time between failed key requests.
constexpr const auto kRequestRetryWait = std::chrono::milliseconds(10);
const std::vector<uint8_t> kKeyId = a2b_hex("371ea35e1a985d75d198a7f41020dc23");
const std::vector<uint8_t> kIv = a2b_hex("cedc47cccd6cb437af41325953c2e5e0");
const std::vector<uint8_t> kEncryptedData = a2b_hex(
@@ -110,17 +115,27 @@ class ParallelCdmTest : public WvCdmTestBase,
ASSERT_EQ(kKeyRequestTypeInitial, key_request->type);
}
void GetKeyResponse(const std::string& url, const CdmKeyRequest& key_request,
void GetKeyResponse(const CdmSessionId& session_id, const std::string& url,
const CdmKeyRequest& key_request,
std::string* key_response) {
UrlRequest url_request(url);
ASSERT_TRUE(url_request.is_connected());
bool request_ok = false;
std::string http_response;
url_request.PostRequest(key_request.message);
ASSERT_TRUE(url_request.GetResponse(&http_response));
int status_code = url_request.GetStatusCode(http_response);
ASSERT_EQ(kHttpOk, status_code);
for (size_t attempt = 1; attempt <= kMaxKeyRequestAttempts; ++attempt) {
UrlRequest url_request(url);
ASSERT_TRUE(url_request.is_connected());
url_request.PostRequest(key_request.message);
if (url_request.GetResponse(&http_response)) {
int status_code = url_request.GetStatusCode(http_response);
ASSERT_EQ(kHttpOk, status_code);
request_ok = true;
break;
} else {
LOGW("License request failed: sid = %s, attempt = %zu",
session_id.c_str(), attempt);
std::this_thread::sleep_for(kRequestRetryWait);
}
}
ASSERT_TRUE(request_ok);
LicenseRequest license_request;
license_request.GetDrmMessage(http_response, *key_response);
}
@@ -184,8 +199,10 @@ class ParallelCdmTest : public WvCdmTestBase,
template <class Function>
void RunSessionThreadsSimultaneously(Function do_work) {
std::atomic<int> threads_waiting(0);
const int session_count = std::min(kThreadCount, GetMaxNumberOfSessions());
// The OEMCrypto V16 adapter makes use of one of the sessions,
// reducing the maximum number of sessions available for the test.
const int session_count =
std::min(kThreadCount, GetMaxNumberOfSessions() - 1);
LOGI("Running %d Threads", session_count);
std::vector<CdmSessionId> sessions(session_count);
std::vector<std::future<void>> threads;
@@ -231,7 +248,10 @@ TEST_P(ParallelCdmTest, ParallelLicenseRequests) {
GenerateKeyRequest(session_id, init_data, &key_request));
std::string key_response;
ASSERT_NO_FATAL_FAILURE(GetKeyResponse(url, key_request, &key_response));
LOGD("Getting license request: sid = %s", session_id.c_str());
ASSERT_NO_FATAL_FAILURE(
GetKeyResponse(session_id, url, key_request, &key_response))
<< "SID: " << session_id;
ASSERT_NO_FATAL_FAILURE(AddKey(session_id, key_response));
});
@@ -248,7 +268,8 @@ TEST_P(ParallelCdmTest, ParallelDecryptSessions) {
GenerateKeyRequest(session_id, init_data, &key_request));
std::string key_response;
ASSERT_NO_FATAL_FAILURE(GetKeyResponse(url, key_request, &key_response));
ASSERT_NO_FATAL_FAILURE(
GetKeyResponse(session_id, url, key_request, &key_response));
ASSERT_NO_FATAL_FAILURE(AddKey(session_id, key_response));
@@ -273,7 +294,8 @@ TEST_P(ParallelCdmTest, ParallelDecryptsInSameSession) {
GenerateKeyRequest(session_id, init_data, &key_request));
std::string key_response;
ASSERT_NO_FATAL_FAILURE(GetKeyResponse(url, key_request, &key_response));
ASSERT_NO_FATAL_FAILURE(
GetKeyResponse(session_id, url, key_request, &key_response));
ASSERT_NO_FATAL_FAILURE(AddKey(session_id, key_response));

View File

@@ -79,6 +79,7 @@ class StubCdmClientPropertySet : public CdmClientPropertySet {
}
uint32_t session_sharing_id() const override { return session_sharing_id_; }
virtual bool use_atsc_mode() const { return false; }
void set_session_sharing_id(uint32_t id) override {
session_sharing_id_ = id;

View File

@@ -294,8 +294,8 @@ void WvCdmTestBase::Provision() {
std::shared_ptr<EngineMetrics>(new EngineMetrics));
FakeProvisioningServer server;
CdmResponseType result = cdm_engine.GetProvisioningRequest(
cert_type, cert_authority, server.service_certificate(), &prov_request,
&provisioning_server_url);
cert_type, cert_authority, server.service_certificate(), kLevelDefault,
&prov_request, &provisioning_server_url);
ASSERT_EQ(NO_ERROR, result);
if (!binary_provisioning_) {
std::vector<uint8_t> prov_request_v = Base64SafeDecode(prov_request);
@@ -304,8 +304,8 @@ void WvCdmTestBase::Provision() {
std::string response;
ASSERT_TRUE(server.MakeResponse(prov_request, &response))
<< "Fake provisioning server could not provision";
result =
cdm_engine.HandleProvisioningResponse(response, &cert, &wrapped_key);
result = cdm_engine.HandleProvisioningResponse(response, kLevelDefault,
&cert, &wrapped_key);
EXPECT_EQ(NO_ERROR, result);
} else {
// TODO(fredgc): provision for different SPOIDs.
@@ -314,7 +314,7 @@ void WvCdmTestBase::Provision() {
CdmResponseType result = cdm_engine.GetProvisioningRequest(
cert_type, cert_authority, config_.provisioning_service_certificate(),
&prov_request, &provisioning_server_url);
kLevelDefault, &prov_request, &provisioning_server_url);
ASSERT_EQ(NO_ERROR, result);
if (binary_provisioning_) {
@@ -329,84 +329,54 @@ void WvCdmTestBase::Provision() {
// for test vs. production server.
provisioning_server_url.assign(config_.provisioning_server());
// TODO(b/139361531): Remove loop once provisioning service is stable.
std::string http_message;
size_t attempt_num = 0;
bool provision_success = false;
do {
if (attempt_num > 0) {
// Sleep between attempts.
std::this_thread::sleep_for(std::chrono::seconds(1));
}
++attempt_num;
// Make request.
UrlRequest url_request(provisioning_server_url);
if (!url_request.is_connected()) {
LOGE("Failed to connect to provisioning server: url = %s",
provisioning_server_url.c_str());
continue;
}
url_request.PostCertRequestInQueryString(prov_request);
// Receive and parse response.
if (!url_request.GetResponse(&http_message)) {
LOGE("Failed to get provisioning response");
continue;
}
LOGV("http_message: \n%s\n", http_message.c_str());
if (binary_provisioning_) {
// extract provisioning response from received message
// Extracts signed response from JSON string, result is serialized
// protobuf.
static const std::string kMessageStart = "\"signedResponse\": \"";
static const std::string kMessageEnd = "\"";
std::string protobuf_response;
if (!ExtractSignedMessage(http_message, kMessageStart, kMessageEnd,
&protobuf_response)) {
LOGE(
"Failed to extract signed serialized response from JSON "
"response");
continue;
}
LOGV("Extracted response message: \n%s\n", protobuf_response.c_str());
// base64 decode response to yield binary protobuf
std::vector<uint8_t> response_vec(Base64SafeDecode(protobuf_response));
if (response_vec.empty() && !protobuf_response.empty()) {
LOGE("Failed to decode base64 of response: response = %s",
protobuf_response.c_str());
continue;
}
std::string binary_protobuf_response(response_vec.begin(),
response_vec.end());
if (cdm_engine.HandleProvisioningResponse(
binary_protobuf_response, &cert, &wrapped_key) != NO_ERROR) {
LOGE("Failed to handle provisioning response");
continue;
}
} else {
if (cdm_engine.HandleProvisioningResponse(http_message, &cert,
&wrapped_key) != NO_ERROR) {
LOGE("Failed to handle binary provisioning response");
continue;
}
}
provision_success = true;
} while (attempt_num <= kDefaultMaxProvisioningAttempts &&
!provision_success);
if (attempt_num > 1) {
LOGW("Provisioning request failed at least once: attempts = %zu",
attempt_num);
// Make request.
UrlRequest url_request(provisioning_server_url);
if (!url_request.is_connected()) {
LOGE("Failed to connect to provisioning server: url = %s",
provisioning_server_url.c_str());
}
url_request.PostCertRequestInQueryString(prov_request);
// Receive and parse response.
std::string http_message;
ASSERT_TRUE(url_request.GetResponse(&http_message))
<< "Failed to get provisioning response";
LOGV("http_message: \n%s\n", http_message.c_str());
if (binary_provisioning_) {
// extract provisioning response from received message
// Extracts signed response from JSON string, result is serialized
// protobuf.
static const std::string kMessageStart = "\"signedResponse\": \"";
static const std::string kMessageEnd = "\"";
std::string protobuf_response;
const bool extract_ok = ExtractSignedMessage(
http_message, kMessageStart, kMessageEnd, &protobuf_response);
ASSERT_TRUE(extract_ok) << "Failed to extract signed serialized "
"response from JSON response";
LOGV("Extracted response message: \n%s\n", protobuf_response.c_str());
ASSERT_FALSE(protobuf_response.empty())
<< "Protobuf response is unexpectedly empty";
// base64 decode response to yield binary protobuf
const std::vector<uint8_t> response_vec(
Base64SafeDecode(protobuf_response));
ASSERT_FALSE(response_vec.empty())
<< "Failed to decode base64 of response: response = "
<< protobuf_response;
const std::string binary_protobuf_response(response_vec.begin(),
response_vec.end());
ASSERT_EQ(NO_ERROR, cdm_engine.HandleProvisioningResponse(
binary_protobuf_response, kLevelDefault, &cert,
&wrapped_key));
} else {
ASSERT_EQ(NO_ERROR,
cdm_engine.HandleProvisioningResponse(
http_message, kLevelDefault, &cert, &wrapped_key));
}
ASSERT_TRUE(provision_success)
<< "Failed to provision: message = " << http_message;
}
}
@@ -561,6 +531,7 @@ void TestLicenseHolder::GenerateKeyRequest(
CdmAppParameterMap app_parameters;
CdmKeySetId key_set_id;
InitializationData init_data(init_data_type_string, key_id);
if (g_cutoff >= LOG_DEBUG) init_data.DumpToLogs();
CdmKeyRequest key_request;
CdmResponseType result = cdm_engine_->GenerateKeyRequest(
session_id_, key_set_id, init_data, kLicenseTypeStreaming, app_parameters,

View File

@@ -22,9 +22,6 @@ namespace wvcdm {
// to configure OEMCrypto to use a test keybox.
class WvCdmTestBase : public ::testing::Test {
public:
// Default number of provisioning try attempts.
constexpr static size_t kDefaultMaxProvisioningAttempts = 10;
WvCdmTestBase();
~WvCdmTestBase() override {}
void SetUp() override;

View File

@@ -284,21 +284,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case INSUFFICIENT_CRYPTO_RESOURCES:
*os << "INSUFFICIENT_CRYPTO_RESOURCES";
break;
case INSUFFICIENT_CRYPTO_RESOURCES_2:
*os << "INSUFFICIENT_CRYPTO_RESOURCES_2";
break;
case INSUFFICIENT_CRYPTO_RESOURCES_3:
*os << "INSUFFICIENT_CRYPTO_RESOURCES_3";
break;
case INSUFFICIENT_CRYPTO_RESOURCES_4:
*os << "INSUFFICIENT_CRYPTO_RESOURCES_4";
break;
case INSUFFICIENT_CRYPTO_RESOURCES_5:
*os << "INSUFFICIENT_CRYPTO_RESOURCES_5";
break;
case INSUFFICIENT_CRYPTO_RESOURCES_6:
*os << "INSUFFICIENT_CRYPTO_RESOURCES_6";
break;
case INSUFFICIENT_OUTPUT_PROTECTION:
*os << "INSUFFICIENT_OUTPUT_PROTECTION";
break;
@@ -521,6 +506,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case LICENSE_RESPONSE_PARSE_ERROR_5:
*os << "LICENSE_RESPONSE_PARSE_ERROR_5";
break;
case LICENSE_USAGE_ENTRY_MISSING:
*os << "LICENSE_USAGE_ENTRY_MISSING";
break;
case LIST_LICENSE_ERROR_1:
*os << "LIST_LICENSE_ERROR_1";
break;
@@ -560,6 +548,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case LOAD_USAGE_ENTRY_GENERATION_SKEW:
*os << "LOAD_USAGE_ENTRY_GENERATION_SKEW";
break;
case LOAD_USAGE_ENTRY_INVALID_SESSION:
*os << "LOAD_USAGE_ENTRY_INVALID_SESSION";
break;
case LOAD_USAGE_ENTRY_SIGNATURE_FAILURE:
*os << "LOAD_USAGE_ENTRY_SIGNATURE_FAILURE";
break;
@@ -578,6 +569,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case LOAD_USAGE_HEADER_UNKNOWN_ERROR:
*os << "LOAD_USAGE_HEADER_UNKNOWN_ERROR";
break;
case MOVE_USAGE_ENTRY_DESTINATION_IN_USE:
*os << "MOVE_USAGE_ENTRY_DESTINATION_IN_USE";
break;
case MOVE_USAGE_ENTRY_UNKNOWN_ERROR:
*os << "MOVE_USAGE_ENTRY_UNKNOWN_ERROR";
break;
@@ -818,8 +812,11 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case SET_DECRYPT_HASH_ERROR:
*os << "SET_DECRYPT_HASH_ERROR";
break;
case SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR:
*os << "SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR";
case SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE:
*os << "SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE";
break;
case SHRINK_USAGE_TABLE_HEADER_UNKNOWN_ERROR:
*os << "SHRINK_USAGE_TABLE_HEADER_UNKNOWN_ERROR";
break;
case SIGNATURE_NOT_FOUND:
*os << "SIGNATURE_NOT_FOUND";
@@ -923,6 +920,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case WEBM_INIT_DATA_UNAVAILABLE:
*os << "WEBM_INIT_DATA_UNAVAILABLE";
break;
case PROVISIONING_NOT_ALLOWED_FOR_ATSC:
*os << "PROVISIONING_NOT_ALLOWED_FOR_ATSC";
break;
default:
*os << "Unknown CdmResponseType";
break;

View File

@@ -87,8 +87,8 @@ void UrlRequest::Reconnect() {
if (socket_.Connect(kConnectTimeoutMs)) {
is_connected_ = true;
} else {
LOGE("failed to connect to %s, port=%d", socket_.domain_name().c_str(),
socket_.port());
LOGE("Failed to connect: url = %s, port = %d, attempt = %u",
socket_.domain_name().c_str(), socket_.port(), i);
}
}
}
@@ -148,7 +148,7 @@ bool UrlRequest::PostRequestWithPath(const std::string& path,
// buffer to store length of data as a string
char data_size_buffer[32] = {0};
snprintf(data_size_buffer, sizeof(data_size_buffer), "%zd", data.size());
snprintf(data_size_buffer, sizeof(data_size_buffer), "%zu", data.size());
request.append("Content-Length: ");
request.append(data_size_buffer); // appends size of data
@@ -158,7 +158,8 @@ bool UrlRequest::PostRequestWithPath(const std::string& path,
request.append(data);
int ret = socket_.Write(request.c_str(), request.size(), kWriteTimeoutMs);
const int ret =
socket_.Write(request.c_str(), request.size(), kWriteTimeoutMs);
LOGV("HTTP request: (%d): %s", request.size(), b2a_hex(request).c_str());
return ret != -1;
}

File diff suppressed because it is too large Load Diff