diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index 511a88bf..bc6145f8 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -92,7 +92,7 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { CdmProvisioningRequest* request, std::string* default_url); virtual CdmResponseType HandleProvisioningResponse( - const CdmIdentifier& identifier, CdmProvisioningResponse& response, + const CdmIdentifier& identifier, const CdmProvisioningResponse& response, RequestedSecurityLevel requested_security_level, std::string* cert, std::string* wrapped_key); diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 2ff88768..a0f6edae 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -227,7 +227,7 @@ CdmResponseType WvContentDecryptionModule::GetProvisioningRequest( } CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse( - const CdmIdentifier& identifier, CdmProvisioningResponse& response, + const CdmIdentifier& identifier, const CdmProvisioningResponse& response, RequestedSecurityLevel requested_security_level, std::string* cert, std::string* wrapped_key) { CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 21cff53d..b960cbcb 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -52,7 +52,11 @@ namespace { // HTTP response codes. const int kHttpOk = 200; -const int kDrmCertificateExpiryPeriod = 150; + +// For tests checking functionality of expiring. +constexpr uint32_t kDrmCertificateExpiryPeriod = 120; +constexpr uint32_t kDrmCertificateExpirySleepPeriod = + kDrmCertificateExpiryPeriod + 30; const wvcdm::CdmIdentifier kExampleIdentifier = { wvcdm::EMPTY_SPOID, "com.example", "com.example", 7, 9}; @@ -1868,11 +1872,26 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase { // Post a request and extract the signed provisioning message from // the HTTP response. - std::string GetCertRequestResponse(const std::string& server_url) { + // Setting a non-zero value to |duration_seconds| will request a + // limited duration DRM certificate. + std::string GetCertRequestResponse(const std::string& server_url, + uint32_t duration_seconds = 0) { // Use secure connection and chunk transfer coding. - UrlRequest url_request(server_url); + std::string actual_url = server_url; + if (duration_seconds > 0) { + const auto query_start = actual_url.find('?'); + if (query_start == std::string::npos) { + actual_url.push_back('?'); + } else { + actual_url.push_back('&'); + } + actual_url.append("options.expiration_delta_seconds="); + actual_url.append(std::to_string(duration_seconds)); + } + + UrlRequest url_request(actual_url); EXPECT_TRUE(url_request.is_connected()) - << "Fail to connect to " << server_url; + << "Fail to connect to " << actual_url; url_request.PostCertRequestInQueryString(key_msg_); std::string message; EXPECT_TRUE(url_request.GetResponse(&message)); @@ -2573,6 +2592,10 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningRevocationTest) { } } +// Test checks that the CDM correctly reports provisioning status when +// a certificate has expired. It is expected that the CDM reports that +// the specified CDM engine is provisioned only during the certificate's +// validity period. TEST_F(WvCdmRequestLicenseTest, ProvisioningWithExpiringCertTest) { EXPECT_EQ(NO_ERROR, decryptor_->Unprovision(kSecurityLevelL1, kExampleIdentifier)); @@ -2584,7 +2607,7 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningWithExpiringCertTest) { // Provision std::string provisioning_server; - CdmCertificateType cert_type = kCertificateWidevine; + const CdmCertificateType cert_type = kCertificateWidevine; std::string cert_authority, cert, wrapped_key; EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->GetProvisioningRequest( @@ -2592,18 +2615,19 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningWithExpiringCertTest) { kEmptyServiceCertificate, kLevelDefault, &key_msg_, &provisioning_server)); - std::string response = GetCertRequestResponse(config.provisioning_server()); - EXPECT_NE(0, static_cast(response.size())); + const std::string response = GetCertRequestResponse( + config.provisioning_server(), kDrmCertificateExpiryPeriod); + EXPECT_FALSE(response.empty()) << "Failed to get DRM provisioning response"; EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->HandleProvisioningResponse( kExampleIdentifier, response, kLevelDefault, &cert, &wrapped_key)); - EXPECT_EQ(0, static_cast(cert.size())); - EXPECT_EQ(0, static_cast(wrapped_key.size())); - decryptor_->CloseSession(session_id_); + EXPECT_TRUE(cert.empty()) << "Widevine certs should not be returned"; + EXPECT_TRUE(wrapped_key.empty()) + << "Keys from Widevine certs should not be returned"; // Make sure it is provisioned, then wait for certificate expiry period EXPECT_TRUE(IsProvisioned(kExampleIdentifier, kLevelDefault)); - sleep(kDrmCertificateExpiryPeriod); + sleep(kDrmCertificateExpirySleepPeriod); // Verify that it is no longer provisioned after the certificate expires EXPECT_FALSE(IsProvisioned(kExampleIdentifier, kLevelDefault)); @@ -2781,6 +2805,8 @@ TEST_F(WvCdmRequestLicenseTest, AddStreamingKeyTest) { decryptor_->CloseSession(session_id_); } +// Test checks that the CDM does not allow key request generations +// if the DRM certificate is expired. TEST_F(WvCdmRequestLicenseTest, StreamingWithExpiringCertTest) { EXPECT_EQ(NO_ERROR, decryptor_->Unprovision(kSecurityLevelL1, kExampleIdentifier)); @@ -2800,13 +2826,15 @@ TEST_F(WvCdmRequestLicenseTest, StreamingWithExpiringCertTest) { kEmptyServiceCertificate, kLevelDefault, &key_msg_, &provisioning_server)); - std::string response = GetCertRequestResponse(config.provisioning_server()); - EXPECT_NE(0, static_cast(response.size())); + const std::string response = GetCertRequestResponse( + config.provisioning_server(), kDrmCertificateExpiryPeriod); + EXPECT_FALSE(response.empty()) << "Failed to get DRM provisioning response"; EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->HandleProvisioningResponse( kExampleIdentifier, response, kLevelDefault, &cert, &wrapped_key)); - EXPECT_EQ(0, static_cast(cert.size())); - EXPECT_EQ(0, static_cast(wrapped_key.size())); + EXPECT_TRUE(cert.empty()) << "Widevine certs should not be returned"; + EXPECT_TRUE(wrapped_key.empty()) + << "Keys from Widevine certs should not be returned"; EXPECT_TRUE(IsProvisioned(kExampleIdentifier, kLevelDefault)); @@ -2821,6 +2849,17 @@ TEST_F(WvCdmRequestLicenseTest, StreamingWithExpiringCertTest) { nullptr); VerifyKeyRequestResponse(config_.license_server(), config_.client_auth()); decryptor_->CloseSession(session_id_); + + sleep(kDrmCertificateExpirySleepPeriod); + + // Fetch another stream license, after expiry. + EXPECT_EQ(NO_ERROR, + decryptor_->OpenSession(config_.key_system(), nullptr, + kExampleIdentifier, nullptr, &session_id_)); + GenerateKeyRequest(NEED_PROVISIONING, ISO_BMFF_VIDEO_MIME_TYPE, + binary_key_id(), app_parameters, kLicenseTypeStreaming, + kExampleIdentifier, nullptr); + decryptor_->CloseSession(session_id_); } TEST_F(WvCdmRequestLicenseTest, AddKeyOfflineTest) { @@ -2864,6 +2903,8 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) { decryptor_->CloseSession(session_id_); } +// Test checks that the CDM allows reloading of previously acquired offline +// licenses even if the DRM certificate has expired. TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeysWithExpiringCertTest) { EXPECT_EQ(NO_ERROR, decryptor_->Unprovision(kSecurityLevelL1, kExampleIdentifier)); @@ -2875,7 +2916,7 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeysWithExpiringCertTest) { // Provision std::string provisioning_server; - CdmCertificateType cert_type = kCertificateWidevine; + const CdmCertificateType cert_type = kCertificateWidevine; std::string cert_authority, cert, wrapped_key; EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->GetProvisioningRequest( @@ -2883,13 +2924,15 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeysWithExpiringCertTest) { kEmptyServiceCertificate, kLevelDefault, &key_msg_, &provisioning_server)); - std::string response = GetCertRequestResponse(config.provisioning_server()); - EXPECT_NE(0, static_cast(response.size())); + const std::string response = GetCertRequestResponse( + config.provisioning_server(), kDrmCertificateExpiryPeriod); + EXPECT_FALSE(response.empty()) << "Failed to get DRM provisioning response"; EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->HandleProvisioningResponse( kExampleIdentifier, response, kLevelDefault, &cert, &wrapped_key)); - EXPECT_EQ(0, static_cast(cert.size())); - EXPECT_EQ(0, static_cast(wrapped_key.size())); + EXPECT_TRUE(cert.empty()) << "Widevine certs should not be returned"; + EXPECT_TRUE(wrapped_key.empty()) + << "Keys from Widevine certs should not be returned"; EXPECT_TRUE(IsProvisioned(kExampleIdentifier, kLevelDefault)); @@ -2908,19 +2951,20 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeysWithExpiringCertTest) { nullptr); VerifyKeyRequestResponse(config_.license_server(), client_auth); - CdmKeySetId key_set_id = key_set_id_; + const CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); decryptor_->CloseSession(session_id_); session_id_.clear(); // Wait till certificate expires - sleep(kDrmCertificateExpiryPeriod); + sleep(kDrmCertificateExpirySleepPeriod); - // Make sure the certificate has expired and the device is not provisioned + // Make sure the certificate has expired and the device is not provisioned. EXPECT_FALSE(IsProvisioned(kExampleIdentifier, kLevelDefault)); - // Restore offline license + // Restore offline license. Key restoration should not be prevented + // by the expired DRM certificate. decryptor_->OpenSession(config_.key_system(), nullptr, kExampleIdentifier, nullptr, &session_id_); EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_->RestoreKey(session_id_, key_set_id)); diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index 8e567b32..b74ad900 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -194,7 +194,7 @@ class MockCDM : public WvContentDecryptionModule { std::string*), (override)); MOCK_METHOD(CdmResponseType, HandleProvisioningResponse, - (const CdmIdentifier&, CdmProvisioningResponse&, + (const CdmIdentifier&, const CdmProvisioningResponse&, wvcdm::RequestedSecurityLevel, std::string*, std::string*), (override)); MOCK_METHOD(CdmResponseType, Unprovision, (CdmSecurityLevel,