diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 08b7163c..382f54de 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -420,6 +420,7 @@ enum CdmResponseType : int32_t { CERT_PROVISIONING_RESPONSE_ERROR_9 = 365, CERT_PROVISIONING_RESPONSE_ERROR_10 = 366, CLIENT_TOKEN_NOT_SET = 367, + USAGE_ENTRY_ALREADY_LOADED = 368, // 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_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 783aa6e3..33443f45 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -283,6 +283,11 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id, CdmResponseType sts = usage_table_header_->LoadEntry( crypto_session_.get(), usage_entry_, usage_entry_number_); crypto_metrics_->usage_table_header_load_entry_.Increment(sts); + if (sts == LOAD_USAGE_ENTRY_INVALID_SESSION) { + LOGE("License loaded in different session: key_set_id = %s", + IdToString(key_set_id)); + return USAGE_ENTRY_ALREADY_LOADED; + } if (sts != NO_ERROR) { LOGE("Failed to load usage entry: status = %d", static_cast(sts)); return sts; diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index e9925da3..3871af80 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -96,7 +96,8 @@ const char kUsageInfoFileNameExt[] = ".bin"; const char kUsageInfoFileNamePrefix[] = "usage"; const char kUsageTableFileName[] = "usgtable.bin"; const char kWildcard[] = "*"; -constexpr int64_t kFourMonthsInSeconds = (2 * 30 + 2 * 31) * 24 * 60 * 60; +// TODO(b/192430982): Renable expiration of legacy DRM certificates +// constexpr int64_t kFourMonthsInSeconds = (2 * 30 + 2 * 31) * 24 * 60 * 60; // Helper methods bool SetDeviceCertificate(const std::string& certificate, @@ -427,7 +428,9 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate, if (default_certificate) { Clock clock; device_certificate->set_acquisition_time_seconds(clock.GetCurrentTime()); - } else { + } + /* TODO(b/192430982): Renable expiration of legacy DRM certificates + else { // Since certificates of type kCertificateAtsc are not allowed to be // stored, this is a certificate of type kCertificateLegacy. // The only time when a legacy certificate is stored is when it does not @@ -440,6 +443,7 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate, current_time + kFourMonthsInSeconds + rng.RandomInRange(kFourMonthsInSeconds)); } + */ std::string serialized_file; file.SerializeToString(&serialized_file); @@ -595,6 +599,7 @@ DeviceFiles::CertificateState DeviceFiles::RetrieveCertificate( } case kCertificateLegacy: { + /* TODO(b/192430982): Renable expiration of legacy DRM certificates // Validation check for DRM certificate without an expiration // time set by the provisioning service. Add an expiry time // within the next 6 months +/- 2 months, if one has not been set. @@ -611,6 +616,7 @@ DeviceFiles::CertificateState DeviceFiles::RetrieveCertificate( } if (current_time > expiration_time_seconds) return kCertificateExpired; + */ return kCertificateValid; } diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index 39e2865b..2aab53f0 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -1568,8 +1568,10 @@ const CertificateErrorData kRetrieveLegacyCertificateErrorData[] = { kTestLegacyCertificateFileDataInvalidClientExpiration}, }; +/* TODO(b/192430982): Renable expiration of legacy DRM certificates constexpr size_t kNumberOfLegacyCertificates = ArraySize(kRetrieveLegacyCertificateErrorData); +*/ const CertificateErrorData kRetrieveDefaultCertificateErrorData[] = { // Certificate expired @@ -4020,6 +4022,7 @@ TEST_F(DeviceFilesTest, RetrieveAtscCertificateNotFound) { &serial_number, &system_id)); } +/* TODO(b/192430982): Renable expiration of legacy DRM certificates TEST_F(DeviceFilesTest, RetrieveLegacyCertificateWithoutExpirationTime) { MockFileSystem file_system; std::string certificate_file_name; @@ -4221,6 +4224,7 @@ TEST_F(DeviceFilesTest, RetrieveDefaultCertificate) { EXPECT_EQ(kTestWrappedKey, private_key); EXPECT_EQ("7CB49F987A635E1E0A52184694582D6E", b2a_hex(serial_number)); } +*/ TEST_F(DeviceFilesTest, RetrieveDefaultCertificateNeverExpires) { MockFileSystem file_system; @@ -4331,7 +4335,9 @@ TEST_F(DeviceFilesTest, RetrieveCertificateWithoutKeyType) { // Call to Open will return a unique_ptr, freeing this object. // The file will be re-written with a new client expiration time MockFile* read_file = new MockFile(); + /* TODO(b/192430982): Renable expiration of legacy DRM certificates MockFile* write_file = new MockFile(); + */ EXPECT_CALL(file_system, Exists(StrEq(device_legacy_certificate_path))) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); @@ -4341,17 +4347,21 @@ TEST_F(DeviceFilesTest, RetrieveCertificateWithoutKeyType) { EXPECT_CALL(file_system, FileSize(StrEq(device_legacy_certificate_path))) .WillOnce(Return(data.size())); EXPECT_CALL(file_system, DoOpen(StrEq(device_legacy_certificate_path), _)) - .WillOnce(Return(read_file)) - .WillOnce(Return(write_file)); + .WillOnce(Return(read_file)); + /* TODO(b/192430982): Renable expiration of legacy DRM certificates + .WillOnce(Return(write_file)); + */ EXPECT_CALL(*read_file, Read(NotNull(), Eq(data.size()))) .WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()), Return(data.size()))); EXPECT_CALL(*read_file, Write(_, _)).Times(0); + /* TODO(b/192430982): Renable expiration of legacy DRM certificates EXPECT_CALL(*write_file, Read(_, _)).Times(0); EXPECT_CALL(*write_file, Write(_, _)) .With(AllArgs(StrAndLenContains(std::vector{ kTestCertificateWithoutExpiration, kTestWrappedKey.key()}))) .WillOnce(ReturnArg<1>()); + */ DeviceFiles device_files(&file_system); EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index cd78290c..5364eb2c 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -887,6 +887,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case USAGE_ENTRY_NUMBER_MISMATCH: *os << "USAGE_ENTRY_NUMBER_MISMATCH"; break; + case USAGE_ENTRY_ALREADY_LOADED: + *os << "USAGE_ENTRY_ALREADY_LOADED"; + break; case USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE: *os << "USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE"; break; diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index e1ab605f..334b6fc9 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -43,6 +45,8 @@ const uint32_t kClockTolerance = 10; const uint32_t kMaxUsageTableSize = 50; const std::string kEmptyServiceCertificate; +constexpr int64_t kUnlimitedDurationValue = LLONG_MAX; + // TODO(rfrias): refactor to print out the decryption test names struct SubSampleInfo { bool retrieve_key; @@ -1304,10 +1308,25 @@ TEST_P(WvCdmStreamingNoPstTest, UsageTest) { QueryKeyStatus(true, true, &license_duration_remaining, &playback_duration_remaining); - EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, - expected_seconds_since_license_received, kClockTolerance); - EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, - expected_seconds_since_initial_playback, kClockTolerance); + if (initial_license_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, + expected_seconds_since_license_received, kClockTolerance) + << "initial_license_duration_remaining = " + << initial_license_duration_remaining + << ", license_duration_remaining = " << license_duration_remaining; + } + + if (initial_playback_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, + expected_seconds_since_initial_playback, kClockTolerance) + << "initial_playback_duration_remaining = " + << initial_playback_duration_remaining + << ", playback_duration_remaining = " << playback_duration_remaining; + } decryptor_->CloseSession(session_id_); } @@ -1371,10 +1390,25 @@ TEST_P(WvCdmStreamingPstTest, UsageTest) { QueryKeyStatus(true, false, &license_duration_remaining, &playback_duration_remaining); - EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, - expected_seconds_since_license_received, kClockTolerance); - EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, - expected_seconds_since_initial_playback, kClockTolerance); + if (initial_license_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, + expected_seconds_since_license_received, kClockTolerance) + << "initial_license_duration_remaining = " + << initial_license_duration_remaining + << ", license_duration_remaining = " << license_duration_remaining; + } + + if (initial_playback_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, + expected_seconds_since_initial_playback, kClockTolerance) + << "initial_playback_duration_remaining = " + << initial_playback_duration_remaining + << ", playback_duration_remaining = " << playback_duration_remaining; + } decryptor_->CloseSession(session_id_); } @@ -1438,10 +1472,29 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) { QueryKeyStatus(true, false, &license_duration_remaining, &playback_duration_remaining); - EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, - expected_seconds_since_license_received, kClockTolerance); - EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, - expected_seconds_since_initial_playback, kClockTolerance); + // For unlimited "rental durations", the "license duration" will + // effectively be unlimited. Remaining license duration in this + // case is represented by |kUnlimitedDurationValue| and will not + // change over time. + if (initial_license_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, + expected_seconds_since_license_received, kClockTolerance) + << "initial_license_duration_remaining = " + << initial_license_duration_remaining + << ", license_duration_remaining = " << license_duration_remaining; + } + + if (initial_playback_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, + expected_seconds_since_initial_playback, kClockTolerance) + << "initial_playback_duration_remaining = " + << initial_playback_duration_remaining + << ", playback_duration_remaining = " << playback_duration_remaining; + } decryptor_->CloseSession(session_id_); @@ -1533,11 +1586,29 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) { QueryKeyStatus(false, true, &license_duration_remaining, &playback_duration_remaining); - EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, - expected_seconds_since_license_received, kClockTolerance); - EXPECT_NEAR( - initial_playback_duration_remaining - playback_duration_remaining, - expected_seconds_since_initial_playback, kClockTolerance); + if (initial_license_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue) + << "i = " << i; + } else { + EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, + expected_seconds_since_license_received, kClockTolerance) + << "initial_license_duration_remaining = " + << initial_license_duration_remaining + << ", license_duration_remaining = " << license_duration_remaining + << ", i = " << i; + } + + if (initial_playback_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue) + << "i = " << i; + } else { + EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, + expected_seconds_since_initial_playback, kClockTolerance) + << "initial_playback_duration_remaining = " + << initial_playback_duration_remaining + << ", playback_duration_remaining = " << playback_duration_remaining + << ", i = " << i; + } // Decrypt data SubSampleInfo* data = &kEncryptedOfflineClip2SubSample; @@ -1577,10 +1648,25 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) { QueryKeyStatus(false, true, &license_duration_remaining, &playback_duration_remaining); - EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, - expected_seconds_since_license_received, kClockTolerance); - EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, - expected_seconds_since_initial_playback, kClockTolerance); + if (initial_license_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, + expected_seconds_since_license_received, kClockTolerance) + << "initial_license_duration_remaining = " + << initial_license_duration_remaining + << ", license_duration_remaining = " << license_duration_remaining; + } + + if (initial_playback_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, + expected_seconds_since_initial_playback, kClockTolerance) + << "initial_playback_duration_remaining = " + << initial_playback_duration_remaining + << ", playback_duration_remaining = " << playback_duration_remaining; + } decryptor_->CloseSession(session_id_); diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index 2e81e97b..23cd2bfb 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -301,10 +301,11 @@ enum { kCertProvisioningResponseError9 = ERROR_DRM_VENDOR_MIN + 316, kCertProvisioningResponseError10 = ERROR_DRM_VENDOR_MIN + 317, kClientTokenNotSet = ERROR_DRM_VENDOR_MIN + 318, + kUsageEntryAlreadyLoaded = ERROR_DRM_VENDOR_MIN + 319, // 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 + 318, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 319, // 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 ab35381c..305644ec 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -539,6 +539,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kUpdateUsageEntryUnknownError; case wvcdm::USAGE_ENTRY_NUMBER_MISMATCH: return kUsageEntryNumberMismatch; + case wvcdm::USAGE_ENTRY_ALREADY_LOADED: + return kUsageEntryAlreadyLoaded; case wvcdm::USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE: return kUsageGetEntryRetrieveInvalidStorageType; case wvcdm::USAGE_GET_ENTRY_RETRIEVE_LICENSE_FAILED: diff --git a/libwvdrmengine/include_hidl/mapErrors-inl.h b/libwvdrmengine/include_hidl/mapErrors-inl.h index 60e83548..bceea4d9 100644 --- a/libwvdrmengine/include_hidl/mapErrors-inl.h +++ b/libwvdrmengine/include_hidl/mapErrors-inl.h @@ -361,6 +361,7 @@ static Status mapCdmResponseType_1_0(wvcdm::CdmResponseType res) { case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_9: case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_10: case wvcdm::CLIENT_TOKEN_NOT_SET: + case wvcdm::USAGE_ENTRY_ALREADY_LOADED: ALOGW("Returns UNKNOWN error for legacy status: %d", res); return Status::ERROR_DRM_UNKNOWN; @@ -617,6 +618,7 @@ static S mapCdmResponseType(wvcdm::CdmResponseType res) { break; case wvcdm::GET_RELEASED_LICENSE_ERROR: case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_3: + case wvcdm::USAGE_ENTRY_ALREADY_LOADED: err = ::drm::V1_4::Status::LICENSE_STATE_ERROR; break; case wvcdm::DEVICE_CERTIFICATE_ERROR_2: