diff --git a/CHANGELOG.md b/CHANGELOG.md index fc57ac1..9ae5b78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ [TOC] +## [Version 16.4.1][v16.4.1] + +Patch release which includes a fix for a bug in the OPK session state machine +logic. Previously the state machine code would only allow OEMCrypto_MoveEntry() +to be called when a usage entry had been loaded. This misses a few use cases +from the CDM where OEMCrypto_MoveEntry() could be called immediately after +opening a session or waiting for a license. + +This bug could result in situations where users are unable to download offline +licenses. If the usage table is completely filled (~300 entries by default in +OPK), then this bug may occur when the CDM tries to move old entries to make +room for new licenses. Similarly, if the usage table has gaps where previous +entries were deleted, then this bug may occur when the CDM tries to defragment +the usage table by moving newer usage entries into those gaps. + ## [Version 16.4 plus opk beta 2][v16.4+opk-beta2] Second beta release of the OEMCrypto Porting Kit (OPK), supporting OEMCrypto v16. @@ -65,7 +80,7 @@ for more details. Public release for OEMCrypto API and ODK library version 16.4. - +[v16.4.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v16.4.1 [v16.4]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v16.4 [v16.4+extra-test]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v16.4+extra-tests [v16.4+doc-updates]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v16.4+doc-updates diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h index 91e264c..f70d89a 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h @@ -12,6 +12,6 @@ #define STR(s) #s #define BUILD_INFO() \ "Widevine OEMCrypto TA v" XSTR(API_MAJOR_VERSION) "." XSTR( \ - API_MINOR_VERSION) ".0" + API_MINOR_VERSION) ".1" #endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c index a1181ee..5fe69dd 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c @@ -271,6 +271,9 @@ OEMCryptoResult OPKI_CheckStatePreCall(OEMCryptoSession* session, case API_MOVEENTRY: switch (session->state) { case (SESSION_USAGE_ENTRY_LOADED): + case (SESSION_OPENED): + case (SESSION_WAIT_FOR_LICENSE): + case (SESSION_LOAD_DRM_RSA_KEY): return OEMCrypto_SUCCESS; default: goto err; diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index 1e82258..0e4da11 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -8557,6 +8557,39 @@ TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntries) { FailReloadLicense(&entries[3], OEMCrypto_ERROR_UNKNOWN_FAILURE)); } +TEST_P(OEMCryptoUsageTableDefragTest, MakeAndMoveEntry) { + // 1. Make an entry then close. + LicenseWithUsageEntry entry; + ASSERT_NO_FATAL_FAILURE(entry.set_pst("pst 0")); + ASSERT_NO_FATAL_FAILURE(entry.MakeOfflineAndClose(this)); + ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(entry.session().close()); + + // 2. Make an entry then immediately move it into the previous slot. + // Not using helper functions because they shoehorn the session state into + // a limited set of possibilities. We want to create the specific case of + // immediately moving a newly created entry. + + // Like LicenseWithUsageEntry::MakeAndLoad() but stop after creating the new + // usage entry. + Session session; + ASSERT_NO_FATAL_FAILURE(session.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session)); + LicenseRoundTrip license_messages_(&session); + license_messages_.set_control(wvoec::kControlNonceOrEntry); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + OEMCryptoResult result; + ASSERT_NO_FATAL_FAILURE(session.CreateNewUsageEntry(&result)); + + // Not the same as Session::MoveUsageEntry, which opens and closes a session + // around the move operation. We just want to call MoveEntry on the current + // state. + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_MoveEntry(session.session_id(), 0)); + ASSERT_NO_FATAL_FAILURE(session.close()); +} + // A usage table entry cannot be moved into an entry where an open session is // currently using the entry. TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntriesToOpenSession) {