diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 8d57fb3e..bc70903b 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -319,6 +319,10 @@ typedef OEMCryptoResult (*L1_LoadProvisioning_t)( size_t signature_length, uint8_t* wrapped_private_key, size_t* wrapped_private_key_length); typedef uint32_t (*L1_MinorAPIVersion_t)(); +typedef OEMCryptoResult (*L1_OPK_SerializationVersion_t)(uint32_t* ree_major, + uint32_t* ree_minor, + uint32_t* tee_major, + uint32_t* tee_minor); typedef OEMCryptoResult (*L1_GenerateOTARequest_t)(OEMCrypto_SESSION session, uint8_t* buffer, size_t* buffer_length, @@ -411,6 +415,7 @@ struct FunctionPointers { L1_MaximumUsageTableHeaderSize_t MaximumUsageTableHeaderSize; L1_LoadProvisioning_t LoadProvisioning; L1_MinorAPIVersion_t MinorAPIVersion; + L1_OPK_SerializationVersion_t OPK_SerializationVersion; L1_LoadKeys_V8_t LoadKeys_V8; L1_GenerateRSASignature_V8_t GenerateRSASignature_V8; @@ -961,6 +966,7 @@ class Adapter { LOOKUP_ALL(16, MaximumUsageTableHeaderSize, OEMCrypto_MaximumUsageTableHeaderSize); LOOKUP_ALL(16, LoadProvisioning, OEMCrypto_LoadProvisioning); LOOKUP_ALL(16, MinorAPIVersion, OEMCrypto_MinorAPIVersion); + LOOKUP_ALL(16, OPK_SerializationVersion, OEMCrypto_OPK_SerializationVersion); LOOKUP_ALL(16, GenerateOTARequest, OEMCrypto_GenerateOTARequest); LOOKUP_ALL(16, ProcessOTAKeybox, OEMCrypto_ProcessOTAKeybox); // clang-format on @@ -2873,6 +2879,18 @@ extern "C" OEMCryptoResult OEMCrypto_FreeSecureBuffer( return pair.fcn->FreeSecureBuffer(pair.session, output_descriptor, secure_fd); } +extern "C" OEMCryptoResult OEMCrypto_OPK_SerializationVersion( + uint32_t* ree_major, uint32_t* ree_minor, uint32_t* tee_major, + uint32_t* tee_minor) { + if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault); + if (!fcn || fcn->OPK_SerializationVersion == nullptr) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + return fcn->OPK_SerializationVersion(ree_major, ree_minor, tee_major, + tee_minor); +} + extern "C" OEMCryptoResult OEMCrypto_GenerateOTARequest( OEMCrypto_SESSION session, uint8_t* buffer, size_t* buffer_length, uint32_t use_test_key) { diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_serialization_version_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_serialization_version_test.cpp new file mode 100644 index 00000000..31bfacb5 --- /dev/null +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_serialization_version_test.cpp @@ -0,0 +1,107 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +#include + +#include + +#include "OEMCryptoCENC.h" +#include "log.h" +#include "oec_test_data.h" + +using namespace std; + +namespace wvoec { + +class OEMCryptoTest : public ::testing::Test { + protected: + OEMCryptoTest() {} + + void SetUp() override { + ::testing::Test::SetUp(); + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + } + + void TearDown() override { + OEMCrypto_Terminate(); + ::testing::Test::TearDown(); + } +}; + +TEST_F(OEMCryptoTest, OPK_SerializationVersion) { + uint32_t ree_major = 0; + uint32_t ree_minor = 0; + uint32_t tee_major = 0; + uint32_t tee_minor = 0; + OEMCryptoResult sts = OEMCrypto_OPK_SerializationVersion( + &ree_major, &ree_minor, &tee_major, &tee_minor); + if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + cout << "OPK REE serialization version is " << ree_major << "." << ree_minor + << "\n"; + cout << "OPK TEE serialization version is " << tee_major << "." << tee_minor + << "\n"; + EXPECT_NE(ree_major, 0u); + EXPECT_NE(tee_major, 0u); + + const uint32_t orig_ree_major = ree_major; + const uint32_t orig_ree_minor = ree_minor; + const uint32_t orig_tee_major = tee_major; + const uint32_t orig_tee_minor = tee_minor; + + /* test requiring a specific version, should create incompatibility */ + ree_major = 100; + ree_minor = 1; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(OPK_ERROR_INCOMPATIBLE_VERSION, sts); + EXPECT_EQ(ree_major, 100u); + EXPECT_EQ(ree_minor, 1u); + + /* now OEMCrypto_Initialize should fail with incompatible version */ + OEMCrypto_Terminate(); + EXPECT_EQ(OPK_ERROR_INCOMPATIBLE_VERSION, OEMCrypto_Initialize()); + + /* restore the default versions */ + ree_major = 0; + ree_minor = 0; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + EXPECT_EQ(ree_major, orig_ree_major); + EXPECT_EQ(ree_minor, orig_ree_minor); + EXPECT_EQ(tee_major, orig_tee_major); + EXPECT_EQ(tee_minor, orig_tee_minor); + + /* OEMCrypto_Initialize should work now */ + OEMCrypto_Terminate(); + EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + + /* changing minor version shouldn't create incompatibility */ + ree_minor++; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(ree_minor, orig_ree_minor + 1); + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + + /* OEMCrypto_Initialize should still work */ + OEMCrypto_Terminate(); + EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + + /* remove the REE version override so subsequent tests work */ + ree_major = 0; + ree_minor = 0; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + } +} + +} // namespace wvoec