Snap for 7196743 from 0c87234d45 to tm-release

Change-Id: I8f8f50a0f7e72472d5e6a38c514d6b98dd794e08
This commit is contained in:
android-build-team Robot
2021-03-10 04:17:49 +00:00
16 changed files with 1098 additions and 370 deletions

View File

@@ -7,6 +7,7 @@
#include "crypto_session.h"
#include <inttypes.h>
#include <string.h>
#include <algorithm>
@@ -1745,11 +1746,11 @@ CdmResponseType CryptoSession::GenerateUsageReport(
static_cast<int>(pst_report.pst_length()));
LOGV("OEMCrypto_PST_Report.padding: %d\n",
static_cast<int>(pst_report.padding()));
LOGV("OEMCrypto_PST_Report.seconds_since_license_received: %ld\n",
LOGV("OEMCrypto_PST_Report.seconds_since_license_received: %" PRId64 "\n",
pst_report.seconds_since_license_received());
LOGV("OEMCrypto_PST_Report.seconds_since_first_decrypt: %ld\n",
LOGV("OEMCrypto_PST_Report.seconds_since_first_decrypt: %" PRId64 "\n",
pst_report.seconds_since_first_decrypt());
LOGV("OEMCrypto_PST_Report.seconds_since_last_decrypt: %ld\n",
LOGV("OEMCrypto_PST_Report.seconds_since_last_decrypt: %" PRId64 "\n",
pst_report.seconds_since_last_decrypt());
LOGV("OEMCrypto_PST_Report: %s\n", b2a_hex(*usage_report).c_str());

View File

@@ -558,13 +558,16 @@ bool InitializationData::ConstructWidevineInitData(
// Now format as Widevine init data protobuf
WidevinePsshData cenc_header;
// TODO(rfrias): The algorithm is a deprecated field, but proto changes
// have not yet been pushed to production. Set until then.
// TODO(rfrias): The algorithm and provider are deprecated fields, but proto
// changes have not yet been pushed to production. Set until then.
CORE_UTIL_IGNORE_DEPRECATED
cenc_header.set_algorithm(WidevinePsshData_Algorithm_AESCTR);
cenc_header.set_provider(provider);
CORE_UTIL_RESTORE_WARNINGS
for (size_t i = 0; i < key_ids.size(); ++i) {
cenc_header.add_key_ids(key_ids[i]);
}
cenc_header.set_provider(provider);
cenc_header.set_content_id(content_id);
if (method == kHlsMethodAes128)
cenc_header.set_protection_scheme(kFourCcCbc1);

View File

@@ -225,7 +225,9 @@ class WvCdmEngineTest : public WvCdmEnginePreProvTest {
int status_code = url_request.GetStatusCode(response);
if (expect_success)
EXPECT_EQ(kHttpOk, status_code) << "Error response: " << response;
EXPECT_EQ(kHttpOk, status_code)
<< "Error response from " << server_url << ":\n"
<< response;
if (status_code != kHttpOk) {
return "";
@@ -419,14 +421,14 @@ TEST_F(WvCdmEngineTest, LicenseRenewalSpecifiedServer) {
}
}
// This test generates a renewal and then requests the renewal from the same
// server from which we requested the original license.
TEST_F(WvCdmEngineTest, LicenseRenewalSameServer) {
// This test generates a renewal and then requests it from the server specified
// by the current test configuration.
TEST_F(WvCdmEngineTest, LicenseRenewal) {
GenerateKeyRequest(binary_key_id(), kCencMimeType);
VerifyNewKeyResponse(config_.license_server(), config_.client_auth());
GenerateRenewalRequest();
VerifyRenewalKeyResponse(config_.license_server(), config_.client_auth());
VerifyRenewalKeyResponse(config_.renewal_server(), config_.client_auth());
}
TEST_F(WvCdmEngineTest, ParseDecryptHashStringTest) {

View File

@@ -309,25 +309,13 @@ ConfigTestEnv::ConfigTestEnv(ServerConfigurationId server_id, bool streaming,
}
}
ConfigTestEnv& ConfigTestEnv::operator=(const ConfigTestEnv& other) {
this->server_id_ = other.server_id_;
this->client_auth_ = other.client_auth_;
this->key_id_ = other.key_id_;
this->key_system_ = other.key_system_;
this->license_server_ = other.license_server_;
this->provisioning_server_ = other.provisioning_server_;
this->license_service_certificate_ = other.license_service_certificate_;
this->provisioning_service_certificate_ =
other.provisioning_service_certificate_;
return *this;
}
void ConfigTestEnv::Init(ServerConfigurationId server_id) {
this->server_id_ = server_id;
client_auth_ = license_servers[server_id].client_tag;
key_id_ = license_servers[server_id].key_id;
key_system_ = kWidevineKeySystem;
license_server_ = license_servers[server_id].license_server_url;
renewal_server_.clear();
provisioning_server_ = license_servers[server_id].provisioning_server_url;
license_service_certificate_ =
a2bs_hex(license_servers[server_id].license_service_certificate);

View File

@@ -61,9 +61,12 @@ class ConfigTestEnv {
ConfigTestEnv(ServerConfigurationId server_id, bool streaming);
ConfigTestEnv(ServerConfigurationId server_id, bool streaming, bool renew,
bool release);
// Allow copy and assign. Performance is not an issue in test initialization.
ConfigTestEnv(const ConfigTestEnv &other) { *this = other; };
ConfigTestEnv& operator=(const ConfigTestEnv &other);
// Allow copy, assign, and move. Performance is not an issue in test
// initialization.
ConfigTestEnv(const ConfigTestEnv&) = default;
ConfigTestEnv(ConfigTestEnv&&) = default;
ConfigTestEnv& operator=(const ConfigTestEnv&) = default;
ConfigTestEnv& operator=(ConfigTestEnv&&) = default;
~ConfigTestEnv() {};
@@ -72,6 +75,12 @@ class ConfigTestEnv {
const KeyId& key_id() const { return key_id_; }
const CdmKeySystem& key_system() const { return key_system_; }
const std::string& license_server() const { return license_server_; }
const std::string& renewal_server() const {
if (!renewal_server_.empty())
return renewal_server_;
else
return license_server_;
}
const std::string& provisioning_server() const {
return provisioning_server_;
}
@@ -93,6 +102,9 @@ class ConfigTestEnv {
void set_license_server(const std::string& license_server) {
license_server_.assign(license_server);
}
void set_renewal_server(const std::string& renewal_server) {
renewal_server_.assign(renewal_server);
}
void set_license_service_certificate(
const std::string& license_service_certificate) {
license_service_certificate_.assign(license_service_certificate);
@@ -113,6 +125,7 @@ class ConfigTestEnv {
KeyId key_id_;
CdmKeySystem key_system_;
std::string license_server_;
std::string renewal_server_;
std::string provisioning_server_;
std::string license_service_certificate_;
std::string provisioning_service_certificate_;

File diff suppressed because it is too large Load Diff

View File

@@ -716,8 +716,13 @@ TEST_P(HlsConstructionTest, InitData) {
if (param.success_) {
WidevinePsshData cenc_header;
EXPECT_TRUE(cenc_header.ParseFromString(value));
CORE_UTIL_IGNORE_DEPRECATED
EXPECT_EQ(video_widevine::WidevinePsshData_Algorithm_AESCTR,
cenc_header.algorithm());
EXPECT_EQ(param.provider_, cenc_header.provider());
CORE_UTIL_RESTORE_WARNINGS
for (size_t i = 0; i < param.key_ids_.size(); ++i) {
bool key_id_found = false;
if (param.key_ids_[i].size() != 32) continue;
@@ -729,7 +734,6 @@ TEST_P(HlsConstructionTest, InitData) {
}
EXPECT_TRUE(key_id_found);
}
EXPECT_EQ(param.provider_, cenc_header.provider());
std::vector<uint8_t> param_content_id_vec(Base64Decode(param.content_id_));
EXPECT_EQ(
std::string(param_content_id_vec.begin(), param_content_id_vec.end()),
@@ -822,6 +826,8 @@ TEST_P(HlsParseTest, Parse) {
WidevinePsshData cenc_header;
EXPECT_TRUE(cenc_header.ParseFromString(init_data.data()));
CORE_UTIL_IGNORE_DEPRECATED
EXPECT_EQ(video_widevine::WidevinePsshData_Algorithm_AESCTR,
cenc_header.algorithm());
if (param.key_.compare(kJsonProvider) == 0) {
@@ -831,6 +837,7 @@ TEST_P(HlsParseTest, Parse) {
} else if (param.key_.compare(kJsonKeyIds) == 0) {
EXPECT_EQ(param.value_, b2a_hex(cenc_header.key_ids(0)));
}
CORE_UTIL_RESTORE_WARNINGS
EXPECT_EQ(kHlsIvHexValue, b2a_hex(init_data.hls_iv()));
} else {

View File

@@ -19,6 +19,7 @@
#include "license_request.h"
#include "log.h"
#include "metrics_collections.h"
#include "oec_device_features.h"
#include "test_base.h"
#include "test_printers.h"
#include "test_sleep.h"
@@ -115,22 +116,30 @@ class CorePIGTest : public WvCdmTestBaseWithEngine {
const std::vector<uint8_t> input(buffer_size, 0);
std::vector<uint8_t> output(buffer_size, 0);
const std::vector<uint8_t> iv(KEY_IV_SIZE, 0);
Decrypt(session_id, key_id, input, iv, &output, NO_ERROR);
ASSERT_EQ(NO_ERROR, Decrypt(session_id, key_id, input, iv, &output));
}
// Try to use the key to decrypt, but expect the key has expired.
void FailDecrypt(const CdmSessionId& session_id, const KeyId& key_id) {
void FailDecrypt(const CdmSessionId& session_id, const KeyId& key_id,
CdmResponseType expected_status) {
constexpr size_t buffer_size = 500;
const std::vector<uint8_t> input(buffer_size, 0);
std::vector<uint8_t> output(buffer_size, 0);
const std::vector<uint8_t> iv(KEY_IV_SIZE, 0);
Decrypt(session_id, key_id, input, iv, &output, NEED_KEY);
CdmResponseType status = Decrypt(session_id, key_id, input, iv, &output);
// If the server knows we cannot handle the key, it would not have given us
// the key. In that case, the status should indicate no key.
if (status != NEED_KEY) {
// Otherwise, we should have gotten the expected error.
ASSERT_EQ(expected_status, status);
}
}
void Decrypt(const CdmSessionId& session_id, const KeyId& key_id,
const std::vector<uint8_t>& input,
const std::vector<uint8_t>& iv, std::vector<uint8_t>* output,
CdmResponseType expected_status) {
// Decrypt or fail to decrypt, with the expected status.
CdmResponseType Decrypt(const CdmSessionId& session_id, const KeyId& key_id,
const std::vector<uint8_t>& input,
const std::vector<uint8_t>& iv,
std::vector<uint8_t>* output) {
CdmDecryptionParametersV16 params(key_id);
params.is_secure = false;
CdmDecryptionSample sample(input.data(), output->data(), 0, input.size(),
@@ -138,9 +147,54 @@ class CorePIGTest : public WvCdmTestBaseWithEngine {
CdmDecryptionSubsample subsample(0, input.size());
sample.subsamples.push_back(subsample);
params.samples.push_back(sample);
return cdm_engine_.DecryptV16(session_id, params);
}
// Use the key to decrypt to a secure buffer.
void DecryptSecure(const CdmSessionId& session_id, const KeyId& key_id) {
ASSERT_TRUE(wvoec::global_features.test_secure_buffers);
constexpr size_t buffer_size = 500;
const std::vector<uint8_t> input(buffer_size, 0);
const std::vector<uint8_t> iv(KEY_IV_SIZE, 0);
// To create a secure buffer, we need to know the OEMCrypto session id.
CdmQueryMap query_map;
cdm_engine_.QueryOemCryptoSessionId(session_id, &query_map);
const std::string oec_session_id_string =
query_map[QUERY_KEY_OEMCRYPTO_SESSION_ID];
uint32_t oec_session_id = std::stoi(oec_session_id_string);
int secure_buffer_fid;
OEMCrypto_DestBufferDesc output_descriptor;
output_descriptor.type = OEMCrypto_BufferType_Secure;
output_descriptor.buffer.secure.handle_length = buffer_size;
ASSERT_EQ(
OEMCrypto_AllocateSecureBuffer(oec_session_id, buffer_size,
&output_descriptor, &secure_buffer_fid),
OEMCrypto_SUCCESS);
ASSERT_NE(output_descriptor.buffer.secure.handle, nullptr);
// It is OK if OEMCrypto changes the maximum size, but there must
// still be enough room for our data.
ASSERT_GE(output_descriptor.buffer.secure.handle_length, buffer_size);
output_descriptor.buffer.secure.offset = 0;
// Now create a sample array for the CDM layer.
CdmDecryptionParametersV16 params(key_id);
params.is_secure = true;
CdmDecryptionSample sample(input.data(),
output_descriptor.buffer.secure.handle, 0,
input.size(), iv);
CdmDecryptionSubsample subsample(0, input.size());
sample.subsamples.push_back(subsample);
params.samples.push_back(sample);
CdmResponseType status = cdm_engine_.DecryptV16(session_id, params);
ASSERT_EQ(expected_status, status);
// Free the secure buffer before we check the return status.
OEMCrypto_FreeSecureBuffer(oec_session_id, &output_descriptor,
secure_buffer_fid);
ASSERT_EQ(status, NO_ERROR);
}
};
@@ -192,4 +246,36 @@ TEST_F(CorePIGTest, OfflineWithPST) {
ASSERT_NO_FATAL_FAILURE(CloseSession(session_id));
}
// This test verifies that the system can download and install license with a
// key that requires secure buffers. It also verifies that we cannot decrypt to
// a non-secure buffer using this key, but that we can decrypt to a secure
// buffer, if the test harness supports secure buffers.
TEST_F(CorePIGTest, OfflineHWSecureRequired) {
const std::string content_id = "GTS_HW_SECURE_ALL";
const KeyId key_id = "0000000000000002";
const CdmLicenseType license_type = kLicenseTypeOffline;
CdmSessionId session_id;
ASSERT_NO_FATAL_FAILURE(OpenSession(&session_id));
CdmKeyRequest key_request;
ASSERT_NO_FATAL_FAILURE(
GenerateKeyRequest(session_id, content_id, &key_request, license_type));
std::string key_response;
ASSERT_NO_FATAL_FAILURE(GetKeyResponse(key_request, &key_response));
CdmKeySetId key_set_id;
ASSERT_NO_FATAL_FAILURE(
AddKey(session_id, key_response, license_type, &key_set_id));
// First we try to decrypt to a non-secure buffer and verify that it fails.
// TODO(b/164517875): This error code should be something actionable.
ASSERT_NO_FATAL_FAILURE(FailDecrypt(session_id, key_id, DECRYPT_ERROR));
// Next, if possible, we try to decrypt to a secure buffer, and verify
// success.
if (wvoec::global_features.test_secure_buffers) {
ASSERT_NO_FATAL_FAILURE(DecryptSecure(session_id, key_id));
} else {
LOGI("Test harness cannot create secure buffers. test skipped.");
}
ASSERT_NO_FATAL_FAILURE(CloseSession(session_id));
}
} // namespace wvcdm

View File

@@ -93,6 +93,19 @@ void show_menu(const char* prog_name, const std::string& extra_help_text) {
<< " in the url" << std::endl
<< std::endl;
std::cout << " --renewal_server_url=<url>" << std::endl;
std::cout << " configure the renewal server url, please include http[s] "
"in the url"
<< std::endl
<< " If not set, this defaults to be the same url used by the "
"license server."
<< std::endl
<< " Some tests, such as LicenseRenewalSpecifiedServer, will "
"ignore this setting. "
<< std::endl
<< " See comments in the code for an explanation." << std::endl
<< std::endl;
std::cout << " --provisioning_server_url=<url>" << std::endl;
std::cout
<< " configure the provisioning server url, please include http[s]"
@@ -457,6 +470,8 @@ bool WvCdmTestBase::Initialize(int argc, const char* const argv[],
default_config_.set_provisioning_service_certificate(certificate);
} else if (arg_prefix == "--license_server_url") {
default_config_.set_license_server(arg_value);
} else if (arg_prefix == "--renewal_server_url") {
default_config_.set_renewal_server(arg_value);
} else if (arg_prefix == "--provisioning_server_url") {
default_config_.set_provisioning_server(arg_value);
} else {
@@ -480,6 +495,8 @@ bool WvCdmTestBase::Initialize(int argc, const char* const argv[],
<< default_config_.provisioning_server() << std::endl;
std::cout << "Default License Server: " << default_config_.license_server()
<< std::endl;
std::cout << "Default Renewal Server: " << default_config_.renewal_server()
<< std::endl;
std::cout << "Default KeyID: " << default_config_.key_id() << std::endl
<< std::endl;

View File

@@ -11,7 +11,7 @@
#include "test_base.h"
int main(int argc, char** argv) {
if (!wvcdm::WvCdmTestBase::Initialize(argc, argv)) return 0;
if (!wvcdm::WvCdmTestBase::Initialize(argc, argv)) return 1;
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -78,9 +78,7 @@ struct LoggingUidSetter {
// unit tests.
CORE_UTIL_EXPORT void InitLogging();
// Only enable format specifier warnings on LP64 systems. There is
// no easy portable method to handle format specifiers for int64_t.
#if (defined(__GNUC__) || defined(__clang__)) && defined(__LP64__)
#ifdef __GNUC__
[[gnu::format(printf, 5, 6)]] CORE_UTIL_EXPORT void Log(const char* file,
const char* function,
int line,

View File

@@ -11,12 +11,23 @@
# else
# define CORE_UTIL_EXPORT __declspec(dllimport)
# endif
# define CORE_UTIL_IGNORE_DEPRECATED
# define CORE_UTIL_RESTORE_WARNINGS
#else
# ifdef CORE_UTIL_IMPLEMENTATION
# define CORE_UTIL_EXPORT __attribute__((visibility("default")))
# else
# define CORE_UTIL_EXPORT
# endif
# ifdef __GNUC__
# define CORE_UTIL_IGNORE_DEPRECATED \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
# define CORE_UTIL_RESTORE_WARNINGS _Pragma("GCC diagnostic pop")
# else
# define CORE_UTIL_IGNORE_DEPRECATED
# define CORE_UTIL_RESTORE_WARNINGS
# endif
#endif
#endif // WVCDM_UTIL_UTIL_COMMON_H_

View File

@@ -254,6 +254,8 @@ std::vector<uint8_t> Base64SafeDecode(const std::string& b64_input) {
std::string HexEncode(const uint8_t* in_buffer, unsigned int size) {
static const char kHexChars[] = "0123456789ABCDEF";
if (size == 0) return "";
constexpr unsigned int kMaxSafeSize = 2048;
if (size > kMaxSafeSize) size = kMaxSafeSize;
// Each input byte creates two output hex characters.
std::string out_buffer(size * 2, '\0');

View File

@@ -9,6 +9,9 @@
#else
# include <sys/types.h>
#endif
#ifdef __APPLE__
# include <TargetConditionals.h>
#endif
#include <errno.h>
#include <string.h>
@@ -73,10 +76,13 @@ bool TestSleep::RollbackSystemTime(int seconds) {
file_time.dwHighDateTime = long_time >> 32;
if (!FileTimeToSystemTime(&file_time, &time)) return false;
if (!SetSystemTime(&time)) return false;
#elif TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
LOGE("iOS time rollback: cannot set system time.");
return false;
#else
auto time = std::chrono::system_clock::now();
auto modified_time = time - std::chrono::seconds(seconds);
;
timespec time_spec;
time_spec.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(
modified_time.time_since_epoch())
@@ -140,6 +146,9 @@ bool TestSleep::CanChangeSystemTime() {
}
LOGE("Win32 time rollback: cannot set system time.");
return false;
#elif TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
LOGE("iOS time rollback: cannot set system time.");
return false;
#else
// Otherwise, the test needs to be run as root.
const uid_t uid = getuid();

View File

@@ -0,0 +1,406 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include <stdlib.h>
#include <mutex>
#include <gtest/gtest.h>
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oemcrypto_ref_test_utils.h"
#include "oemcrypto_rsa_key.h"
namespace wvoec_ref {
constexpr size_t kMessageSize = 4 * 1024; // 4 kB
constexpr size_t kCastMessageSize = 83; // Special max size.
class OEMCryptoRsaKeyTest : public ::testing::TestWithParam<RsaFieldSize> {
public:
void SetUp() override {
// RSA key generation is slow (~2 seconds) compared to the
// operations they perform (<50 ms). Each key type is generated
// once and globally stored in serialized form.
// Caching the instance may result in test failures for
// memory-leak detection.
const RsaFieldSize field_size = GetParam();
std::lock_guard<std::mutex> rsa_key_lock(rsa_key_mutex_);
// Use of a switch case is intentional to cause compiler warnings
// if a new field size is introduced without updating the test.
switch (field_size) {
case kRsa2048Bit: {
if (!rsa_2048_key_data_.empty()) {
key_ = RsaPrivateKey::Load(rsa_2048_key_data_);
}
if (!key_) {
key_ = RsaPrivateKey::New(kRsa2048Bit);
}
if (rsa_2048_key_data_.empty() && key_) {
rsa_2048_key_data_ = key_->Serialize();
}
} break;
case kRsa3072Bit: {
if (!rsa_3072_key_data_.empty()) {
key_ = RsaPrivateKey::Load(rsa_3072_key_data_);
}
if (!key_) {
key_ = RsaPrivateKey::New(kRsa3072Bit);
}
if (rsa_3072_key_data_.empty() && key_) {
rsa_3072_key_data_ = key_->Serialize();
}
} break;
case kRsaFieldUnknown: // Suppress compiler warnings
LOGE("RSA test was incorrectly instantiation");
exit(EXIT_FAILURE);
break;
}
}
void TearDown() override { key_.reset(); }
protected:
std::unique_ptr<RsaPrivateKey> key_;
static std::mutex rsa_key_mutex_;
static std::vector<uint8_t> rsa_2048_key_data_;
static std::vector<uint8_t> rsa_3072_key_data_;
};
std::mutex OEMCryptoRsaKeyTest::rsa_key_mutex_;
std::vector<uint8_t> OEMCryptoRsaKeyTest::rsa_2048_key_data_;
std::vector<uint8_t> OEMCryptoRsaKeyTest::rsa_3072_key_data_;
// Basic verification of RSA private key generation.
TEST_P(OEMCryptoRsaKeyTest, KeyProperties) {
ASSERT_TRUE(key_);
const RsaFieldSize expected_field_size = GetParam();
EXPECT_EQ(key_->field_size(), expected_field_size);
EXPECT_NE(nullptr, key_->GetRsaKey());
}
// Checks that the private key serialization APIs are compatible
// and performing in a manner that is similar to other OEMCrypto methods
// that retrieve data.
TEST_P(OEMCryptoRsaKeyTest, SerializePrivateKey) {
ASSERT_TRUE(key_);
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t buffer_size = kInitialBufferSize;
std::vector<uint8_t> buffer(buffer_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
key_->Serialize(buffer.data(), &buffer_size));
EXPECT_GT(buffer_size, kInitialBufferSize);
buffer.resize(buffer_size);
EXPECT_EQ(OEMCrypto_SUCCESS, key_->Serialize(buffer.data(), &buffer_size));
buffer.resize(buffer_size);
const std::vector<uint8_t> direct_key_data = key_->Serialize();
EXPECT_FALSE(direct_key_data.empty());
ASSERT_EQ(buffer.size(), direct_key_data.size());
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that a private key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPrivateKey) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> key_data = key_->Serialize();
std::unique_ptr<RsaPrivateKey> loaded_key = RsaPrivateKey::Load(key_data);
ASSERT_TRUE(loaded_key);
EXPECT_EQ(key_->field_size(), loaded_key->field_size());
const std::vector<uint8_t> loaded_key_data = loaded_key->Serialize();
ASSERT_EQ(key_data.size(), loaded_key_data.size());
for (size_t i = 0; i < key_data.size(); i++) {
ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that a private key with explicitly indicated schemes include
// the scheme fields in the reserialized key.
TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPrivateKeyWithAllowedSchemes) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> raw_key_data = key_->Serialize();
std::vector<uint8_t> key_data = {'S', 'I', 'G', 'N', 0x00, 0x00, 0x00, 0x03};
key_data.insert(key_data.end(), raw_key_data.begin(), raw_key_data.end());
std::unique_ptr<RsaPrivateKey> explicit_key = RsaPrivateKey::Load(key_data);
ASSERT_TRUE(explicit_key);
EXPECT_EQ(key_->field_size(), explicit_key->field_size());
EXPECT_EQ(explicit_key->allowed_schemes(), 0x03);
const std::vector<uint8_t> explicit_key_data = explicit_key->Serialize();
ASSERT_EQ(key_data.size(), explicit_key_data.size());
ASSERT_EQ(key_data, explicit_key_data);
}
// Checks that a public key can be created from the private key.
TEST_P(OEMCryptoRsaKeyTest, DerivePublicKey) {
ASSERT_TRUE(key_);
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_TRUE(key_->IsMatchingPublicKey(*pub_key));
}
// Checks that the public key serialization APIs are compatible
// and performing in a manner that is similar to other OEMCrypto methods
// that retrieve data.
TEST_P(OEMCryptoRsaKeyTest, SerializePublicKey) {
ASSERT_TRUE(key_);
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t buffer_size = kInitialBufferSize;
std::vector<uint8_t> buffer(buffer_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
pub_key->Serialize(buffer.data(), &buffer_size));
EXPECT_GT(buffer_size, kInitialBufferSize);
buffer.resize(buffer_size);
EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->Serialize(buffer.data(), &buffer_size));
buffer.resize(buffer_size);
const std::vector<uint8_t> direct_key_data = pub_key->Serialize();
EXPECT_FALSE(direct_key_data.empty());
ASSERT_EQ(buffer.size(), direct_key_data.size());
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that a public key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPublicKey) {
ASSERT_TRUE(key_);
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
const std::vector<uint8_t> key_data = pub_key->Serialize();
std::unique_ptr<RsaPublicKey> loaded_key = RsaPublicKey::Load(key_data);
ASSERT_TRUE(loaded_key);
EXPECT_EQ(pub_key->field_size(), loaded_key->field_size());
EXPECT_EQ(pub_key->allowed_schemes(), loaded_key->allowed_schemes());
const std::vector<uint8_t> loaded_key_data = loaded_key->Serialize();
ASSERT_EQ(key_data.size(), loaded_key_data.size());
for (size_t i = 0; i < key_data.size(); i++) {
ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that the RSA signature generating API operates similar to
// existing signature generation functions.
TEST_P(OEMCryptoRsaKeyTest, GenerateSignature) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> message = RandomData(kMessageSize);
ASSERT_FALSE(message.empty()) << "CdmRandom failed";
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t signature_size = kInitialBufferSize;
std::vector<uint8_t> signature(signature_size);
EXPECT_EQ(
OEMCrypto_ERROR_SHORT_BUFFER,
key_->GenerateSignature(message.data(), message.size(), kRsaPssDefault,
signature.data(), &signature_size));
EXPECT_GT(signature_size, kInitialBufferSize);
signature.resize(signature_size);
EXPECT_EQ(
OEMCrypto_SUCCESS,
key_->GenerateSignature(message.data(), message.size(), kRsaPssDefault,
signature.data(), &signature_size));
signature.resize(signature_size);
EXPECT_LE(signature_size, key_->SignatureSize());
}
// Checks that RSA signatures can be verified by an RSA public key.
TEST_P(OEMCryptoRsaKeyTest, VerifySignature) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> message = RandomData(kMessageSize);
ASSERT_FALSE(message.empty()) << "CdmRandom failed";
const std::vector<uint8_t> signature = key_->GenerateSignature(message);
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->VerifySignature(message, signature));
// Check with different message.
const std::vector<uint8_t> message_two = RandomData(kMessageSize);
EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
pub_key->VerifySignature(message_two, signature));
// Check with bad signature.
const std::vector<uint8_t> bad_signature = RandomData(signature.size());
EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
pub_key->VerifySignature(message, bad_signature));
}
// Checks that the special CAST receiver signature scheme works
// to the degree that it is possible to test.
TEST_P(OEMCryptoRsaKeyTest, GenerateAndVerifyRsaSignature) {
ASSERT_TRUE(key_);
// Key must be enabled for PKCS1 Block 1 padding scheme.
// To do so, the key is serialized and the padding scheme is
// added to the key data.
const std::vector<uint8_t> key_data = key_->Serialize();
ASSERT_FALSE(key_data.empty());
std::vector<uint8_t> pkcs_enabled_key_data = {
'S', 'I', 'G', 'N', 0x00, 0x00, 0x00, kSign_PKCS1_Block1};
pkcs_enabled_key_data.insert(pkcs_enabled_key_data.end(), key_data.begin(),
key_data.end());
std::unique_ptr<RsaPrivateKey> pkcs_enabled_key =
RsaPrivateKey::Load(pkcs_enabled_key_data);
ASSERT_TRUE(pkcs_enabled_key);
// The actual cast message is a domain specific hash of the message,
// however, random data works for testing purposes.
const std::vector<uint8_t> message = RandomData(kCastMessageSize);
// Generate signature.
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t signature_size = kInitialBufferSize;
std::vector<uint8_t> signature(signature_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
pkcs_enabled_key->GenerateSignature(message.data(), message.size(),
kRsaPkcs1Cast, signature.data(),
&signature_size));
EXPECT_GT(signature_size, kInitialBufferSize);
signature.resize(signature_size);
EXPECT_EQ(OEMCrypto_SUCCESS,
pkcs_enabled_key->GenerateSignature(message.data(), message.size(),
kRsaPkcs1Cast, signature.data(),
&signature_size));
signature.resize(signature_size);
EXPECT_LE(signature_size, pkcs_enabled_key->SignatureSize());
// Verify signature.
std::unique_ptr<RsaPublicKey> pub_key = pkcs_enabled_key->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_EQ(OEMCrypto_SUCCESS,
pub_key->VerifySignature(message, signature, kRsaPkcs1Cast));
}
// Verifies the session key exchange protocol used by the licensing
// server.
TEST_P(OEMCryptoRsaKeyTest, ShareSessionKey) {
constexpr size_t kSessionKeySize = 16;
ASSERT_TRUE(key_);
std::unique_ptr<RsaPublicKey> public_key = key_->MakePublicKey();
ASSERT_TRUE(public_key);
// Generate session key.
const std::vector<uint8_t> session_key = RandomData(kSessionKeySize);
ASSERT_FALSE(session_key.empty());
// Server's perspective.
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t enc_session_key_size = kInitialBufferSize;
std::vector<uint8_t> enc_session_key(enc_session_key_size);
OEMCryptoResult result = public_key->EncryptSessionKey(
session_key.data(), session_key.size(), enc_session_key.data(),
&enc_session_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
enc_session_key.resize(enc_session_key_size);
result = public_key->EncryptSessionKey(session_key.data(), session_key.size(),
enc_session_key.data(),
&enc_session_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
enc_session_key.resize(enc_session_key_size);
// Client's perspective.
size_t received_session_key_size = kInitialBufferSize;
std::vector<uint8_t> received_session_key(received_session_key_size);
result = key_->DecryptSessionKey(
enc_session_key.data(), enc_session_key.size(),
received_session_key.data(), &received_session_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
received_session_key.resize(received_session_key_size);
result = key_->DecryptSessionKey(
enc_session_key.data(), enc_session_key.size(),
received_session_key.data(), &received_session_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
received_session_key.resize(received_session_key_size);
// Compare keys.
ASSERT_EQ(session_key.size(), received_session_key.size());
ASSERT_EQ(session_key, received_session_key);
}
// Verifies the encryption key exchange protocol used by the licensing
// server.
TEST_P(OEMCryptoRsaKeyTest, ShareEncryptionKey) {
constexpr size_t kEncryptionKeySize = 16;
ASSERT_TRUE(key_);
std::unique_ptr<RsaPublicKey> public_key = key_->MakePublicKey();
ASSERT_TRUE(public_key);
// Generate session key.
const std::vector<uint8_t> encryption_key = RandomData(kEncryptionKeySize);
ASSERT_FALSE(encryption_key.empty());
// Server's perspective.
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t enc_encryption_key_size = kInitialBufferSize;
std::vector<uint8_t> enc_encryption_key(enc_encryption_key_size);
OEMCryptoResult result = public_key->EncryptEncryptionKey(
encryption_key.data(), encryption_key.size(), enc_encryption_key.data(),
&enc_encryption_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
enc_encryption_key.resize(enc_encryption_key_size);
result = public_key->EncryptEncryptionKey(
encryption_key.data(), encryption_key.size(), enc_encryption_key.data(),
&enc_encryption_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
enc_encryption_key.resize(enc_encryption_key_size);
// Client's perspective.
size_t received_encryption_key_size = kInitialBufferSize;
std::vector<uint8_t> received_encryption_key(received_encryption_key_size);
result = key_->DecryptEncryptionKey(
enc_encryption_key.data(), enc_encryption_key.size(),
received_encryption_key.data(), &received_encryption_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
received_encryption_key.resize(received_encryption_key_size);
result = key_->DecryptEncryptionKey(
enc_encryption_key.data(), enc_encryption_key.size(),
received_encryption_key.data(), &received_encryption_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
received_encryption_key.resize(received_encryption_key_size);
// Compare keys.
ASSERT_EQ(encryption_key.size(), received_encryption_key.size());
ASSERT_EQ(encryption_key, received_encryption_key);
}
INSTANTIATE_TEST_CASE_P(AllFieldSizes, OEMCryptoRsaKeyTest,
::testing::Values(kRsa2048Bit, kRsa3072Bit));
} // namespace wvoec_ref

View File

@@ -106,8 +106,8 @@ adb_shell_run request_license_test $PROVISIONING_ARG
# Additional tests
adb_shell_run base64_test
adb_shell_run buffer_reader_test
adb_shell_run cdm_engine_test
adb_shell_run cdm_engine_metrics_decorator_unittest
adb_shell_run cdm_engine_test
adb_shell_run cdm_session_unittest
adb_shell_run certificate_provisioning_unittest
adb_shell_run counter_metric_unittest