From e9e4b76817a4847ebe1317596aa498642c1e100a Mon Sep 17 00:00:00 2001 From: Geoffrey Alexander Date: Wed, 24 Jan 2024 17:29:34 +0000 Subject: [PATCH 1/9] Rename and clarify Drm Reprovisioning token types [ Merge of http://go/wvgerrit/194374 ] Renames and adds clarifying comments to Drm Reprovisioning token types. All provisioning methods can be forced to reprovision by apps which can cause reprovisioning to be an overloaded term. Renaming token types used by the Drm Reprovisioning method to more clearly state they are used for Drm Certificate Reprovisioning should help to avoid confusion. This change also adds comments to help clarify when and where Drm Reprovisioning is used as a provisioning type. Bug: b/305093063 Test: WVTS * Added dependency to dynamic perf tests to fix missing header build error. Change-Id: I158eb5672ad9e655a60bc68e0f4f2f7a0d464b4e --- libwvdrmengine/cdm/core/include/wv_cdm_types.h | 4 +++- libwvdrmengine/cdm/core/src/cdm_engine.cpp | 2 +- .../cdm/core/src/certificate_provisioning.cpp | 2 +- libwvdrmengine/cdm/core/src/client_identification.cpp | 2 +- libwvdrmengine/cdm/core/src/crypto_session.cpp | 10 ++++++---- libwvdrmengine/cdm/core/src/license_protocol.proto | 8 +++++--- libwvdrmengine/cdm/core/src/system_id_extractor.cpp | 2 +- libwvdrmengine/cdm/core/src/wv_cdm_types.cpp | 4 ++-- .../core/test/certificate_provisioning_unittest.cpp | 2 +- .../cdm/core/test/crypto_session_unittest.cpp | 4 ++-- 10 files changed, 23 insertions(+), 17 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index e14a02ea..5a5a12db 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -607,7 +607,9 @@ enum CdmClientTokenType : int32_t { kClientTokenOemCert, kClientTokenUninitialized, kClientTokenBootCertChain, - kClientTokenDrmReprovisioning, + // For use by internal L3 CDMs supporting individualization of embedded + // drm certificates. + kClientTokenDrmCertificateReprovisioning, }; // kNonSecureUsageSupport - TEE does not provide any support for usage diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index d2622086..b60f58c1 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -754,7 +754,7 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level, } switch (token_type) { case kClientTokenDrmCert: - case kClientTokenDrmReprovisioning: + case kClientTokenDrmCertificateReprovisioning: *query_response = QUERY_VALUE_DRM_CERTIFICATE; break; case kClientTokenKeybox: diff --git a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp index 38973baf..b40c3825 100644 --- a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp +++ b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp @@ -169,7 +169,7 @@ CertificateProvisioning::GetProvisioningType() { return SignedProvisioningMessage::PROVISIONING_40; case kClientTokenOemCert: return SignedProvisioningMessage::PROVISIONING_30; - case kClientTokenDrmReprovisioning: + case kClientTokenDrmCertificateReprovisioning: return SignedProvisioningMessage::DRM_REPROVISIONING; default: return SignedProvisioningMessage::PROVISIONING_20; diff --git a/libwvdrmengine/cdm/core/src/client_identification.cpp b/libwvdrmengine/cdm/core/src/client_identification.cpp index 86aa9fff..94bb8720 100644 --- a/libwvdrmengine/cdm/core/src/client_identification.cpp +++ b/libwvdrmengine/cdm/core/src/client_identification.cpp @@ -404,7 +404,7 @@ bool ClientIdentification::GetProvisioningTokenType( } return true; } - case kClientTokenDrmReprovisioning: + case kClientTokenDrmCertificateReprovisioning: *token_type = video_widevine::ClientIdentification::DRM_DEVICE_CERTIFICATE; return true; diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index ee60c5e1..939af6dd 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -348,7 +348,7 @@ CdmResponseType CryptoSession::GetProvisioningMethod( type = kClientTokenBootCertChain; break; case OEMCrypto_DrmReprovisioning: - type = kClientTokenDrmReprovisioning; + type = kClientTokenDrmCertificateReprovisioning; break; case OEMCrypto_ProvisioningError: default: @@ -666,7 +666,8 @@ CdmResponseType CryptoSession::GetProvisioningToken( } else if (pre_provision_token_type_ == kClientTokenBootCertChain) { status = GetBootCertificateChain(requested_security_level, token, additional_token); - } else if (pre_provision_token_type_ == kClientTokenDrmReprovisioning) { + } else if (pre_provision_token_type_ == + kClientTokenDrmCertificateReprovisioning) { status = GetTokenFromEmbeddedCertificate(token); } metrics_->crypto_session_get_token_.Increment(status); @@ -1275,7 +1276,8 @@ CdmResponseType CryptoSession::PrepareAndSignProvisioningRequest( should_specify_algorithm = true; // Do nothing here. The key to signing the provisioning 4.0 request for each // stage has been loaded already when it was generated by OEMCrypto. - } else if (pre_provision_token_type_ == kClientTokenDrmReprovisioning) { + } else if (pre_provision_token_type_ == + kClientTokenDrmCertificateReprovisioning) { should_specify_algorithm = false; // Do nothing here. The baked-in certificate used as the token has already // been loaded when the EncryptedClientId was filled in. @@ -1462,7 +1464,7 @@ CdmResponseType CryptoSession::GetTokenFromEmbeddedCertificate( LOGE("Failed to get token type"); return sts; } - if (token_type != kClientTokenDrmReprovisioning) { + if (token_type != kClientTokenDrmCertificateReprovisioning) { token->clear(); return CdmResponseType(NO_ERROR); } diff --git a/libwvdrmengine/cdm/core/src/license_protocol.proto b/libwvdrmengine/cdm/core/src/license_protocol.proto index 70c778c3..7e814b54 100644 --- a/libwvdrmengine/cdm/core/src/license_protocol.proto +++ b/libwvdrmengine/cdm/core/src/license_protocol.proto @@ -1026,7 +1026,8 @@ message SignedProvisioningMessage { ARCPP_PROVISIONING = 4; // ChromeOS/Arc++ devices. // Android-Attestation-based OTA keyboxes. ANDROID_ATTESTATION_KEYBOX_OTA = 6; - // Certificate reprovisioning for internal L3 CDMs only. + // DRM certificate reprovisioning for individualization of embedded + // DRM certificates used by internal L3 CDMs only. DRM_REPROVISIONING = 7; INTEL_SIGMA_101 = 101; // Intel Sigma 1.0.1 protocol. INTEL_SIGMA_210 = 210; // Intel Sigma 2.1.0 protocol. @@ -1275,8 +1276,9 @@ message DrmCertificate { DEVICE = 2; SERVICE = 3; PROVISIONER = 4; - // Only used by baked-in certificates with internal L3 CDMs that support - // Drm Reprovisioning. + // Only used by internal L3 CDMs with baked-in (embedded) certificates that + // support the Drm Reprovisioning method for individualization of embedded + // certificates. DEVICE_EMBEDDED = 5; } enum ServiceType { diff --git a/libwvdrmengine/cdm/core/src/system_id_extractor.cpp b/libwvdrmengine/cdm/core/src/system_id_extractor.cpp index 791ace5f..72b548fd 100644 --- a/libwvdrmengine/cdm/core/src/system_id_extractor.cpp +++ b/libwvdrmengine/cdm/core/src/system_id_extractor.cpp @@ -60,7 +60,7 @@ bool SystemIdExtractor::ExtractSystemId(uint32_t* system_id) { switch (type) { case kClientTokenDrmCert: // TODO: b/309675153 - Extract system id when using DRM reprovisioning. - case kClientTokenDrmReprovisioning: + case kClientTokenDrmCertificateReprovisioning: LOGW( "Cannot get a system ID from a DRM certificate, " "using null system ID: security_level = %s", diff --git a/libwvdrmengine/cdm/core/src/wv_cdm_types.cpp b/libwvdrmengine/cdm/core/src/wv_cdm_types.cpp index ce21bd81..edc2edf2 100644 --- a/libwvdrmengine/cdm/core/src/wv_cdm_types.cpp +++ b/libwvdrmengine/cdm/core/src/wv_cdm_types.cpp @@ -76,8 +76,8 @@ const char* CdmClientTokenTypeToString(CdmClientTokenType type) { return "BootCertChain"; case kClientTokenUninitialized: return "Uninitialized"; - case kClientTokenDrmReprovisioning: - return "DrmReprovisioning"; + case kClientTokenDrmCertificateReprovisioning: + return "DrmCertificateReprovisioning"; } return UnknownValueRep(type); } diff --git a/libwvdrmengine/cdm/core/test/certificate_provisioning_unittest.cpp b/libwvdrmengine/cdm/core/test/certificate_provisioning_unittest.cpp index cf5ccbd9..01328861 100644 --- a/libwvdrmengine/cdm/core/test/certificate_provisioning_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/certificate_provisioning_unittest.cpp @@ -482,7 +482,7 @@ TEST_P(CertificateProvisioningTest, ProvisioningResponseSuccess) { INSTANTIATE_TEST_SUITE_P( CertificateProvisioningTests, CertificateProvisioningTest, testing::Values(kClientTokenKeybox, kClientTokenOemCert, - kClientTokenDrmReprovisioning), + kClientTokenDrmCertificateReprovisioning), [](const testing::TestParamInfo& param_type) { return CdmClientTokenTypeToString(param_type.param); diff --git a/libwvdrmengine/cdm/core/test/crypto_session_unittest.cpp b/libwvdrmengine/cdm/core/test/crypto_session_unittest.cpp index 138cbff2..a668481d 100644 --- a/libwvdrmengine/cdm/core/test/crypto_session_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/crypto_session_unittest.cpp @@ -99,7 +99,7 @@ TEST_F(CryptoSessionMetricsTest, OpenSessionValidMetrics) { } else if (token_type == kClientTokenBootCertChain) { EXPECT_EQ(OEMCrypto_BootCertificateChain, metrics_proto.oemcrypto_provisioning_method().int_value()); - } else if (token_type == kClientTokenDrmReprovisioning) { + } else if (token_type == kClientTokenDrmCertificateReprovisioning) { EXPECT_EQ(OEMCrypto_DrmReprovisioning, metrics_proto.oemcrypto_provisioning_method().int_value()); } else { @@ -143,7 +143,7 @@ TEST_F(CryptoSessionMetricsTest, GetProvisioningTokenValidMetrics) { } else if (token_type == kClientTokenBootCertChain) { EXPECT_EQ(OEMCrypto_BootCertificateChain, metrics_proto.oemcrypto_provisioning_method().int_value()); - } else if (token_type == kClientTokenDrmReprovisioning) { + } else if (token_type == kClientTokenDrmCertificateReprovisioning) { EXPECT_EQ(OEMCrypto_DrmReprovisioning, metrics_proto.oemcrypto_provisioning_method().int_value()); } else { From d3b869c0aba8554c135b81ea6d43337d7e1cda42 Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Wed, 13 Mar 2024 17:21:30 -0700 Subject: [PATCH 2/9] Remove WvCdmEnginePreProvTestStaging [ Merge of http://go/wvgerrit/194370 ] This test explicitly provisions against the staging server, which we do not require from partners. Bug: 329293570 Test: WV unit/integration tests Change-Id: Id88840f188ec99b386837d83f69844b0990594a9 --- libwvdrmengine/cdm/core/test/cdm_engine_test.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp index 274015ec..074cf343 100644 --- a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp @@ -119,13 +119,6 @@ class WvCdmEnginePreProvTest : public WvCdmTestBaseWithEngine { std::string session_id_; }; -class WvCdmEnginePreProvTestStaging : public WvCdmEnginePreProvTest { - public: - WvCdmEnginePreProvTestStaging() { - config_ = ConfigTestEnv(kContentProtectionStagingServer); - } -}; - class WvCdmEnginePreProvTestProd : public WvCdmEnginePreProvTest { public: WvCdmEnginePreProvTestProd() { @@ -342,8 +335,6 @@ TEST_F(WvCdmEngineTest, SetLicensingServiceInvalidCertificate) { NO_ERROR); }; -TEST_F(WvCdmEnginePreProvTestStaging, ProvisioningTest) { EnsureProvisioned(); } - TEST_F(WvCdmEnginePreProvTestUatBinary, ProvisioningTest) { EnsureProvisioned(); } From 428586b0eb93691dc79af91ee4de8e991e6e211f Mon Sep 17 00:00:00 2001 From: Jacob Trimble Date: Tue, 5 Dec 2023 22:36:20 +0000 Subject: [PATCH 3/9] Change test storage to use protobuf [ Merge of http://go/wvgerrit/193190 ] This changes the persistent test storage to use protobufs instead of manual parsing. This simplifies the code but makes the files less "human readable". Files can be read using 'gqui' if needed. Bug: 312529037 Test: unit/integration tests Change-Id: I1b025eac96458c0061e0883e1e4fd05484842ff2 --- .../cdm/core/src/device_files.proto | 4 + libwvdrmengine/cdm/core/test/reboot_test.cpp | 223 +----------------- libwvdrmengine/cdm/core/test/reboot_test.h | 11 - 3 files changed, 17 insertions(+), 221 deletions(-) diff --git a/libwvdrmengine/cdm/core/src/device_files.proto b/libwvdrmengine/cdm/core/src/device_files.proto index 7b4a02ef..caf93563 100644 --- a/libwvdrmengine/cdm/core/src/device_files.proto +++ b/libwvdrmengine/cdm/core/src/device_files.proto @@ -20,6 +20,10 @@ message NameValue { optional string value = 2; } +message SavedStorage { + map files = 1; +} + message OemCertificate { enum PrivateKeyType { RSA = 0; diff --git a/libwvdrmengine/cdm/core/test/reboot_test.cpp b/libwvdrmengine/cdm/core/test/reboot_test.cpp index 3e5ce5fe..1e4f61f2 100644 --- a/libwvdrmengine/cdm/core/test/reboot_test.cpp +++ b/libwvdrmengine/cdm/core/test/reboot_test.cpp @@ -11,14 +11,14 @@ #include #include "create_test_file_system.h" +#include "device_files.pb.h" #include "license_holder.h" #include "log.h" #include "test_sleep.h" -using wvutil::a2b_hex; +using video_widevine_client::sdk::SavedStorage; using wvutil::FileSystem; using wvutil::TestSleep; -using wvutil::unlimited_b2a_hex; namespace wvcdm { FileSystem* RebootTest::file_system_; @@ -27,179 +27,8 @@ namespace { // How much fudge or round off error do we allow in license durations for reboot // tests. constexpr int64_t kFudge = 10; - -// We will encode a value string by wrapping it in braces, or as hex. -// If the string is not printable, or if it has unmatched braces, then we use -// hex. Otherwise, we surround the whole string with braces. -std::string EncodeString(const std::string& data) { - int braces_count = 0; - for (size_t i = 0; i < data.length(); i++) { - if (data[i] == '{') braces_count++; - if (data[i] == '}') braces_count--; - // If printable or whitespace (because '\n' is not printable?!?). - bool printable = isprint(data[i]) || isspace(data[i]); - // If there are any unprintable characters, except whitespace, or if we - // close a brace before we open it, then just use hex. - if (!printable || braces_count < 0) { - return "0x" + unlimited_b2a_hex(data) + ","; - } - } - // If we left any braces open, then use hex. - if (braces_count != 0) return "0x" + unlimited_b2a_hex(data) + ","; - return "{" + data + "},"; -} - -// Encode a map key for dumping. When we encode a map, we expect the keys to be -// like filenames, so we can separate them with colons and whitespace. If the -// key has these special characters, we will encode as hex. -std::string EncodeKey(const std::string& data) { - if (data.length() == 0) { - LOGE("Encoding empty string as key!"); - return "EMPTY:"; - } - // When decoding, we assume that a key starting with "0x" is in hex. So we - // can't have any keys that start with "0x". - if (data.substr(0, 2) == "0x") return "0x" + unlimited_b2a_hex(data) + ":"; - // If the key is just is not printable, or if it has unmatched braces, then - // we use hex. Otherwise, we surround the whole string with braces. - for (size_t i = 0; i < data.length(); i++) { - if (!isprint(data[i]) || (data[i] == ':')) { - return "0x" + unlimited_b2a_hex(data) + ":"; - } - } - return data + ":"; -} - -// In between keys and values, we will ignore whitespace. This allows a human to -// edit the persistent data a little bit without breaking anything. -void SkipSpace(const std::string& encoded, size_t* index) { - if (!index) return; - while (*index < encoded.length() && isspace(encoded[*index])) (*index)++; -} - -// Decode a string that was encoded using EncodeString. -std::string DecodeString(const std::string& encoded, size_t* index) { - if (!index) return ""; - SkipSpace(encoded, index); - if (*index + 2 >= - encoded.length()) { // Encoded string has at least 3 characters. - LOGE("Error decoding short string from %s at %zd", encoded.c_str(), *index); - *index = encoded.length(); - return ""; - } - if (encoded[*index] == '{') { - (*index)++; - size_t start = *index; - int braces_count = 1; - while (*index < encoded.length()) { - if (encoded[*index] == '{') braces_count++; - if (encoded[*index] == '}') braces_count--; - if (braces_count == 0) { - size_t end = *index; - (*index) += 2; // absorb the comma and the '}', too. - return encoded.substr(start, end - start); - } - (*index)++; - } - std::string tail = encoded.substr(start); - LOGE("Non-terminated brace %s at %zd: %s", encoded.c_str(), start, - tail.c_str()); - *index = encoded.length(); - return ""; - } - if (encoded[*index] != '0' || encoded[*index + 1] != 'x') { - std::string tail = encoded.substr(*index); - LOGE("Hex should start with 0x in %s at %zd: %s", encoded.c_str(), *index, - tail.c_str()); - *index = encoded.length(); - return ""; - } - *index += 2; - size_t start = *index; - while (*index < encoded.length()) { - if (encoded[*index] == ',') { - size_t end = *index; - std::vector result = a2b_hex(encoded.substr(start, end - start)); - (*index)++; // absorb the comma. - return std::string(result.begin(), result.end()); - } - (*index)++; - } - std::string tail = encoded.substr(start); - LOGE("Bad encoding in %s at %zd: %s", encoded.c_str(), start, tail.c_str()); - *index = encoded.length(); - return ""; -} - -// Decode a string that was encoded with EncodeKey. -std::string DecodeKey(const std::string& encoded, size_t* index) { - if (!index) return ""; - SkipSpace(encoded, index); - if (*index + 1 >= encoded.length()) { - LOGE("Error decoding key from %s at %zd", encoded.c_str(), *index); - *index = encoded.length(); - return ""; - } - // If it starts with 0x, then it is in hex. - if (encoded[*index] == '0' && encoded[*index + 1] == 'x') { - size_t start = *index + 2; - while (*index < encoded.length() && encoded[*index] != ':') (*index)++; - size_t end = *index; - std::vector result = a2b_hex(encoded.substr(start, end - start)); - (*index)++; // skip the colon. - return std::string(result.begin(), result.end()); - } - size_t start = *index; - while (*index < encoded.length() && encoded[*index] != ':') (*index)++; - size_t end = *index; - (*index)++; // skip the colon. - return encoded.substr(start, end - start); -} } // namespace -std::string RebootTest::DumpData( - const std::map& data) { - std::ostringstream output; - output << "{\n"; - for (const auto& entry : data) { - output << " " << EncodeKey(entry.first) << " " - << EncodeString(entry.second) + "\n"; - } - output << "}\n"; - return output.str(); -} - -bool RebootTest::ParseDump(const std::string& dump, - std::map* data) { - size_t index = 0; - SkipSpace(dump, &index); - if (index >= dump.length()) return false; - if (dump[index] != '{') { - LOGE("Dump does not start with '{'"); - return false; - } - index++; // absorb '{' - while (true) { - SkipSpace(dump, &index); - if (index >= dump.length()) return false; - if (dump[index] == '}') { - index++; // absorb '}' - SkipSpace(dump, &index); - if (index != dump.length()) { - std::string tail = dump.substr(index); - LOGE("Trailing data in dump. %s at %zd: %s", dump.c_str(), index, - tail.c_str()); - return false; - } - return true; - } - std::string tail = dump.substr(index); - std::string key = DecodeKey(dump, &index); - std::string value = DecodeString(dump, &index); - (*data)[key] = value; - } -} - void RebootTest::SetUp() { WvCdmTestBase::SetUp(); if (!file_system_) file_system_ = CreateTestFileSystem(); @@ -221,7 +50,10 @@ void RebootTest::SetUp() { std::string dump(file_size, ' '); ssize_t read = file->Read(&dump[0], dump.size()); EXPECT_EQ(read, file_size) << "Error reading persistent data file."; - EXPECT_TRUE(ParseDump(dump, &persistent_data_)); + + SavedStorage proto; + EXPECT_TRUE(proto.ParseFromString(dump)); + persistent_data_.insert(proto.files().begin(), proto.files().end()); } TestSleep::SyncFakeClock(); } @@ -231,7 +63,13 @@ void RebootTest::TearDown() { auto file = file_system_->Open(persistent_data_filename_, FileSystem::kCreate | FileSystem::kTruncate); ASSERT_TRUE(file) << "Failed to open file: " << persistent_data_filename_; - std::string dump = DumpData(persistent_data_); + + SavedStorage proto; + proto.mutable_files()->insert(persistent_data_.begin(), + persistent_data_.end()); + std::string dump; + ASSERT_TRUE(proto.SerializeToString(&dump)); + const ssize_t bytes_written = file->Write(dump.data(), dump.length()); EXPECT_EQ(bytes_written, static_cast(dump.length())); WvCdmTestBase::TearDown(); @@ -254,41 +92,6 @@ void RebootTest::SaveTime(const std::string& key, int64_t time) { persistent_data_[key] = std::to_string(time); } -/** Test the dump and restore functions above. This does not test CDM - functionality. */ -TEST_F(RebootTest, TestDumpUtil) { - // Check that an empty map can be saved. - std::map map1; - const std::string dump = DumpData(map1); - std::map map2; - EXPECT_TRUE(ParseDump(dump, &map2)); - EXPECT_EQ(map1, map2); - // Now fill it with some data and try again. - map1["key1"] = "this is a string. "; - map1["key2"] = "mismatch } {"; - map1["key3"] = "mismatch } "; - map1["key4"] = "mismatch {"; - map1["key5"] = "this: { has { matched } } braces { /.,)(**&^$&^% }"; - map1["key6"] = ""; - map1["00 whitespace in key 00"] = "value is ok"; - // This key looks like it might be hex. It should show up as hex in the - // save file. - map1["0x_bad_key_00"] = "value is ok"; - std::string big_string = "start with something {binary"; - // Double big_string 8 times, i.e. times 256, so it's bigger than 2k: - for (int i = 0; i < 8; i++) big_string = big_string + big_string; - map1["big_file"] = big_string; - const std::string dump2 = DumpData(map1); - std::map map3; - EXPECT_TRUE(ParseDump(dump2, &map3)); - EXPECT_EQ(map1, map3); - if (test_pass() == 0) { - persistent_data_ = map1; - } else { - EXPECT_EQ(persistent_data_, map1); - } -} - /** Verify that the file system stores files from one test pass to the next. */ TEST_F(RebootTest, FilesArePersistent) { const std::string key = "saved_value"; diff --git a/libwvdrmengine/cdm/core/test/reboot_test.h b/libwvdrmengine/cdm/core/test/reboot_test.h index fae4993e..5d9b097e 100644 --- a/libwvdrmengine/cdm/core/test/reboot_test.h +++ b/libwvdrmengine/cdm/core/test/reboot_test.h @@ -22,17 +22,6 @@ class RebootTest : public WvCdmTestBaseWithEngine { static void set_file_system(wvutil::FileSystem* file_system) { file_system_ = file_system; } - // Dump a map to a std string in an almost human readable way so that the map - // can be rebuilt using ParseDump below. The keys in the map must be standard - // identifier strings, which means no special characters or whitespace. By - // "almost human readable", we mean that a human debugging the dump will be - // able to find the keys, and see the values if they are printable or see a - // hex dump of the values if they are not. - static std::string DumpData(const std::map& data); - // Parse a dump generated by DumpData and recreate the original data map. - // Returns true on success. - static bool ParseDump(const std::string& dump, - std::map* data); static int test_pass() { return default_config_->test_pass(); } From 38243aca4c9e2e385440a49bd0d09ae50cde73f1 Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Wed, 13 Mar 2024 17:23:33 -0700 Subject: [PATCH 4/9] Adjust skipping tests when provisioning skipped [ Merge of http://go/wvgerrit/194254 ] For some platforms, we cannot provision. In this case, any test that needs provisioning is skipped. However, when a test is skipped in a subroutine, the rest of SetUp is still run. Any failures in SetUp will cause the test to be marked as a failure. This CL duplicates the check for skipping the test in SetUp and in TearDown. Bug: 329467151 Test: WV and unit/integration tests Change-Id: I0087b12a3f26b52ecf62bf7b0e7bcf4fa2c6c763 --- .../cdm/core/test/duration_use_case_test.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libwvdrmengine/cdm/core/test/duration_use_case_test.cpp b/libwvdrmengine/cdm/core/test/duration_use_case_test.cpp index 7346e510..e9c003ef 100644 --- a/libwvdrmengine/cdm/core/test/duration_use_case_test.cpp +++ b/libwvdrmengine/cdm/core/test/duration_use_case_test.cpp @@ -128,6 +128,12 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, // appended to it. void SetUp() override { WvCdmTestBase::SetUp(); + // TODO: b/305093063 - Remove when Drm Reprovisioning server is implemented. + if (wvoec::global_features.provisioning_method == + OEMCrypto_DrmReprovisioning) { + GTEST_SKIP() + << "Skipping until Drm Reprovisioning server support is implemented."; + } EnsureProvisioned(); license_holder_.set_can_persist(GetParam()); ASSERT_NO_FATAL_FAILURE(license_holder_.OpenSession()); @@ -152,6 +158,14 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, } void TearDown() override { + // TODO: b/305093063 - Remove when Drm Reprovisioning server is implemented. + if (wvoec::global_features.provisioning_method == + OEMCrypto_DrmReprovisioning) { + // Since the session was not opened above. We can skip closing the session + // here too. This should be removed when EnsureProvisioning no longer + // skips this test. + return; + } license_holder_.CloseSession(); // Log the time used in this test suite. When this comment was written, // these tests took over three hours. If we want to improve that, we need to From 882c80783bd114a6a6d74f3e5cf156db641ec81f Mon Sep 17 00:00:00 2001 From: Vicky Min Date: Fri, 23 Feb 2024 11:06:50 -0800 Subject: [PATCH 5/9] Update ODK version to 18.4 [ Merge of http://go/wvgerrit/192493 ] Bug: 311951236 Test: WVTS Change-Id: Ia59bfacf91d812f36f7a198632f7fa3462d0b8df --- .../oemcrypto/odk/include/core_message_features.h | 6 +++--- libwvdrmengine/oemcrypto/odk/include/odk_structs.h | 2 +- libwvdrmengine/oemcrypto/odk/test/odk_test.cpp | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libwvdrmengine/oemcrypto/odk/include/core_message_features.h b/libwvdrmengine/oemcrypto/odk/include/core_message_features.h index ea689076..e4d6a0e3 100644 --- a/libwvdrmengine/oemcrypto/odk/include/core_message_features.h +++ b/libwvdrmengine/oemcrypto/odk/include/core_message_features.h @@ -26,9 +26,9 @@ struct CoreMessageFeatures { // This is the published version of the ODK Core Message library. The default // behavior is for the server to restrict messages to at most this version - // number. The default is 18.4. - uint32_t maximum_major_version = 18; - uint32_t maximum_minor_version = 4; + // number. The default is 19.0. + uint32_t maximum_major_version = 19; + uint32_t maximum_minor_version = 0; bool operator==(const CoreMessageFeatures &other) const; bool operator!=(const CoreMessageFeatures &other) const { diff --git a/libwvdrmengine/oemcrypto/odk/include/odk_structs.h b/libwvdrmengine/oemcrypto/odk/include/odk_structs.h index 99cc9f09..c0989277 100644 --- a/libwvdrmengine/oemcrypto/odk/include/odk_structs.h +++ b/libwvdrmengine/oemcrypto/odk/include/odk_structs.h @@ -19,7 +19,7 @@ extern "C" { #define ODK_MINOR_VERSION 0 /* ODK Version string. Date changed automatically on each release. */ -#define ODK_RELEASE_DATE "ODK v19.0 2024-02-10" +#define ODK_RELEASE_DATE "ODK v19.0 2024-02-23" /* The lowest version number for an ODK message. */ #define ODK_FIRST_VERSION 16 diff --git a/libwvdrmengine/oemcrypto/odk/test/odk_test.cpp b/libwvdrmengine/oemcrypto/odk/test/odk_test.cpp index 955741ca..41996d9f 100644 --- a/libwvdrmengine/oemcrypto/odk/test/odk_test.cpp +++ b/libwvdrmengine/oemcrypto/odk/test/odk_test.cpp @@ -1292,7 +1292,8 @@ std::vector TestCases() { {0, 16, 5, 16, 5}, {0, 17, 1, 17, 1}, {0, 17, 2, 17, 2}, - {0, 18, 4, 18, 4}, // Change to 19 when the default version is updated. + {0, 18, 3, 18, 3}, // Change to 19 when the default version is updated. + {0, 18, 4, 18, 4}, }; return test_cases; } From 5e186dcfa665c8e653f1ccd74ea374f723acea3f Mon Sep 17 00:00:00 2001 From: Cong Lin Date: Thu, 14 Mar 2024 10:20:08 -0700 Subject: [PATCH 6/9] Fix bcc length for printing [ Merge of http://go/wvgerrit/194310 ] Resize bcc to the correct length to eliminate the trailing zeros. Bug: 330645490 Test: core unit tests Change-Id: I56b6d30120735a4d7a0f39f29a9f255bd2d2d18c --- libwvdrmengine/cdm/core/test/provisioning_holder.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libwvdrmengine/cdm/core/test/provisioning_holder.cpp b/libwvdrmengine/cdm/core/test/provisioning_holder.cpp index 954b2eff..697beb97 100644 --- a/libwvdrmengine/cdm/core/test/provisioning_holder.cpp +++ b/libwvdrmengine/cdm/core/test/provisioning_holder.cpp @@ -185,6 +185,7 @@ std::string ProvisioningHolder::DumpProvAttempt(const std::string& request, if (result != OEMCrypto_SUCCESS) { info << "--- ERROR GETTING BCC. result=" << result; } else { + bcc.resize(bcc_length); info << "BCC = (len=" << bcc_length << ") " << wvutil::unlimited_b2a_hex(bcc) << "\n" << "Additional Sig = (len=" << signature_length << ") " From 8046719c10fd3a276a8af463fd27bac82a808b12 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Wed, 20 Mar 2024 22:53:19 -0700 Subject: [PATCH 7/9] Correct copyright header [ Merge of http://go/wvgerrit/186825 ] Remove the words ` All rights reserved.` from Widevine's existing copyright headers. For context, see cl/578224540 Bug: 330655176 Test: WVTS PiperOrigin-RevId: 580020267 Change-Id: I43e845b83f438e4ef7f0f542c2f4e427a188ab06 --- libwvdrmengine/oemcrypto/odk/src/odk_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libwvdrmengine/oemcrypto/odk/src/odk_timer.c b/libwvdrmengine/oemcrypto/odk/src/odk_timer.c index c837d783..57e4f431 100644 --- a/libwvdrmengine/oemcrypto/odk/src/odk_timer.c +++ b/libwvdrmengine/oemcrypto/odk/src/odk_timer.c @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC. All rights reserved. This file and proprietary +// Copyright 2019 Google LLC. This file and proprietary // source code may only be used and distributed under the Widevine // License Agreement. From b3157f2328323444b8fce5fe6a518c9177dce14b Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Wed, 20 Mar 2024 23:30:26 -0700 Subject: [PATCH 8/9] Add DRM reprovisioning request generation [ Merge of http://go/wvgerrit/192010 ] Adding files not merged in ag/26501922 Updates the CDM to add support for DRM reprovisioning request creation. - Load the baked-in certificate for use as the client token. - Add functions to build and sign a drm reprovisioning request. - Update the Rikers L3 OEMCrypto implementation to support signing provisioning requests and getting embedded certificate. - Update client id token to handle DRM reprovisioning. - Add OEMCrypto function to load the baked-in device certificate in Rikers CDMs and stubs for non-Rikers CDMs. - Add dynamic adapter support for getting embedded device certificate only on L3. Bug: 305093063 Test: WVTS Change-Id: I839db69a48c1add196f9b56e6ee3812f549f814d --- libwvdrmengine/oemcrypto/test/oec_device_features.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libwvdrmengine/oemcrypto/test/oec_device_features.cpp b/libwvdrmengine/oemcrypto/test/oec_device_features.cpp index 5047a39e..0bd759f6 100644 --- a/libwvdrmengine/oemcrypto/test/oec_device_features.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_device_features.cpp @@ -151,6 +151,7 @@ void DeviceFeatures::PickDerivedKey() { derive_key_method = TEST_PROVISION_30; return; case OEMCrypto_DrmCertificate: + case OEMCrypto_DrmReprovisioning: if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) { derive_key_method = LOAD_TEST_RSA_KEY; } @@ -237,6 +238,8 @@ const char* ProvisioningMethodName(OEMCrypto_ProvisioningMethod method) { return "OEMCrypto_OEMCertificate"; case OEMCrypto_BootCertificateChain: return "OEMCrypto_BootCertificateChain"; + case OEMCrypto_DrmReprovisioning: + return "OEMCrypto_DrmReprovisioning"; } // Not reachable return ""; From a798692e4ec1ef383a32c93449710dfc962a3535 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Wed, 20 Mar 2024 23:49:49 -0700 Subject: [PATCH 9/9] Unit tests for forbidden RSA key usage [ Partial merge of http://go/wvgerrit/188279 ] This CL adds unit tests to verify that the following forbidden uses of an RSA private key do not work: - ForbidPrepAndSign -- A cast cert key cannot sign a license request. - ForbidUseAsDRMCert -- A cast cert cannot be used with the DRM cert's padding scheme and it cannot be used to derive keys from a session key. - *ForbidRSASignatureForDRMKey* -- A DRM cert key cannot be used with GenerateRSASignature. - *OEMCertForbidGenerateRSASignature* -- An OEM cert key cannot be used with GenerateRSASignature. Bug: 251875110 Test: WVTS Change-Id: I55b1eb04465023352edea55ba4ef532d1cd07231 --- libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp index 34c39319..2a6e0197 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp @@ -11,7 +11,7 @@ using ::testing::Range; namespace wvoec { -/// @addtogroup generic +/// @addtogroup cast /// @{ /** If a device can load a private key with the alternate padding schemes, it @@ -82,10 +82,7 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, ForbidPrepAndSign) { OEMCryptoResult result = OEMCrypto_PrepAndSignLicenseRequest( s.session_id(), message.data(), message.size(), &core_message_length, signature.data(), &signature_length); - // TODO: remove OEMCrypto_ERROR_INVALID_RSA_KEY once OEMCrypto v16 is not - // supported anymore. This error code has been deprecated since v17. - ASSERT_TRUE(result == OEMCrypto_ERROR_INVALID_KEY || - result == OEMCrypto_ERROR_INVALID_RSA_KEY); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_KEY, result); const vector zero(signature.size(), 0); ASSERT_EQ(signature, zero); // Signature should not have been computed. }