Merge changes I55b1eb04,I839db69a,I43e845b8,I56b6d301,Ia59bfacf, ... into main
* changes: Unit tests for forbidden RSA key usage Add DRM reprovisioning request generation Correct copyright header Fix bcc length for printing Update ODK version to 18.4 Adjust skipping tests when provisioning skipped Change test storage to use protobuf Remove WvCdmEnginePreProvTestStaging Rename and clarify Drm Reprovisioning token types
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -404,7 +404,7 @@ bool ClientIdentification::GetProvisioningTokenType(
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case kClientTokenDrmReprovisioning:
|
||||
case kClientTokenDrmCertificateReprovisioning:
|
||||
*token_type =
|
||||
video_widevine::ClientIdentification::DRM_DEVICE_CERTIFICATE;
|
||||
return true;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ message NameValue {
|
||||
optional string value = 2;
|
||||
}
|
||||
|
||||
message SavedStorage {
|
||||
map<string, string> files = 1;
|
||||
}
|
||||
|
||||
message OemCertificate {
|
||||
enum PrivateKeyType {
|
||||
RSA = 0;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -482,7 +482,7 @@ TEST_P(CertificateProvisioningTest, ProvisioningResponseSuccess) {
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
CertificateProvisioningTests, CertificateProvisioningTest,
|
||||
testing::Values(kClientTokenKeybox, kClientTokenOemCert,
|
||||
kClientTokenDrmReprovisioning),
|
||||
kClientTokenDrmCertificateReprovisioning),
|
||||
[](const testing::TestParamInfo<CertificateProvisioningTest::ParamType>&
|
||||
param_type) {
|
||||
return CdmClientTokenTypeToString(param_type.param);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 << ") "
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
#include <sstream>
|
||||
|
||||
#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<uint8_t> 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<uint8_t> 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<std::string, std::string>& 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<std::string, std::string>* 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<ssize_t>(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<std::string, std::string> map1;
|
||||
const std::string dump = DumpData(map1);
|
||||
std::map<std::string, std::string> 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<std::string, std::string> 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";
|
||||
|
||||
@@ -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<std::string, std::string>& 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<std::string, std::string>* data);
|
||||
|
||||
static int test_pass() { return default_config_->test_pass(); }
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -1292,7 +1292,8 @@ std::vector<VersionParameters> 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;
|
||||
}
|
||||
|
||||
@@ -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 "";
|
||||
|
||||
@@ -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<uint8_t> zero(signature.size(), 0);
|
||||
ASSERT_EQ(signature, zero); // Signature should not have been computed.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user