Update partner repo
This change includes: - update zlib - add helper to initialize whitebox on another thread - provider key on security level SW_SECURE_CRYPTO above
This commit is contained in:
@@ -56,9 +56,9 @@ git_repository(
|
||||
http_archive(
|
||||
name = "zlib",
|
||||
build_file = "@com_google_protobuf//:third_party/zlib.BUILD",
|
||||
sha256 = "ff0ba4c292013dbc27530b3a81e1f9a813cd39de01ca5e0f8bf355702efa593e",
|
||||
strip_prefix = "zlib-1.3",
|
||||
urls = ["https://zlib.net/zlib-1.3.tar.gz"],
|
||||
sha256 = "9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23",
|
||||
strip_prefix = "zlib-1.3.1",
|
||||
urls = ["https://zlib.net/zlib-1.3.1.tar.gz"],
|
||||
)
|
||||
|
||||
# ODK
|
||||
|
||||
@@ -23,6 +23,7 @@ cc_library(
|
||||
# protocol v2.2 enabled (b/177271059).
|
||||
# TODO(kqyang): Remove the flag after deprecating v16.x server SDKs.
|
||||
"WORKAROUND_STRIP_PADDING_BUG",
|
||||
"PROVIDER_KEY_SW_SECURE_CRYPTO_ABOVE",
|
||||
],
|
||||
}) + select({
|
||||
"//:is_chromeos": ["WV_ENABLE_HW_VERIFICATION=1"],
|
||||
|
||||
@@ -613,7 +613,6 @@ TEST_P(LicenseWhiteboxDecryptTest, MismatchProviderKeyId) {
|
||||
if (!LoadLicense(settings, other_provider_key_id))
|
||||
GTEST_SKIP();
|
||||
|
||||
// Decryption should succeed, but the plaintext should be incorrect.
|
||||
ASSERT_EQ(WB_License_Decrypt(
|
||||
whitebox_, WB_CIPHER_MODE_CBC,
|
||||
golden_data_.CBCContent().software_crypto_key.id.data(),
|
||||
@@ -625,7 +624,14 @@ TEST_P(LicenseWhiteboxDecryptTest, MismatchProviderKeyId) {
|
||||
&plaintext_size_),
|
||||
WB_RESULT_OK);
|
||||
plaintext_.resize(plaintext_size_);
|
||||
// If the software_crypto_key doesn't use provider key, the mismatched
|
||||
// provider does not affect content decryption. Otherwise, the decyrption
|
||||
// would be in correct.
|
||||
#ifdef PROVIDER_KEY_SW_SECURE_CRYPTO_ABOVE
|
||||
ASSERT_EQ(plaintext_, golden_data_.CBCContent().plaintext);
|
||||
#else
|
||||
ASSERT_NE(plaintext_, golden_data_.CBCContent().plaintext);
|
||||
#endif
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
|
||||
@@ -63,6 +63,31 @@ class LicenseWhitebox {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SignRequest() {
|
||||
if (!whitebox_)
|
||||
return false;
|
||||
|
||||
size_t license_request_signature_size = 256;
|
||||
std::vector<uint8_t> license_request_signature(
|
||||
license_request_signature_size);
|
||||
std::vector<uint8_t> invalid_license_request = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
|
||||
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
||||
auto const result = WB_License_SignLicenseRequest(
|
||||
whitebox_, invalid_license_request.data(),
|
||||
invalid_license_request.size(), license_request_signature.data(),
|
||||
&license_request_signature_size);
|
||||
if (result != WB_RESULT_OK) {
|
||||
LOG(ERROR) << "WB_License_SignLicenseRequest failed: " << result;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WB_License_Whitebox* whitebox() { return whitebox_; }
|
||||
|
||||
private:
|
||||
@@ -77,6 +102,11 @@ int main(int argc, char** argv) {
|
||||
|
||||
widevine::LicenseWhitebox whitebox;
|
||||
|
||||
if (!whitebox.SignRequest()) {
|
||||
LOG(ERROR) << "Failed to sign license.";
|
||||
return 1;
|
||||
}
|
||||
|
||||
widevine::GoldenData golden_data;
|
||||
if (!whitebox.LoadLicense(golden_data.CTRContent().software_crypto_key)) {
|
||||
LOG(ERROR) << "Failed to load license.";
|
||||
|
||||
@@ -281,14 +281,23 @@ std::vector<uint8_t> GetPadding(TestLicenseBuilder::Padding padding) {
|
||||
|
||||
// Wrap the content key |unwrapped_content_key| using |provider_key_id| and
|
||||
// |key_encryption_key|, as appropriate.
|
||||
std::string WrapContentKey(const std::vector<uint8_t>& unwrapped_content_key,
|
||||
size_t provider_key_id,
|
||||
const std::string& key_encryption_key,
|
||||
const std::string& key_encryption_key_iv) {
|
||||
std::string WrapContentKey(
|
||||
const std::vector<uint8_t>& unwrapped_content_key,
|
||||
size_t provider_key_id,
|
||||
const std::string& key_encryption_key,
|
||||
const std::string& key_encryption_key_iv,
|
||||
video_widevine::License_KeyContainer_SecurityLevel security_level) {
|
||||
auto provider_keys = GetProviderKeys();
|
||||
const bool provider_key_id_valid =
|
||||
bool provider_key_id_valid =
|
||||
(provider_key_id >= 1 && provider_key_id <= provider_keys.size());
|
||||
|
||||
#ifdef PROVIDER_KEY_SW_SECURE_CRYPTO_ABOVE
|
||||
provider_key_id_valid =
|
||||
provider_key_id_valid &&
|
||||
security_level !=
|
||||
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO;
|
||||
#endif
|
||||
|
||||
// If |provider_key_id| is used, encrypt the unwrapped key using the
|
||||
// appropriate provider key. Otherwise, use |unwrapped_content_key| for the
|
||||
// next step.
|
||||
@@ -353,7 +362,8 @@ void AddContentKeyToContainer(const ContentKeyData& key_data,
|
||||
key.insert(key.end(), padding.begin(), padding.end());
|
||||
|
||||
auto wrapped_content_key =
|
||||
WrapContentKey(key, settings.provider_key_id, container_key, key_iv);
|
||||
WrapContentKey(key, settings.provider_key_id, container_key, key_iv,
|
||||
container->level());
|
||||
container->set_key(wrapped_content_key);
|
||||
|
||||
if (settings.content_key_key_size_override) {
|
||||
|
||||
105
whitebox/crypto_utils/whitebox_init_helper.h
Normal file
105
whitebox/crypto_utils/whitebox_init_helper.h
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
|
||||
#ifndef WHITEBOX_INIT_HELPER_H_
|
||||
#define WHITEBOX_INIT_HELPER_H_
|
||||
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
|
||||
#include <api/license_whitebox.h>
|
||||
|
||||
/**
|
||||
* Defines a helper class to initialize the Zimperium whitebox. This spawns
|
||||
* a background thread to initialize in the background.
|
||||
*/
|
||||
template <typename Thread = std::thread,
|
||||
typename Mutex = std::mutex,
|
||||
typename ConditionVariable =
|
||||
typename std::conditional<std::is_same<Mutex, std::mutex>::value,
|
||||
std::condition_variable,
|
||||
std::condition_variable_any>::type>
|
||||
class WhiteboxInitHelper final {
|
||||
public:
|
||||
enum class State {
|
||||
None,
|
||||
SignReady,
|
||||
ProcessReady,
|
||||
Error,
|
||||
};
|
||||
|
||||
WhiteboxInitHelper() {}
|
||||
~WhiteboxInitHelper() {
|
||||
if (thread_) thread_->join();
|
||||
}
|
||||
|
||||
State state() const {
|
||||
std::unique_lock<Mutex> lock(mutex_);
|
||||
return state_;
|
||||
}
|
||||
|
||||
WB_Result result() const {
|
||||
std::unique_lock<Mutex> lock(mutex_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
/** Spawns the background thread and starts initializing. */
|
||||
void StartThread() {
|
||||
if (!thread_) {
|
||||
thread_.reset(
|
||||
new Thread(std::bind(&WhiteboxInitHelper::ThreadMain, this)));
|
||||
}
|
||||
}
|
||||
|
||||
/** Blocks the current thread until the sign initialization has finished. */
|
||||
WB_Result EnsureSignReady() {
|
||||
std::unique_lock<Mutex> lock(mutex_);
|
||||
while (state_ < State::SignReady) {
|
||||
cond_.wait(lock);
|
||||
}
|
||||
return result_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks the current thread until the process initialization has finished.
|
||||
*/
|
||||
WB_Result EnsureProcessReady() {
|
||||
std::unique_lock<Mutex> lock(mutex_);
|
||||
while (state_ < State::ProcessReady) {
|
||||
cond_.wait(lock);
|
||||
}
|
||||
return result_;
|
||||
}
|
||||
|
||||
private:
|
||||
void ThreadMain() {
|
||||
auto result = WB_License_SignLicenseRequest_Init();
|
||||
{
|
||||
std::unique_lock<Mutex> lock(mutex_);
|
||||
state_ = result == WB_RESULT_OK ? State::SignReady : State::Error;
|
||||
result_ = result;
|
||||
cond_.notify_all();
|
||||
if (result != WB_RESULT_OK) return;
|
||||
}
|
||||
|
||||
result = WB_License_ProcessLicenseResponse_Init();
|
||||
|
||||
std::unique_lock<Mutex> lock(mutex_);
|
||||
state_ = result == WB_RESULT_OK ? State::ProcessReady : State::Error;
|
||||
result_ = result;
|
||||
cond_.notify_all();
|
||||
}
|
||||
|
||||
std::unique_ptr<Thread> thread_;
|
||||
ConditionVariable cond_;
|
||||
Mutex mutex_;
|
||||
State state_ = State::None;
|
||||
WB_Result result_ = WB_RESULT_OK;
|
||||
};
|
||||
|
||||
#endif // WHITEBOX_INIT_HELPER_H_
|
||||
@@ -37,12 +37,20 @@ bool LicenseParser::UnwrapKey(
|
||||
size_t provider_key_id,
|
||||
const std::string& key_decryption_key,
|
||||
const std::string& key_decryption_key_iv,
|
||||
video_widevine::License_KeyContainer_SecurityLevel security_level,
|
||||
std::string* unwrapped_key) {
|
||||
// provider keys are only applied on content keys.
|
||||
const bool provider_key_id_valid =
|
||||
bool provider_key_id_valid =
|
||||
(provider_key_id >= 1 && provider_key_id <= provider_keys.size() &&
|
||||
key_type == KeyType::kContentKey);
|
||||
|
||||
#ifdef PROVIDER_KEY_SW_SECURE_CRYPTO_ABOVE
|
||||
provider_key_id_valid =
|
||||
provider_key_id_valid &&
|
||||
security_level !=
|
||||
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO;
|
||||
#endif
|
||||
|
||||
// If |provider_key_id| is used and valid, then start by unmasking it.
|
||||
std::string key = wrapped_key;
|
||||
if (provider_key_id_valid) {
|
||||
|
||||
@@ -50,16 +50,18 @@ class LicenseParser {
|
||||
const std::string& encrypted,
|
||||
std::string* decrypted);
|
||||
|
||||
// Unwrap key |wrapped_key| using |key_type|, |provider_key_id| and
|
||||
// |key_decryption_key|, as necessary. Returns true and
|
||||
// Unwrap key |wrapped_key| using |key_type|, |provider_key_id|,
|
||||
// |key_decryption_key| and |security_level|, as necessary. Returns true and
|
||||
// |unwrapped_content_key| is updated on success, false otherwise.
|
||||
static bool UnwrapKey(KeyType key_type,
|
||||
const std::string& wrapped_key,
|
||||
const std::vector<ProviderKey>& provider_keys,
|
||||
size_t provider_key_id,
|
||||
const std::string& key_decryption_key,
|
||||
const std::string& key_decryption_key_iv,
|
||||
std::string* unwrapped_key);
|
||||
static bool UnwrapKey(
|
||||
KeyType key_type,
|
||||
const std::string& wrapped_key,
|
||||
const std::vector<ProviderKey>& provider_keys,
|
||||
size_t provider_key_id,
|
||||
const std::string& key_decryption_key,
|
||||
const std::string& key_decryption_key_iv,
|
||||
video_widevine::License_KeyContainer_SecurityLevel security_level,
|
||||
std::string* unwrapped_key);
|
||||
|
||||
// Creates and returns a InternalKey based on the values provided.
|
||||
// |level| determines whether decrypt or masked_decrypt is allowed.
|
||||
|
||||
@@ -258,7 +258,7 @@ InternalKey OdkLicenseParser::ParseInternalKey(
|
||||
|
||||
std::string unwrapped_key;
|
||||
if (!UnwrapKey(key_type, wrapped_key, provider_keys, provider_key_id,
|
||||
decryption_key, iv, &unwrapped_key)) {
|
||||
decryption_key, iv, security_level, &unwrapped_key)) {
|
||||
VLOG(3) << "Failed to decrypt key.";
|
||||
return InternalKey();
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ InternalKey ProtobufLicenseParser::ParseInternalKey(
|
||||
std::string wrapped_key = key.key().substr(0, key_size_without_padding);
|
||||
std::string unwrapped_key;
|
||||
if (!UnwrapKey(key_type, wrapped_key, provider_keys, provider_key_id,
|
||||
decryption_key, key.iv(), &unwrapped_key)) {
|
||||
decryption_key, key.iv(), key.level(), &unwrapped_key)) {
|
||||
VLOG(3) << "Failed to decrypt content key.";
|
||||
return InternalKey();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user