diff --git a/libwvdrmengine/cdm/core/include/cdm_client_property_set.h b/libwvdrmengine/cdm/core/include/cdm_client_property_set.h index 38398ebe..e6c7ba4c 100644 --- a/libwvdrmengine/cdm/core/include/cdm_client_property_set.h +++ b/libwvdrmengine/cdm/core/include/cdm_client_property_set.h @@ -24,6 +24,7 @@ class CdmClientPropertySet { virtual uint32_t session_sharing_id() const = 0; virtual void set_session_sharing_id(uint32_t id) = 0; virtual const std::string& app_id() const = 0; + virtual bool use_atsc_mode() const = 0; }; } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index 65f96955..6325e49e 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -219,7 +219,7 @@ class CdmSession { private: friend class CdmSessionTest; - bool GenerateKeySetId(CdmKeySetId* key_set_id); + bool GenerateKeySetId(bool atsc_mode_enabled, CdmKeySetId* key_set_id); CdmResponseType StoreLicense(); diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 5de50572..70f55e36 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -95,13 +95,16 @@ class DeviceFiles { return Init(security_level); } + // ATSC certificates are installed by the ATSC service. They can be read + // and used but not written or removed. virtual bool StoreCertificate(const std::string& certificate, const std::string& wrapped_private_key); - virtual bool RetrieveCertificate(std::string* certificate, + virtual bool RetrieveCertificate(bool atsc_mode_enabled, + std::string* certificate, std::string* wrapped_private_key, std::string* serial_number, uint32_t* system_id); - virtual bool HasCertificate(); + virtual bool HasCertificate(bool atsc_mode_enabled); virtual bool RemoveCertificate(); virtual bool StoreLicense(const CdmLicenseData& license_data, @@ -256,7 +259,7 @@ class DeviceFiles { bool RemoveFile(const std::string& name); ssize_t GetFileSize(const std::string& name); - static std::string GetCertificateFileName(); + static std::string GetCertificateFileName(bool atsc_mode_enabled); static std::string GetHlsAttributesFileNameExtension(); static std::string GetLicenseFileNameExtension(); static std::string GetUsageTableFileName(); @@ -264,8 +267,8 @@ class DeviceFiles { #if defined(UNIT_TEST) FRIEND_TEST(DeviceFilesSecurityLevelTest, SecurityLevel); - FRIEND_TEST(DeviceCertificateStoreTest, StoreCertificate); - FRIEND_TEST(DeviceCertificateTest, DISABLED_ReadCertificate); + FRIEND_TEST(DeviceCertificateTest, StoreCertificate); + FRIEND_TEST(DeviceCertificateTest, ReadCertificate); FRIEND_TEST(DeviceCertificateTest, HasCertificate); FRIEND_TEST(DeviceFilesStoreTest, StoreLicense); FRIEND_TEST(DeviceFilesHlsAttributesTest, Delete); diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index 5d427e20..3db2a051 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -43,8 +43,10 @@ static const uint32_t RESOURCE_RATING_TIER_MAX = RESOURCE_RATING_TIER_VERY_HIGH; static const uint32_t OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER = 15; static const char SESSION_ID_PREFIX[] = "sid"; +static const char ATSC_KEY_SET_ID_PREFIX[] = "atscksid"; static const char KEY_SET_ID_PREFIX[] = "ksid"; static const char KEY_SYSTEM[] = "com.widevine"; +static const char ATSC_APP_PACKAGE_NAME[] = "org.atsc"; // define query keys, values here static const std::string QUERY_KEY_LICENSE_TYPE = diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 7d87adfe..c06ed7e5 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -408,10 +408,12 @@ enum CdmResponseType { CANNOT_DECRYPT_ZERO_SUBSAMPLES = 354, SAMPLE_AND_SUBSAMPLE_SIZE_MISMATCH = 355, INVALID_IV_SIZE = 356, - LOAD_USAGE_ENTRY_INVALID_SESSION = 357, + PROVISIONING_NOT_ALLOWED_FOR_ATSC = 357, + // 357 was |LOAD_USAGE_ENTRY_INVALID_SESSION| in early R builds MOVE_USAGE_ENTRY_DESTINATION_IN_USE = 358, SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE = 359, LICENSE_USAGE_ENTRY_MISSING = 360, + LOAD_USAGE_ENTRY_INVALID_SESSION = 361, // Don't forget to add new values to // * core/test/test_printers.cpp. // * android/include/mapErrors-inl.h diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 66309966..c18dc339 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -62,6 +62,7 @@ class UsagePropertySet : public CdmClientPropertySet { void set_session_sharing_id(uint32_t /* id */) override {} const std::string& app_id() const override { return app_id_; } void set_app_id(const std::string& appId) { app_id_ = appId; } + bool use_atsc_mode() const override { return false; } private: std::string app_id_; diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 6955ed52..9dd23530 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -159,8 +159,12 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, // License server client ID token is a stored certificate. Stage it or // indicate that provisioning is needed. Get token from stored certificate std::string wrapped_key; - if (!file_handle_->RetrieveCertificate(&client_token, &wrapped_key, - &serial_number, nullptr)) { + bool atsc_mode_enabled = false; + if (cdm_client_property_set != nullptr) + atsc_mode_enabled = cdm_client_property_set->use_atsc_mode(); + if (!file_handle_->RetrieveCertificate(atsc_mode_enabled, &client_token, + &wrapped_key, &serial_number, + nullptr)) { return NEED_PROVISIONING; } CdmResponseType load_cert_sts; @@ -186,7 +190,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, if (forced_session_id) { key_set_id_ = *forced_session_id; } else { - bool ok = GenerateKeySetId(&key_set_id_); + bool ok = GenerateKeySetId(atsc_mode_enabled, &key_set_id_); (void)ok; // ok is now used when assertions are turned off. assert(ok); } @@ -849,7 +853,8 @@ CdmSessionId CdmSession::GenerateSessionId() { return SESSION_ID_PREFIX + IntToString(++session_num); } -bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) { +bool CdmSession::GenerateKeySetId(bool atsc_mode_enabled, + CdmKeySetId* key_set_id) { RETURN_FALSE_IF_NULL(key_set_id); std::vector random_data( @@ -861,7 +866,10 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) { return false; } - *key_set_id = KEY_SET_ID_PREFIX + b2a_hex(random_data); + if (atsc_mode_enabled) + *key_set_id = ATSC_KEY_SET_ID_PREFIX + b2a_hex(random_data); + else + *key_set_id = KEY_SET_ID_PREFIX + b2a_hex(random_data); // key set collision if (file_handle_->LicenseExists(*key_set_id)) { diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index c49c34db..0401e8f8 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -70,6 +70,7 @@ using video_widevine_client::sdk:: namespace { +const char kAtscCertificateFileName[] = "atsccert.bin"; const char kCertificateFileName[] = "cert.bin"; const char kHlsAttributesFileNameExt[] = ".hal"; const char kUsageInfoFileNamePrefix[] = "usage"; @@ -126,19 +127,21 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate, std::string serialized_file; file.SerializeToString(&serialized_file); - return StoreFileWithHash(GetCertificateFileName(), serialized_file) == + return StoreFileWithHash(GetCertificateFileName(false), serialized_file) == kNoError; } -bool DeviceFiles::RetrieveCertificate(std::string* certificate, +bool DeviceFiles::RetrieveCertificate(bool atsc_mode_enabled, + std::string* certificate, std::string* wrapped_private_key, std::string* serial_number, uint32_t* system_id) { RETURN_FALSE_IF_UNINITIALIZED(); video_widevine_client::sdk::File file; - if (RetrieveHashedFile(GetCertificateFileName(), &file) != kNoError) { - LOGE("Unable to retrieve certificate file"); + if (RetrieveHashedFile(GetCertificateFileName(atsc_mode_enabled), &file) != + kNoError) { + LOGW("Unable to retrieve certificate file"); return false; } @@ -166,14 +169,16 @@ bool DeviceFiles::RetrieveCertificate(std::string* certificate, device_certificate.certificate(), serial_number, system_id); } -bool DeviceFiles::HasCertificate() { +bool DeviceFiles::HasCertificate(bool atsc_mode_enabled) { RETURN_FALSE_IF_UNINITIALIZED(); - return FileExists(GetCertificateFileName()); + + return FileExists(GetCertificateFileName(atsc_mode_enabled)); } bool DeviceFiles::RemoveCertificate() { RETURN_FALSE_IF_UNINITIALIZED() - return RemoveFile(GetCertificateFileName()); + + return RemoveFile(GetCertificateFileName(false)); } bool DeviceFiles::StoreLicense(const CdmLicenseData& license_data, @@ -1214,8 +1219,8 @@ ssize_t DeviceFiles::GetFileSize(const std::string& name) { return file_system_->FileSize(path); } -std::string DeviceFiles::GetCertificateFileName() { - return kCertificateFileName; +std::string DeviceFiles::GetCertificateFileName(bool atsc_mode_enabled) { + return atsc_mode_enabled ? kAtscCertificateFileName : kCertificateFileName; } std::string DeviceFiles::GetUsageTableFileName() { return kUsageTableFileName; } diff --git a/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp index 6d09be08..4b9d2d4b 100644 --- a/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp @@ -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&()); }; diff --git a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp index f0ac0731..674939e8 100644 --- a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp @@ -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) diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index 6dc0ec11..94564ea1 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -32,27 +32,26 @@ 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 +75,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; @@ -2075,9 +2086,9 @@ class DeviceFilesTest : public ::testing::Test { class DeviceFilesStoreTest : public DeviceFilesTest, public ::testing::WithParamInterface {}; -class DeviceCertificateStoreTest : public DeviceFilesTest {}; - -class DeviceCertificateTest : public DeviceFilesTest {}; +class DeviceCertificateTest + : public DeviceFilesTest, + public ::testing::WithParamInterface {}; class DeviceFilesSecurityLevelTest : public DeviceFilesTest, @@ -2185,12 +2196,12 @@ MATCHER_P8(Contains, str1, str2, str3, str4, str5, str6, map7, str8, "") { data.find(str8) != std::string::npos); } -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(); @@ -2207,12 +2218,12 @@ 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(); @@ -2233,16 +2244,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 +2266,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,7 +2284,7 @@ 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(); diff --git a/libwvdrmengine/cdm/core/test/license_request.h b/libwvdrmengine/cdm/core/test/license_request.h index 93254c1e..6188d8e4 100644 --- a/libwvdrmengine/cdm/core/test/license_request.h +++ b/libwvdrmengine/cdm/core/test/license_request.h @@ -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); diff --git a/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp b/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp index aecbc92a..6958d307 100644 --- a/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp @@ -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; diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index 25bb54b9..6caa8931 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -935,6 +935,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; diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index caf0ae10..d7fd97ba 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -198,7 +198,8 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { TestWvCdmClientPropertySet() : use_privacy_mode_(false), is_session_sharing_enabled_(false), - session_sharing_id_(0) {} + session_sharing_id_(0), + use_atsc_mode_(false) {} virtual ~TestWvCdmClientPropertySet() {} virtual const std::string& app_id() const { return app_id_; } @@ -214,6 +215,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { return is_session_sharing_enabled_; } virtual uint32_t session_sharing_id() const { return session_sharing_id_; } + virtual bool use_atsc_mode() const { return use_atsc_mode_; } void set_app_id(const std::string& app_id) { app_id_ = app_id; } void set_security_level(const std::string& security_level) { @@ -229,6 +231,9 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { is_session_sharing_enabled_ = enable; } void set_session_sharing_id(uint32_t id) { session_sharing_id_ = id; } + void set_use_atsc_mode(bool use_atsc_mode) { + use_atsc_mode_ = use_atsc_mode; + } private: std::string app_id_; @@ -237,6 +242,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { bool use_privacy_mode_; bool is_session_sharing_enabled_; uint32_t session_sharing_id_; + bool use_atsc_mode_; }; class WvCdmExtendedDurationTest : public WvCdmTestBase { diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index f3c562af..e7b03eb3 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -1608,7 +1608,8 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { TestWvCdmClientPropertySet() : use_privacy_mode_(false), is_session_sharing_enabled_(false), - session_sharing_id_(0) {} + session_sharing_id_(0), + use_atsc_mode_(false) {} virtual ~TestWvCdmClientPropertySet() {} virtual const std::string& app_id() const { return app_id_; } @@ -1624,6 +1625,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { return is_session_sharing_enabled_; } virtual uint32_t session_sharing_id() const { return session_sharing_id_; } + virtual bool use_atsc_mode() const { return use_atsc_mode_; } void set_app_id(const std::string& app_id) { app_id_ = app_id; } void set_security_level(const std::string& security_level) { @@ -1639,6 +1641,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { is_session_sharing_enabled_ = enable; } void set_session_sharing_id(uint32_t id) { session_sharing_id_ = id; } + void set_use_atsc_mode(bool use_atsc_mode) { use_atsc_mode_ = use_atsc_mode; } private: std::string app_id_; @@ -1647,6 +1650,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { bool use_privacy_mode_; bool is_session_sharing_enabled_; uint32_t session_sharing_id_; + bool use_atsc_mode_; }; class TestWvCdmEventListener : public WvCdmEventListener { @@ -2279,13 +2283,13 @@ TEST_F(WvCdmRequestLicenseTest, UnprovisionTest) { std::string wrapped_private_key; std::string serial_number; uint32_t system_id; - EXPECT_TRUE(handle.RetrieveCertificate(&certificate, &wrapped_private_key, - &serial_number, &system_id)); + EXPECT_TRUE(handle.RetrieveCertificate( + false, &certificate, &wrapped_private_key, &serial_number, &system_id)); EXPECT_EQ(NO_ERROR, decryptor_->Unprovision(security_level, kDefaultCdmIdentifier)); - EXPECT_FALSE(handle.RetrieveCertificate(&certificate, &wrapped_private_key, - &serial_number, &system_id)); + EXPECT_FALSE(handle.RetrieveCertificate( + false, &certificate, &wrapped_private_key, &serial_number, &system_id)); } TEST_F(WvCdmRequestLicenseTest, ProvisioningInterposedRetryTest) { diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index d0bf031c..9cfb2228 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -289,14 +289,17 @@ enum { kCannotDecryptZeroSubsamples = ERROR_DRM_VENDOR_MIN + 306, kSampleAndSubsampleSizeMismatch = ERROR_DRM_VENDOR_MIN + 307, kInvalidIvSize = ERROR_DRM_VENDOR_MIN + 308, - kLoadUsageEntryInvalidSession = ERROR_DRM_VENDOR_MIN + 309, + kProvisioningNotAllowedForAtsc = ERROR_DRM_VENDOR_MIN + 309, + // ERROR_DRM_VENDOR_MIN + 309 was |kLoadUsageEntryInvalidSession| + // in early R builds kMoveUsageEntryDestinationInUse = ERROR_DRM_VENDOR_MIN + 310, kShrinkUsageTableHeaderEntryInUse = ERROR_DRM_VENDOR_MIN + 311, kLicenseUsageEntryMissing = ERROR_DRM_VENDOR_MIN + 312, + kLoadUsageEntryInvalidSession = ERROR_DRM_VENDOR_MIN + 313, // This should always follow the last error code. // The offset value should be updated each time a new error code is added. - kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 312, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 313, // Used by crypto test mode kErrorTestMode = ERROR_DRM_VENDOR_MAX, diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h index c86726ed..e7315d7f 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -442,6 +442,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kPrivacyModeError2; case wvcdm::PRIVACY_MODE_ERROR_3: return kPrivacyModeError3; + case wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC: + return kProvisioningNotAllowedForAtsc; case wvcdm::REFRESH_KEYS_ERROR: return kRefreshKeysError; case wvcdm::REINIT_ERROR: diff --git a/libwvdrmengine/include_hidl/mapErrors-inl.h b/libwvdrmengine/include_hidl/mapErrors-inl.h index dfd4daa4..c6f61778 100644 --- a/libwvdrmengine/include_hidl/mapErrors-inl.h +++ b/libwvdrmengine/include_hidl/mapErrors-inl.h @@ -359,6 +359,7 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) { case wvcdm::MOVE_USAGE_ENTRY_DESTINATION_IN_USE: case wvcdm::SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE: case wvcdm::LICENSE_USAGE_ENTRY_MISSING: + case wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC: ALOGW("Returns UNKNOWN error for legacy status: %d", res); return Status::ERROR_DRM_UNKNOWN; diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index 6b9fa6d5..3284a901 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -190,7 +190,8 @@ class WVDrmPlugin : public android::DrmPlugin, class WVClientPropertySet : public wvcdm::CdmClientPropertySet { public: WVClientPropertySet() - : mUsePrivacyMode(false), mShareKeys(false), mSessionSharingId(0) {} + : mUsePrivacyMode(false), mShareKeys(false), mSessionSharingId(0), + mUseAtscMode(false) {} virtual ~WVClientPropertySet() {} @@ -243,6 +244,14 @@ class WVDrmPlugin : public android::DrmPlugin, mAppId = appId; } + virtual bool use_atsc_mode() const { + return mUseAtscMode; + } + + void set_use_atsc_mode(bool useAtscMode) { + mUseAtscMode = useAtscMode; + } + private: DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet); @@ -252,6 +261,7 @@ class WVDrmPlugin : public android::DrmPlugin, bool mShareKeys; uint32_t mSessionSharingId; std::string mAppId; + bool mUseAtscMode; const std::string mEmptyString; } mPropertySet; diff --git a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h index 8f0608a8..06cf4d59 100644 --- a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h @@ -287,7 +287,8 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, class WVClientPropertySet : public wvcdm::CdmClientPropertySet { public: WVClientPropertySet() - : mUsePrivacyMode(false), mShareKeys(false), mSessionSharingId(0) {} + : mUsePrivacyMode(false), mShareKeys(false), mSessionSharingId(0), + mUseAtscMode(false) {} virtual ~WVClientPropertySet() {} @@ -351,6 +352,14 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, mAppId = appId; } + virtual bool use_atsc_mode() const { + return mUseAtscMode; + } + + void set_use_atsc_mode(bool useAtscMode) { + mUseAtscMode = useAtscMode; + } + private: DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet); @@ -360,6 +369,7 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, bool mShareKeys; uint32_t mSessionSharingId; std::string mAppId; + bool mUseAtscMode; const std::string mEmptyString; } mPropertySet; @@ -385,6 +395,9 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, const std::string& origin() const { return mCdmIdentifier.origin; } bool set_origin(const std::string& id); + // This sets the app package name to allow apps to access ATSC licenses + bool set_use_atsc_mode(bool enable); + // Indicates whether the builder can still be modified. This returns false // until a call to getCdmIdentifier. bool is_sealed() { return mIsIdentifierSealed; } diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index ccb01a65..70164ae4 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -364,6 +364,10 @@ status_t WVDrmPlugin::getProvisionRequest(const String8& cert_type, CdmProvisioningRequest cdmProvisionRequest; string cdmDefaultUrl; + if (mPropertySet.use_atsc_mode()) { + return mapCdmResponseType(wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC); + } + CdmCertificateType cdmCertType = kCertificateWidevine; if (cert_type == "X.509") { cdmCertType = kCertificateX509; @@ -551,6 +555,12 @@ status_t WVDrmPlugin::getPropertyString(const String8& name, return queryProperty(QUERY_KEY_MAX_USAGE_TABLE_ENTRIES, value); } else if (name == "oemCryptoApiMinorVersion") { return queryProperty(QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION, value); + } else if (name == "atscMode") { + if (mPropertySet.use_atsc_mode()) { + value = kEnable; + } else { + value = kDisable; + } } else { ALOGE("App requested unknown string property %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; @@ -663,6 +673,15 @@ status_t WVDrmPlugin::setPropertyString(const String8& name, return mapCdmResponseType(res); } else if (name == "decryptHashSessionId") { mDecryptHashSessionId = value.string(); + } else if (name == "atscMode") { + if (value == kEnable) { + mPropertySet.set_use_atsc_mode(true); + } else if (value == kDisable) { + mPropertySet.set_use_atsc_mode(false); + } else { + ALOGE("App requested unknown atsc mode %s", value.string()); + return android::BAD_VALUE; + } } else { ALOGE("App set unknown string property %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; @@ -1087,6 +1106,10 @@ bool WVDrmPlugin::initDataResemblesPSSH(const Vector& initData) { } status_t WVDrmPlugin::unprovision(const CdmIdentifier& identifier) { + if (mPropertySet.use_atsc_mode()) { + return mapCdmResponseType(wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC); + } + CdmResponseType res1 = mCDM->Unprovision(kSecurityLevelL1, identifier); CdmResponseType res3 = mCDM->Unprovision(kSecurityLevelL3, identifier); if (!isCdmResponseTypeSuccess(res1)) diff --git a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp index 205f842e..d14d6ed3 100644 --- a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp @@ -700,6 +700,12 @@ Return WVDrmPlugin::getProvisionRequest_1_2( std::string defaultUrl; std::vector request; + if (mPropertySet.use_atsc_mode()) { + _hidl_cb(mapCdmResponseType_1_2(wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC), + toHidlVec(request), hidl_string(defaultUrl)); + return Void(); + } + CdmIdentifier identifier; status = static_cast(mCdmIdentifierBuilder.getCdmIdentifier(&identifier)); if (status != Status_V1_2::OK) { @@ -1261,6 +1267,12 @@ Return WVDrmPlugin::getPropertyString(const hidl_string& propertyName, status = queryProperty(wvcdm::QUERY_KEY_MAX_USAGE_TABLE_ENTRIES, value); } else if (name == "oemCryptoApiMinorVersion") { status = queryProperty(wvcdm::QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION, value); + } else if (name == "atscMode") { + if (mPropertySet.use_atsc_mode()) { + value = kEnable; + } else { + value = kDisable; + } } else { ALOGE("App requested unknown string property %s", name.c_str()); status = Status::ERROR_DRM_CANNOT_HANDLE; @@ -1413,6 +1425,23 @@ Return WVDrmPlugin::setPropertyString(const hidl_string& propertyName, return mapCdmResponseType(res); } else if (name == "decryptHashSessionId") { mDecryptHashSessionId = _value.c_str(); + } else if (name == "atscMode") { + if (_value == kEnable) { + if (!mCdmIdentifierBuilder.set_use_atsc_mode(true)) { + ALOGE("Cdm identifier builder is sealed. Setting ATSC mode prohibited"); + return Status::BAD_VALUE; + } + mPropertySet.set_use_atsc_mode(true); + } else if (_value == kDisable) { + if (!mCdmIdentifierBuilder.set_use_atsc_mode(false)) { + ALOGE("Cdm identifier builder is sealed. Setting ATSC mode prohibited"); + return Status::BAD_VALUE; + } + mPropertySet.set_use_atsc_mode(false); + } else { + ALOGE("App requested unknown ATSC mode %s", _value.c_str()); + return Status::BAD_VALUE; + } } else { ALOGE("App set unknown string property %s", name.c_str()); return Status::ERROR_DRM_CANNOT_HANDLE; @@ -2077,6 +2106,9 @@ bool WVDrmPlugin::initDataResemblesPSSH(const std::vector& initData) { } Status WVDrmPlugin::unprovision(const CdmIdentifier& identifier) { + if (mPropertySet.use_atsc_mode()) + return mapCdmResponseType(wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC); + CdmResponseType res1 = mCDM->Unprovision(wvcdm::kSecurityLevelL1, identifier); CdmResponseType res3 = mCDM->Unprovision(wvcdm::kSecurityLevelL3, identifier); if (!isCdmResponseTypeSuccess(res1)) @@ -2149,6 +2181,13 @@ bool WVDrmPlugin::CdmIdentifierBuilder::set_origin(const std::string& id) { return true; } +bool WVDrmPlugin::CdmIdentifierBuilder::set_use_atsc_mode(bool enable) { + if (is_sealed()) return false; + mCdmIdentifier.app_package_name = + enable ? wvcdm::ATSC_APP_PACKAGE_NAME : mAppPackageName; + return true; +} + Status WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid() { if (mUseSpoid) { std::string deviceId; @@ -2159,7 +2198,8 @@ Status WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid() { SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, deviceId.data(), deviceId.length()); - SHA256_Update(&ctx, mAppPackageName.data(), mAppPackageName.length()); + SHA256_Update(&ctx, mCdmIdentifier.app_package_name.data(), + mCdmIdentifier.app_package_name.length()); SHA256_Update(&ctx, origin().data(), origin().length()); SHA256_Final(hash, &ctx); diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index 2dbb8669..6d04209f 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -901,6 +901,23 @@ TEST_F(WVDrmPluginTest, GetsProvisioningRequests) { }); } +TEST_F(WVDrmPluginTest, RejectsAtscProvisioningRequests) { + android::sp> cdm = new StrictMock(); + StrictMock crypto; + std::string appPackageName; + + WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); + + Status status = plugin.setPropertyString(hidl_string("atscMode"), + hidl_string("enable")); + + plugin.getProvisionRequest( + hidl_string(""), hidl_string(""), + [&](Status status, hidl_vec , hidl_string ) { + ASSERT_EQ(Status::ERROR_DRM_UNKNOWN, status); + }); +} + TEST_F(WVDrmPluginTest, HandlesProvisioningResponses) { android::sp> cdm = new StrictMock(); StrictMock crypto; @@ -1129,6 +1146,20 @@ TEST_F(WVDrmPluginTest, MuxesOriginUnprovisioningErrors) { }); } +TEST_F(WVDrmPluginTest, RejectsAtscUnprovisionDeviceRequests) { + android::sp> cdm = new StrictMock(); + StrictMock crypto; + std::string appPackageName; + + WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); + + Status status = plugin.setPropertyString(hidl_string("atscMode"), + hidl_string("enable")); + + status = plugin.unprovisionDevice(); + ASSERT_EQ(Status::ERROR_DRM_UNKNOWN, status); +} + TEST_F(WVDrmPluginTest, GetsSecureStops) { android::sp> cdm = new StrictMock(); StrictMock crypto; @@ -2708,6 +2739,108 @@ TEST_F(WVDrmPluginTest, AllowsStoringOfSessionSharingId) { EXPECT_EQ(sharingId, propertySet->session_sharing_id()); } +TEST_F(WVDrmPluginTest, CanSetAtscMode) { + android::sp> cdm = new StrictMock(); + StrictMock crypto; + std::string appPackageName = "com.test.package"; + + const CdmClientPropertySet* propertySet = nullptr; + CdmIdentifier cdmIdAtscModeNotSet; + CdmIdentifier cdmIdAtscModeSet; + CdmIdentifier cdmIdAtscModeReset; + + // Provide expected mock behavior + { + // Provide expected behavior in response to OpenSession and store the + // property set + EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), + SaveArg<1>(&propertySet), + SaveArg<2>(&cdmIdAtscModeNotSet), + testing::Return(wvcdm::NO_ERROR))) + .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), + SaveArg<1>(&propertySet), + SaveArg<2>(&cdmIdAtscModeSet), + testing::Return(wvcdm::NO_ERROR))) + .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), + SaveArg<1>(&propertySet), + SaveArg<2>(&cdmIdAtscModeReset), + testing::Return(wvcdm::NO_ERROR))); + + // Provide expected behavior when plugin requests session control info + EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) + .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); + + EXPECT_CALL(*cdm, CloseSession(_)) + .Times(AtLeast(0)); + } + + WVDrmPlugin plugin1(cdm.get(), appPackageName, &crypto, false); + + // Verify that ATSC mode is disabled by default + plugin1.openSession([&](Status status, hidl_vec hSessionId) { + ASSERT_EQ(Status::OK, status); + sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); + }); + ASSERT_THAT(propertySet, NotNull()); + EXPECT_FALSE(propertySet->use_atsc_mode()); + EXPECT_EQ(cdmIdAtscModeNotSet.app_package_name, appPackageName); + Status status = plugin1.closeSession(toHidlVec(sessionId)); + ASSERT_EQ(Status::OK, status); + + // Verify that ATSC mode can be enabled + WVDrmPlugin plugin2(cdm.get(), appPackageName, &crypto, false); + + // Test turning on ATSC mode + status = plugin2.setPropertyString(hidl_string("atscMode"), + hidl_string("enable")); + ASSERT_EQ(Status::OK, status); + + plugin2.openSession([&](Status status, hidl_vec hSessionId) { + ASSERT_EQ(Status::OK, status); + sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); + }); + ASSERT_THAT(propertySet, NotNull()); + EXPECT_TRUE(propertySet->use_atsc_mode()); + EXPECT_EQ(cdmIdAtscModeSet.app_package_name, wvcdm::ATSC_APP_PACKAGE_NAME); + status = plugin2.closeSession(toHidlVec(sessionId)); + ASSERT_EQ(Status::OK, status); + + + // Verify that ATSC mode can be enabled and disabled + WVDrmPlugin plugin3(cdm.get(), appPackageName, &crypto, false); + + // Test turning on ATSC mode + status = plugin3.setPropertyString(hidl_string("atscMode"), + hidl_string("enable")); + ASSERT_EQ(Status::OK, status); + + // Test turning off ATSC mode + status = plugin3.setPropertyString(hidl_string("atscMode"), + hidl_string("disable")); + ASSERT_EQ(Status::OK, status); + + plugin3.openSession([&](Status status, hidl_vec hSessionId) { + ASSERT_EQ(Status::OK, status); + sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); + }); + ASSERT_THAT(propertySet, NotNull()); + EXPECT_FALSE(propertySet->use_atsc_mode()); + EXPECT_EQ(cdmIdAtscModeReset.app_package_name, appPackageName); + status = plugin3.closeSession(toHidlVec(sessionId)); + ASSERT_EQ(Status::OK, status); + + // Test turning on and off ATSC mode. They should be rejected since the SPOID + // has been calculated + status = plugin3.setPropertyString(hidl_string("atscMode"), + hidl_string("enable")); + ASSERT_NE(Status::OK, status); + + status = plugin3.setPropertyString(hidl_string("atscMode"), + hidl_string("disable")); + ASSERT_NE(Status::OK, status); +} + TEST_F(WVDrmPluginTest, CanSetDecryptHashProperties) { android::sp> cdm = new StrictMock(); StrictMock crypto;