diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index e943ff33..d8898635 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -40,15 +40,6 @@ class CdmEngine { CdmEngine(FileSystem* file_system, const std::string& spoid = EMPTY_SPOID); virtual ~CdmEngine(); - // Set service certificate used when provisioning under this CDM/CdmEngine. - // If no valid service certificate is set, a default one associated with - // the WV production provisioning server will be used. - virtual CdmResponseType SetProvisioningServiceCertificate( - const std::string& certificate); - - // Report whether the service certificate has been set. - virtual bool HasProvisioningServiceCertificate(); - // Session related methods virtual CdmResponseType OpenSession( const CdmKeySystem& key_system, CdmClientPropertySet* property_set, @@ -166,6 +157,7 @@ class CdmEngine { // Generate and return a valid provisioning request. virtual CdmResponseType GetProvisioningRequest( CdmCertificateType cert_type, const std::string& cert_authority, + const std::string& service_certificate, CdmProvisioningRequest* request, std::string* default_url); // Verify and process a provisioning response. @@ -288,6 +280,8 @@ class CdmEngine { virtual metrics::EngineMetrics* GetMetrics() { return &metrics_; } + virtual CdmResponseType ValidateServiceCertificate(const std::string& cert); + private: // private methods CdmResponseType OpenSession( @@ -328,9 +322,6 @@ class CdmEngine { static bool seeded_; - // Service certificate for the provisioning server. - ServiceCertificate provisioning_service_certificate_; - // usage related variables scoped_ptr usage_session_; scoped_ptr usage_property_set_; diff --git a/libwvdrmengine/cdm/core/include/properties.h b/libwvdrmengine/cdm/core/include/properties.h index de06e4ed..2987f87f 100644 --- a/libwvdrmengine/cdm/core/include/properties.h +++ b/libwvdrmengine/cdm/core/include/properties.h @@ -69,10 +69,6 @@ class Properties { std::string* service_certificate); static bool SetServiceCertificate(const CdmSessionId& session_id, const std::string& service_certificate); - static bool GetDeviceProvisioningServiceCertificate( - const CdmSessionId& session_id, std::string* service_certificate); - static bool SetDeviceProvisioningServiceCertificate( - const CdmSessionId& session_id, const std::string& service_certificate); static bool UsePrivacyMode(const CdmSessionId& session_id); static uint32_t GetSessionSharingId(const CdmSessionId& session_id); diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index c2977331..cd1f4b8d 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -85,15 +85,6 @@ CdmEngine::CdmEngine(FileSystem* file_system, const std::string& spoid) CdmEngine::~CdmEngine() {} -CdmResponseType CdmEngine::SetProvisioningServiceCertificate( - const std::string& certificate) { - return provisioning_service_certificate_.Init(certificate); -} - -bool CdmEngine::HasProvisioningServiceCertificate() { - return provisioning_service_certificate_.has_certificate(); -} - CdmResponseType CdmEngine::OpenSession( const CdmKeySystem& key_system, CdmClientPropertySet* property_set, const CdmSessionId& forced_session_id, WvCdmEventListener* event_listener) { @@ -758,7 +749,8 @@ CdmResponseType CdmEngine::QueryOemCryptoSessionId( */ CdmResponseType CdmEngine::GetProvisioningRequest( CdmCertificateType cert_type, const std::string& cert_authority, - CdmProvisioningRequest* request, std::string* default_url) { + const std::string& service_certificate, CdmProvisioningRequest* request, + std::string* default_url) { LOGI("CdmEngine::GetProvisioningRequest"); if (!request) { LOGE("CdmEngine::GetProvisioningRequest: invalid output parameters"); @@ -774,8 +766,7 @@ CdmResponseType CdmEngine::GetProvisioningRequest( if (NULL == cert_provisioning_.get()) { cert_provisioning_.reset( new CertificateProvisioning(metrics_.GetCryptoMetrics())); - CdmResponseType status = cert_provisioning_->Init( - provisioning_service_certificate_.certificate()); + CdmResponseType status = cert_provisioning_->Init(service_certificate); if (status != NO_ERROR) return status; } CdmResponseType ret = cert_provisioning_->GetProvisioningRequest( @@ -1711,6 +1702,11 @@ void CdmEngine::OnKeyReleaseEvent(const CdmKeySetId& key_set_id) { } } +CdmResponseType CdmEngine::ValidateServiceCertificate(const std::string& cert) { + ServiceCertificate certificate; + return certificate.Init(cert); +} + std::string CdmEngine::MapHdcpVersion( CryptoSession::HdcpCapability version) { switch (version) { diff --git a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp index bf1e76e8..066baf28 100644 --- a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp @@ -193,13 +193,11 @@ class WvCdmEnginePreProvTest : public testing::Test { // try to provision. This is needed for testing nonce floods. CryptoSession keep_alive(cdm_engine_.GetMetrics()->GetCryptoMetrics()); - ASSERT_EQ(NO_ERROR, cdm_engine_.SetProvisioningServiceCertificate( - g_provisioning_service_certificate)); CdmResponseType result = NO_ERROR; for(int i = 0; i < 2; ++i) { // Retry once if there is a nonce problem. result = cdm_engine_.GetProvisioningRequest( - cert_type, cert_authority, &prov_request, - &provisioning_server_url); + cert_type, cert_authority, g_provisioning_service_certificate, + &prov_request, &provisioning_server_url); if (result == CERT_PROVISIONING_NONCE_GENERATION_ERROR) { LOGW("Woops. Nonce problem. Try again?"); sleep(1); @@ -295,11 +293,9 @@ class WvCdmEnginePreProvTestUatBinary : public WvCdmEnginePreProvTest { CdmCertificateType cert_type = kCertificateWidevine; std::string cert_authority; std::string cert, wrapped_key; - ASSERT_EQ(NO_ERROR, cdm_engine_.SetProvisioningServiceCertificate( - g_provisioning_service_certificate)); ASSERT_EQ(NO_ERROR, cdm_engine_.GetProvisioningRequest( - cert_type, cert_authority, &binary_prov_request, - &provisioning_server_url)); + cert_type, cert_authority, g_provisioning_service_certificate, + &binary_prov_request, &provisioning_server_url)); // prov_request is binary - base64 encode it std::string prov_request(Base64SafeEncodeNoPad( @@ -508,18 +504,20 @@ class WvCdmEngineTest : public WvCdmEnginePreProvTest { std::string server_url_; }; -// Test that service certificate is initially absent. -TEST_F(WvCdmEnginePreProvTestStaging, - ProvisioningServiceCertificateInitialNoneTest) { - ASSERT_FALSE(cdm_engine_.HasProvisioningServiceCertificate()); +// Tests to validate service certificate +TEST_F(WvCdmEnginePreProvTestUat, ProvisioningServiceCertificateValidTest) { + ASSERT_EQ( + cdm_engine_.ValidateServiceCertificate( + g_provisioning_service_certificate), + NO_ERROR); }; -// Test that service certificate can be properly installed. -TEST_F(WvCdmEnginePreProvTestStaging, ProvisioningServiceCertificateGoodTest) { - ASSERT_EQ(cdm_engine_.SetProvisioningServiceCertificate( - g_license_service_certificate), - NO_ERROR); - ASSERT_TRUE(cdm_engine_.HasProvisioningServiceCertificate()); +TEST_F(WvCdmEnginePreProvTestUat, ProvisioningServiceCertificateInvalidTest) { + std::string certificate = g_provisioning_service_certificate; + // Add four nulls to the beginning of the cert to invalidate it + certificate.insert(0, 4, 0); + + ASSERT_NE(cdm_engine_.ValidateServiceCertificate(certificate), NO_ERROR); }; // Test that provisioning works, even if device is already provisioned. diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index ffc3e27b..0435e973 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -82,8 +82,8 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { // Provisioning related methods virtual CdmResponseType GetProvisioningRequest( CdmCertificateType cert_type, const std::string& cert_authority, - const CdmIdentifier& identifier, CdmProvisioningRequest* request, - std::string* default_url); + const CdmIdentifier& identifier, const std::string& service_certificate, + CdmProvisioningRequest* request, std::string* default_url); virtual CdmResponseType HandleProvisioningResponse( const CdmIdentifier& identifier, CdmProvisioningResponse& response, diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index cfb76046..1e0fcce8 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -192,11 +192,12 @@ CdmResponseType WvContentDecryptionModule::QueryOemCryptoSessionId( CdmResponseType WvContentDecryptionModule::GetProvisioningRequest( CdmCertificateType cert_type, const std::string& cert_authority, - const CdmIdentifier& identifier, CdmProvisioningRequest* request, - std::string* default_url) { + const CdmIdentifier& identifier, const std::string& service_certificate, + CdmProvisioningRequest* request, std::string* default_url) { CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); CdmResponseType sts; M_TIME(sts = cdm_engine->GetProvisioningRequest(cert_type, cert_authority, + service_certificate, request, default_url), cdm_engine->GetMetrics(), cdm_engine_get_provisioning_request_, sts); return sts; diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index 00cb548e..92023e12 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -40,6 +40,7 @@ const uint32_t kMinute = 60; const uint32_t kClockTolerance = 10; const uint32_t kMaxUsageTableSize = 50; +const std::string kEmptyServiceCertificate; // Default license server, can be configured using --server command line option // Default key id (pssh), can be configured using --keyid command line option @@ -443,8 +444,8 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase { std::string cert_authority, cert, wrapped_key; status = decryptor_.GetProvisioningRequest( - cert_type, cert_authority, kDefaultCdmIdentifier, &key_msg_, - &provisioning_server_url); + cert_type, cert_authority, kDefaultCdmIdentifier, + kEmptyServiceCertificate, &key_msg_, &provisioning_server_url); EXPECT_EQ(NO_ERROR, status); if (NO_ERROR != status) return; EXPECT_EQ(provisioning_server_url, g_config->provisioning_server()); diff --git a/libwvdrmengine/cdm/test/cdm_feature_test.cpp b/libwvdrmengine/cdm/test/cdm_feature_test.cpp index 2f815856..bcb9d9a7 100644 --- a/libwvdrmengine/cdm/test/cdm_feature_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_feature_test.cpp @@ -54,6 +54,7 @@ const int kHttpOk = 200; // The following two responses are unused, but left here for human debuggers. // const int kHttpBadRequest = 400; // const int kHttpInternalServerError = 500; +const std::string kEmptyServiceCertificate; // Default license server, can be configured using --server command line option // Default key id (pssh), can be configured using --keyid command line option @@ -418,7 +419,9 @@ TEST_F(WvCdmFeatureTest, OEMCertificateProvisioning) { EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(cert_type, cert_authority, - kDefaultCdmIdentifier, &key_msg_, + kDefaultCdmIdentifier, + kEmptyServiceCertificate, + &key_msg_, &provisioning_server_url)); EXPECT_EQ(provisioning_server_url, g_config->provisioning_server()); @@ -453,7 +456,9 @@ TEST_F(WvCdmFeatureTest, KeyboxProvisioning) { EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(cert_type, cert_authority, - kDefaultCdmIdentifier, &key_msg_, + kDefaultCdmIdentifier, + kEmptyServiceCertificate, + &key_msg_, &provisioning_server_url)); EXPECT_EQ(provisioning_server_url, g_config->provisioning_server()); diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 20ad5cb8..3ca36bed 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -57,6 +57,8 @@ const wvcdm::CdmIdentifier kExampleIdentifier = { 7 }; +const std::string kEmptyServiceCertificate; + // Protobuf generated classes using video_widevine::LicenseIdentification; using video_widevine::LicenseRequest_ContentIdentification; @@ -1170,6 +1172,33 @@ FourSampleDecryptionInfo kCenc30SwitchCipherData[8] = { kCenc30Cbc1Key33Sample, kCenc30Cbc1Key32Sample, } }, }; +// NOTE: Provider ID = staging.google.com +const std::string kGoogleStagingServiceCertificate = wvcdm::a2bs_hex( + "0ac102080312101705b917cc1204868b06333a2f772a8c1882b482920522" + "8e023082010a028201010099ed5b3b327dab5e24efc3b62a95b598520ad5" + "bccb37503e0645b814d876b8df40510441ad8ce3adb11bb88c4e725a5e4a" + "9e0795291d58584023a7e1af0e38a91279393008610b6f158c878c7e21bf" + "fbfeea77e1019e1e5781e8a45f46263d14e60e8058a8607adce04fac8457" + "b137a8d67ccdeb33705d983a21fb4eecbd4a10ca47490ca47eaa5d438218" + "ddbaf1cade3392f13d6ffb6442fd31e1bf40b0c604d1c4ba4c9520a4bf97" + "eebd60929afceef55bbaf564e2d0e76cd7c55c73a082b996120b8359edce" + "24707082680d6f67c6d82c4ac5f3134490a74eec37af4b2f010c59e82843" + "e2582f0b6b9f5db0fc5e6edf64fbd308b4711bcf1250019c9f5a09020301" + "00013a146c6963656e73652e7769646576696e652e636f6d128003ae3473" + "14b5a835297f271388fb7bb8cb5277d249823cddd1da30b93339511eb3cc" + "bdea04b944b927c121346efdbdeac9d413917e6ec176a10438460a503bc1" + "952b9ba4e4ce0fc4bfc20a9808aaaf4bfcd19c1dcfcdf574ccac28d1b410" + "416cf9de8804301cbdb334cafcd0d40978423a642e54613df0afcf96ca4a" + "9249d855e42b3a703ef1767f6a9bd36d6bf82be76bbf0cba4fde59d2abcc" + "76feb64247b85c431fbca52266b619fc36979543fca9cbbdbbfafa0e1a55" + "e755a3c7bce655f9646f582ab9cf70aa08b979f867f63a0b2b7fdb362c5b" + "c4ecd555d85bcaa9c593c383c857d49daab77e40b7851ddfd24998808e35" + "b258e75d78eac0ca16f7047304c20d93ede4e8ff1c6f17e6243e3f3da8fc" + "1709870ec45fba823a263f0cefa1f7093b1909928326333705043a29bda6" + "f9b4342cc8df543cb1a1182f7c5fff33f10490faca5b25360b76015e9c5a" + "06ab8ee02f00d2e8d5986104aacc4dd475fd96ee9ce4e326f21b83c70585" + "77b38732cddabc6a6bed13fb0d49d38a45eb87a5f4"); + } // namespace namespace wvcdm { @@ -1570,8 +1599,9 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase { std::string cert_authority, cert, wrapped_key; status = decryptor_.GetProvisioningRequest(cert_type, cert_authority, - identifier, &key_msg_, - &provisioning_server); + identifier, + kEmptyServiceCertificate, + &key_msg_, &provisioning_server); EXPECT_EQ(wvcdm::NO_ERROR, status); if (NO_ERROR != status) return; EXPECT_EQ(provisioning_server, g_config->provisioning_server()); @@ -1652,8 +1682,38 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) { EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, - kDefaultCdmIdentifier, &key_msg_, - &provisioning_server)); + kDefaultCdmIdentifier, + kEmptyServiceCertificate, + &key_msg_, &provisioning_server)); + EXPECT_EQ(provisioning_server, g_config->provisioning_server()); + + std::string response = + GetCertRequestResponse(g_config->provisioning_server()); + EXPECT_NE(0, static_cast(response.size())); + EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse( + kDefaultCdmIdentifier, response, &cert, + &wrapped_key)); + EXPECT_EQ(0, static_cast(cert.size())); + EXPECT_EQ(0, static_cast(wrapped_key.size())); + decryptor_.CloseSession(session_id_); +} + +TEST_F(WvCdmRequestLicenseTest, ProvisioningTestWithServiceCertificate) { + CdmResponseType status = + decryptor_.OpenSession(g_key_system, NULL, + kDefaultCdmIdentifier, NULL, + &session_id_); + EXPECT_TRUE(status == NEED_PROVISIONING || status == NO_ERROR) + << "Failure to open session. error: " << status; + std::string provisioning_server; + CdmCertificateType cert_type = kCertificateWidevine; + std::string cert_authority, cert, wrapped_key; + + EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest( + cert_type, cert_authority, + kDefaultCdmIdentifier, + kGoogleStagingServiceCertificate, + &key_msg_, &provisioning_server)); EXPECT_EQ(provisioning_server, g_config->provisioning_server()); std::string response = @@ -1670,17 +1730,19 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) { TEST_F(WvCdmRequestLicenseTest, L3ProvisioningTest) { TestWvCdmClientPropertySet property_set_L3; property_set_L3.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3); - EXPECT_EQ(NEED_PROVISIONING, - decryptor_.OpenSession(g_key_system, &property_set_L3, - kDefaultCdmIdentifier, NULL, - &session_id_)); + CdmResponseType status = + decryptor_.OpenSession(g_key_system, &property_set_L3, + kDefaultCdmIdentifier, NULL, &session_id_); + EXPECT_TRUE(status == NEED_PROVISIONING || status == NO_ERROR) + << "Failure to open session. error: " << status; std::string provisioning_server; CdmCertificateType cert_type = kCertificateWidevine; std::string cert_authority, cert, wrapped_key; EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, - kDefaultCdmIdentifier, &key_msg_, + kDefaultCdmIdentifier, + kEmptyServiceCertificate, &key_msg_, &provisioning_server)); EXPECT_EQ(provisioning_server, g_config->provisioning_server()); @@ -1771,13 +1833,15 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningInterposedRetryTest) { EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, - kDefaultCdmIdentifier, &key_msg1, + kDefaultCdmIdentifier, + kEmptyServiceCertificate, &key_msg1, &provisioning_server)); EXPECT_EQ(provisioning_server, g_config->provisioning_server()); EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, - kDefaultCdmIdentifier, &key_msg2, + kDefaultCdmIdentifier, + kEmptyServiceCertificate, &key_msg2, &provisioning_server)); EXPECT_EQ(provisioning_server, g_config->provisioning_server()); @@ -1813,13 +1877,15 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningInterspersedRetryTest) { EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, - kDefaultCdmIdentifier, &key_msg1, + kDefaultCdmIdentifier, + kEmptyServiceCertificate, &key_msg1, &provisioning_server)); EXPECT_EQ(provisioning_server, g_config->provisioning_server()); EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, - kDefaultCdmIdentifier, &key_msg2, + kDefaultCdmIdentifier, + kEmptyServiceCertificate, &key_msg2, &provisioning_server)); EXPECT_EQ(provisioning_server, g_config->provisioning_server()); @@ -1857,7 +1923,8 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_X509ProvisioningTest) { EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, - kDefaultCdmIdentifier, &key_msg_, + kDefaultCdmIdentifier, + kEmptyServiceCertificate, &key_msg_, &provisioning_server)); EXPECT_EQ(provisioning_server, g_config->provisioning_server()); @@ -1897,7 +1964,8 @@ TEST_F(WvCdmRequestLicenseTest, PropertySetTest) { std::string cert_authority, cert, wrapped_key; EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, kDefaultCdmIdentifier, - &key_msg_, &provisioning_server)); + kEmptyServiceCertificate, &key_msg_, + &provisioning_server)); EXPECT_EQ(provisioning_server, g_config->provisioning_server()); std::string response = GetCertRequestResponse(g_config->provisioning_server()); @@ -1973,7 +2041,8 @@ TEST_F(WvCdmRequestLicenseTest, ForceL3Test) { std::string cert_authority, cert, wrapped_key; EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, kDefaultCdmIdentifier, - &key_msg_, &provisioning_server)); + kEmptyServiceCertificate, &key_msg_, + &provisioning_server)); EXPECT_EQ(provisioning_server, g_config->provisioning_server()); std::string response = GetCertRequestResponse(g_config->provisioning_server()); @@ -2262,6 +2331,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) { std::string cert_authority, cert, wrapped_key; EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, kDefaultCdmIdentifier, + kEmptyServiceCertificate, &key_msg_, &provisioning_server)); EXPECT_EQ(provisioning_server, g_config->provisioning_server()); std::string response = @@ -2337,6 +2407,7 @@ TEST_F(WvCdmRequestLicenseTest, std::string cert_authority, cert, wrapped_key; EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest( cert_type, cert_authority, kDefaultCdmIdentifier, + kEmptyServiceCertificate, &key_msg_, &provisioning_server_url)); EXPECT_EQ(provisioning_server_url, g_config->provisioning_server()); std::string response = diff --git a/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp b/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp index 86aa865d..a99e1f08 100644 --- a/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp +++ b/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp @@ -22,6 +22,12 @@ using ::testing::Lt; using ::testing::Test; using wvcdm::CdmResponseType; +namespace { + +const std::string kEmptyServiceCertificate; + +} // unnamed namespace + namespace wvcdm { // This class is used to test the metrics-related feaures of the @@ -46,9 +52,10 @@ TEST_F(WvContentDecryptionModuleMetricsTest, EngineOnlyMetrics) { // This call will create a CdmEngine instance with an EngineMetrics instance. EXPECT_EQ(wvcdm::NO_ERROR, - decryptor_.GetProvisioningRequest(cert_type, cert_authority, - kDefaultCdmIdentifier, &request, - &provisioning_server_url)); + decryptor_.GetProvisioningRequest( + cert_type, cert_authority, kDefaultCdmIdentifier, + kEmptyServiceCertificate, &request, + &provisioning_server_url)); drm_metrics::WvCdmMetrics metrics; ASSERT_EQ(wvcdm::NO_ERROR, diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index 1cf4af41..157fc0e4 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -261,6 +261,8 @@ class WVDrmPlugin : public android::DrmPlugin, CdmIdentifier mCdmIdentifier; + std::string mProvisioningServiceCertificate; + status_t queryProperty(const std::string& property, std::string& stringValue) const; diff --git a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h index 60d6f6a1..3d393fd6 100644 --- a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h @@ -402,6 +402,8 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, map mCryptoSessions; sp mListener; + std::string mProvisioningServiceCertificate; + Status queryProperty(const std::string& property, std::string& stringValue) const; diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index ef59a7a0..1f3ed442 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -370,11 +370,10 @@ status_t WVDrmPlugin::getProvisionRequest(const String8& cert_type, string cdmCertAuthority = cert_authority.string(); - CdmResponseType res = mCDM->GetProvisioningRequest(cdmCertType, - cdmCertAuthority, - mCdmIdentifier, - &cdmProvisionRequest, - &cdmDefaultUrl); + CdmResponseType res = mCDM->GetProvisioningRequest( + cdmCertType, cdmCertAuthority, mCdmIdentifier, + mProvisioningServiceCertificate, &cdmProvisionRequest, + &cdmDefaultUrl); if (isCdmResponseTypeSuccess(res)) { request = ToVector(cdmProvisionRequest); @@ -541,6 +540,8 @@ status_t WVDrmPlugin::getPropertyByteArray(const String8& name, return queryProperty(QUERY_KEY_PROVISIONING_ID, value); } else if (name == "serviceCertificate") { value = ToVector(mPropertySet.service_certificate()); + } else if (name == "provisioningServiceCertificate") { + value = ToVector(mProvisioningServiceCertificate); } else if (name == "metrics") { std::string serialized_metrics; drm_metrics::WvCdmMetrics metrics; @@ -642,6 +643,13 @@ status_t WVDrmPlugin::setPropertyByteArray(const String8& name, } else { return android::BAD_VALUE; } + } else if (name == "provisioningServiceCertificate") { + std::string cert(value.begin(), value.end()); + if (value.isEmpty() || mCDM->IsValidServiceCertificate(cert)) { + mProvisioningServiceCertificate = cert; + } else { + return android::BAD_VALUE; + } } else { ALOGE("App set unknown byte array property %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; diff --git a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp index eb790f5b..f21b8564 100644 --- a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp @@ -596,8 +596,8 @@ Return WVDrmPlugin::restoreKeys(const hidl_vec& sessionId, std::string cdmCertAuthority = certificateAuthority; CdmResponseType res = mCDM->GetProvisioningRequest( - cdmCertType, cdmCertAuthority, identifier, &cdmProvisionRequest, - &cdmDefaultUrl); + cdmCertType, cdmCertAuthority, identifier, + mProvisioningServiceCertificate, &cdmProvisionRequest, &cdmDefaultUrl); if (isCdmResponseTypeSuccess(res)) { request = StrToVector(cdmProvisionRequest); defaultUrl.clear(); @@ -996,6 +996,8 @@ Return WVDrmPlugin::getPropertyByteArray( } } else if (name == "serviceCertificate") { value = StrToVector(mPropertySet.service_certificate()); + } else if (name == "provisioningServiceCertificate") { + value = StrToVector(mProvisioningServiceCertificate); } else if (name == "metrics") { drm_metrics::WvCdmMetrics metrics; // If the cdm identifier is not yet sealed, then there are no metrics @@ -1126,6 +1128,13 @@ Return WVDrmPlugin::setPropertyByteArray( } else { return Status::BAD_VALUE; } + } else if (name == "provisioningServiceCertificate") { + std::string cert(_value.begin(), _value.end()); + if (_value.empty() || mCDM->IsValidServiceCertificate(cert)) { + mProvisioningServiceCertificate = cert; + } else { + return Status::BAD_VALUE; + } } else { ALOGE("App set unknown byte array property %s", name.c_str()); return Status::ERROR_DRM_CANNOT_HANDLE; diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index 24e68acb..08931bb5 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -173,9 +173,10 @@ class MockCDM : public WvContentDecryptionModule { MOCK_METHOD2(QueryOemCryptoSessionId, CdmResponseType(const CdmSessionId&, CdmQueryMap*)); - MOCK_METHOD5(GetProvisioningRequest, CdmResponseType(CdmCertificateType, + MOCK_METHOD6(GetProvisioningRequest, CdmResponseType(CdmCertificateType, const std::string&, const CdmIdentifier&, + const std::string&, CdmProvisioningRequest*, std::string*)); @@ -803,9 +804,10 @@ TEST_F(WVDrmPluginTest, GetsProvisioningRequests) { static const char* kDefaultUrl = "http://google.com/"; EXPECT_CALL(*cdm, GetProvisioningRequest(kCertificateWidevine, IsEmpty(), - HasOrigin(EMPTY_ORIGIN), _, _)) - .WillOnce(DoAll(SetArgPointee<3>(cdmRequest), - SetArgPointee<4>(kDefaultUrl), + HasOrigin(EMPTY_ORIGIN), IsEmpty(), + _, _)) + .WillOnce(DoAll(SetArgPointee<4>(cdmRequest), + SetArgPointee<5>(kDefaultUrl), testing::Return(wvcdm::NO_ERROR))); WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); diff --git a/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp index 066505b4..0970d182 100644 --- a/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp @@ -85,9 +85,10 @@ class MockCDM : public WvContentDecryptionModule { MOCK_METHOD2(QueryOemCryptoSessionId, CdmResponseType(const CdmSessionId&, CdmQueryMap*)); - MOCK_METHOD5(GetProvisioningRequest, CdmResponseType(CdmCertificateType, + MOCK_METHOD6(GetProvisioningRequest, CdmResponseType(CdmCertificateType, const std::string&, const CdmIdentifier&, + const std::string&, CdmProvisioningRequest*, std::string*)); @@ -605,9 +606,10 @@ TEST_F(WVDrmPluginTest, GetsProvisioningRequests) { static const char* kDefaultUrl = "http://google.com/"; EXPECT_CALL(*cdm, GetProvisioningRequest(kCertificateWidevine, IsEmpty(), - HasOrigin(EMPTY_ORIGIN), _, _)) - .WillOnce(DoAll(SetArgPointee<3>(cdmRequest), - SetArgPointee<4>(kDefaultUrl), + HasOrigin(EMPTY_ORIGIN), IsEmpty(), + _, _)) + .WillOnce(DoAll(SetArgPointee<4>(cdmRequest), + SetArgPointee<5>(kDefaultUrl), Return(wvcdm::NO_ERROR))); Vector request;