From 8381c79c3e8accdf0e1b457a173eb79d652bfe8a Mon Sep 17 00:00:00 2001 From: Matt Feddersen Date: Wed, 8 Nov 2023 16:07:53 -0800 Subject: [PATCH] OPK v17.2.1 release This is a patch release that fixes a bug in the OPK where calling OEMCrypto_MoveEntry() immediately after calling OEMCrypto_CreateNewUsageEntry() returns an error when it should return success. --- CHANGELOG.md | 16 +++++++++ .../opk/oemcrypto_ta/oemcrypto_api_macros.h | 2 +- .../opk/oemcrypto_ta/oemcrypto_session.c | 3 ++ .../oemcrypto_corpus_generator_helper.cpp | 6 +++- .../test/oemcrypto_corpus_generator_helper.h | 6 +++- oemcrypto/test/oemcrypto_test.cpp | 33 +++++++++++++++++++ 6 files changed, 63 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e14e991..6aeda43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ [TOC] +## [Version 17.2.1][v17.2.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 17.2][v17.2] This release contains the first version of OPK to support MediaCAS, an @@ -220,3 +235,4 @@ Public release for OEMCrypto API and ODK library version 16.4. [v17.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.1 [v17.1+opk-v17.1.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.1+opk-v17.1.1 [v17.2]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.2 +[v17.2.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.2.1 diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h index 46a38b7..f1ce48d 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h @@ -32,6 +32,6 @@ // v17.1.0 #define API_MAJOR_VERSION 17 #define API_MINOR_VERSION 2 -#define OPK_PATCH_VERSION 0 +#define OPK_PATCH_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 59f981b..4813be9 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c @@ -303,6 +303,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_corpus_generator_helper.cpp b/oemcrypto/test/oemcrypto_corpus_generator_helper.cpp index 31b9bb5..6b603dc 100644 --- a/oemcrypto/test/oemcrypto_corpus_generator_helper.cpp +++ b/oemcrypto/test/oemcrypto_corpus_generator_helper.cpp @@ -1,12 +1,14 @@ /* Copyright 2020 Google LLC. All rights reserved. This file and proprietary */ /* source code may only be used and distributed under the Widevine */ /* License Agreement. */ + #include "oemcrypto_corpus_generator_helper.h" #include #include namespace wvoec { + bool g_generate_corpus; void AppendToFile(const std::string& file_name, const char* message, @@ -32,7 +34,7 @@ void AppendSeparator(const std::string& file_name) { std::string GetFileName(const char* directory) { std::string file_name(PATH_TO_CORPUS); file_name += directory; - file_name += "/"; + file_name += '/'; file_name += std::to_string(rand()); return file_name; } @@ -40,5 +42,7 @@ std::string GetFileName(const char* directory) { void SetGenerateCorpus(bool should_generate_corpus) { g_generate_corpus = should_generate_corpus; } + bool ShouldGenerateCorpus() { return g_generate_corpus; } + } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_corpus_generator_helper.h b/oemcrypto/test/oemcrypto_corpus_generator_helper.h index 7b7b399..ff30d4c 100644 --- a/oemcrypto/test/oemcrypto_corpus_generator_helper.h +++ b/oemcrypto/test/oemcrypto_corpus_generator_helper.h @@ -1,16 +1,18 @@ /* Copyright 2020 Google LLC. All rights reserved. This file and proprietary */ /* source code may only be used and distributed under the Widevine */ /* License Agreement. */ + #ifndef CDM_OEMCRYPTO_CORPUS_GENERATOR_HELPER_H_ #define CDM_OEMCRYPTO_CORPUS_GENERATOR_HELPER_H_ #define PATH_TO_CORPUS "./oemcrypto/test/fuzz_tests/corpus/" -#include +#include #include #include namespace wvoec { + const uint8_t kFuzzDataSeparator[] = {'-', '_', '^', '_'}; void AppendToFile(const std::string& file_name, const char* message, @@ -22,9 +24,11 @@ void AppendSeparator(const std::string& file_name); std::string GetFileName(const char* directory); void SetGenerateCorpus(bool should_generate_corpus); + // Output of this function decides if binary data needs to be written // to corpus files or not. Controlled by --generate_corpus flag. bool ShouldGenerateCorpus(); + } // namespace wvoec #endif // CDM_OEMCRYPTO_CORPUS_GENERATOR_HELPER_H_ diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index f821559..e1f86bb 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -9592,6 +9592,39 @@ TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntries) { ASSERT_NO_FATAL_FAILURE( 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.