diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index 9194f5be..f85cbfe6 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -864,13 +864,13 @@ CdmResponseType CdmLicense::RestoreOfflineLicense( break; case CryptoSession::kUsageDurationsValid: { int64_t current_time = clock_->GetCurrentTime(); - if (current_time - seconds_since_started > 0) - playback_start_time = current_time - seconds_since_started; - if (current_time - last_playback_time > 0) - last_playback_time = current_time - seconds_since_last_played; + playback_start_time = current_time - seconds_since_started; + last_playback_time = current_time - seconds_since_last_played; break; } default: + // Use playback_start_time and last_playback_time from + // persistently stored license data break; } } diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index c60349b4..77aa0c25 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -6598,6 +6598,69 @@ TEST_F(WvCdmRequestLicenseRollbackTest, Offline_RollbackBeforeRestoreKey) { ASSERT_EQ(NO_ERROR, decryptor_->CloseSession(session_id_)); } +// The difference between this test and Offline_RollbackBeforeRestoreKey is +// that this test has a 15 second expiration window. +// Offline_RollbackBeforeRestoreKey has a 5 second window. The rollback +// before restore causes the expiration timer to run from the rollback time. +// The license in Offline_RollbackBeforeRestoreKey is expired by the time +// the rollback is undone, while this one has not yet expired. +TEST_F(WvCdmRequestLicenseRollbackTest, + Offline_LongerDurationRollbackBeforeRestoreKey) { + Unprovision(); + Provision(); + + // The default offline asset is "offline_clip2". Substitute '2' for '8'. + // "offline_clip8" has a 15 second expiration. + std::string key_id; + std::string client_auth; + GetOfflineConfiguration(&key_id, &client_auth); + key_id[key_id.size() - 1] = '8'; + + ASSERT_EQ(NO_ERROR, decryptor_->OpenSession(config_.key_system(), nullptr, + kDefaultCdmIdentifier, nullptr, + &session_id_)); + GenerateKeyRequest(key_id, kLicenseTypeOffline); + VerifyKeyRequestResponse(config_.license_server(), client_auth); + + // Verify that we can decrypt a subsample to begin with. + EXPECT_EQ(NO_ERROR, Decrypt(session_id_)); + + CdmKeySetId key_set_id = key_set_id_; + EXPECT_FALSE(key_set_id_.empty()); + decryptor_->CloseSession(session_id_); + + // This number must be > the time between GenerateKeyRequest and this call. + RollbackSystemTime(10 * 1000); + + session_id_.clear(); + decryptor_->OpenSession(config_.key_system(), nullptr, kDefaultCdmIdentifier, + nullptr, &session_id_); + + decryptor_->RestoreKey(session_id_, key_set_id); + + // Verify we can't decrypt. The license start time is in the future. + EXPECT_EQ(DECRYPT_NOT_READY, Decrypt(session_id_)); + + RestoreSystemTime(); + + // Sleep for a little bit to account for the execution time of OpenSession and + // RestoreKey. + std::this_thread::sleep_for(std::chrono::milliseconds(kExpirationWindowMs_)); + + // Verify we can decrypt. + EXPECT_EQ(NO_ERROR, Decrypt(session_id_)); + + // Sleep for a while more. + std::this_thread::sleep_for(std::chrono::milliseconds(kExpirationTimeMs_)); + + // Rollback time + kExpirationWindowMs_ + kExpirationTimeMs_ (~17s) will have + // elapsed. This is greater than the expiration window for longer duration + // licenses (15s). The license should have expired. + EXPECT_EQ(NEED_KEY, Decrypt(session_id_)); + + ASSERT_EQ(NO_ERROR, decryptor_->CloseSession(session_id_)); +} + TEST_F(WvCdmRequestLicenseRollbackTest, Offline_RollbackAndExpireAfterRestoreKey) { Unprovision(); @@ -6636,6 +6699,8 @@ TEST_F(WvCdmRequestLicenseRollbackTest, RestoreSystemTime(); + EXPECT_EQ(NEED_KEY, Decrypt(session_id_)); + ASSERT_EQ(NO_ERROR, decryptor_->CloseSession(session_id_)); } @@ -6670,9 +6735,11 @@ TEST_F(WvCdmRequestLicenseRollbackTest, std::this_thread::sleep_for( std::chrono::milliseconds(kExpirationWithWindowMs_)); + // Verify that we can no longer decrypt a subsample due to key expiration. + EXPECT_EQ(NEED_KEY, Decrypt(session_id_)); + RollbackSystemTime(kExpirationWithWindowMs_); - // Verify that we can no longer decrypt a subsample due to key expiration. EXPECT_EQ(NEED_KEY, Decrypt(session_id_)); RestoreSystemTime();