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(
|
http_archive(
|
||||||
name = "zlib",
|
name = "zlib",
|
||||||
build_file = "@com_google_protobuf//:third_party/zlib.BUILD",
|
build_file = "@com_google_protobuf//:third_party/zlib.BUILD",
|
||||||
sha256 = "ff0ba4c292013dbc27530b3a81e1f9a813cd39de01ca5e0f8bf355702efa593e",
|
sha256 = "9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23",
|
||||||
strip_prefix = "zlib-1.3",
|
strip_prefix = "zlib-1.3.1",
|
||||||
urls = ["https://zlib.net/zlib-1.3.tar.gz"],
|
urls = ["https://zlib.net/zlib-1.3.1.tar.gz"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# ODK
|
# ODK
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ cc_library(
|
|||||||
# protocol v2.2 enabled (b/177271059).
|
# protocol v2.2 enabled (b/177271059).
|
||||||
# TODO(kqyang): Remove the flag after deprecating v16.x server SDKs.
|
# TODO(kqyang): Remove the flag after deprecating v16.x server SDKs.
|
||||||
"WORKAROUND_STRIP_PADDING_BUG",
|
"WORKAROUND_STRIP_PADDING_BUG",
|
||||||
|
"PROVIDER_KEY_SW_SECURE_CRYPTO_ABOVE",
|
||||||
],
|
],
|
||||||
}) + select({
|
}) + select({
|
||||||
"//:is_chromeos": ["WV_ENABLE_HW_VERIFICATION=1"],
|
"//:is_chromeos": ["WV_ENABLE_HW_VERIFICATION=1"],
|
||||||
|
|||||||
@@ -613,7 +613,6 @@ TEST_P(LicenseWhiteboxDecryptTest, MismatchProviderKeyId) {
|
|||||||
if (!LoadLicense(settings, other_provider_key_id))
|
if (!LoadLicense(settings, other_provider_key_id))
|
||||||
GTEST_SKIP();
|
GTEST_SKIP();
|
||||||
|
|
||||||
// Decryption should succeed, but the plaintext should be incorrect.
|
|
||||||
ASSERT_EQ(WB_License_Decrypt(
|
ASSERT_EQ(WB_License_Decrypt(
|
||||||
whitebox_, WB_CIPHER_MODE_CBC,
|
whitebox_, WB_CIPHER_MODE_CBC,
|
||||||
golden_data_.CBCContent().software_crypto_key.id.data(),
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
||||||
@@ -625,7 +624,14 @@ TEST_P(LicenseWhiteboxDecryptTest, MismatchProviderKeyId) {
|
|||||||
&plaintext_size_),
|
&plaintext_size_),
|
||||||
WB_RESULT_OK);
|
WB_RESULT_OK);
|
||||||
plaintext_.resize(plaintext_size_);
|
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);
|
ASSERT_NE(plaintext_, golden_data_.CBCContent().plaintext);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
|||||||
@@ -63,6 +63,31 @@ class LicenseWhitebox {
|
|||||||
return true;
|
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_; }
|
WB_License_Whitebox* whitebox() { return whitebox_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -77,6 +102,11 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
widevine::LicenseWhitebox whitebox;
|
widevine::LicenseWhitebox whitebox;
|
||||||
|
|
||||||
|
if (!whitebox.SignRequest()) {
|
||||||
|
LOG(ERROR) << "Failed to sign license.";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
widevine::GoldenData golden_data;
|
widevine::GoldenData golden_data;
|
||||||
if (!whitebox.LoadLicense(golden_data.CTRContent().software_crypto_key)) {
|
if (!whitebox.LoadLicense(golden_data.CTRContent().software_crypto_key)) {
|
||||||
LOG(ERROR) << "Failed to load license.";
|
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
|
// Wrap the content key |unwrapped_content_key| using |provider_key_id| and
|
||||||
// |key_encryption_key|, as appropriate.
|
// |key_encryption_key|, as appropriate.
|
||||||
std::string WrapContentKey(const std::vector<uint8_t>& unwrapped_content_key,
|
std::string WrapContentKey(
|
||||||
size_t provider_key_id,
|
const std::vector<uint8_t>& unwrapped_content_key,
|
||||||
const std::string& key_encryption_key,
|
size_t provider_key_id,
|
||||||
const std::string& key_encryption_key_iv) {
|
const std::string& key_encryption_key,
|
||||||
|
const std::string& key_encryption_key_iv,
|
||||||
|
video_widevine::License_KeyContainer_SecurityLevel security_level) {
|
||||||
auto provider_keys = GetProviderKeys();
|
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());
|
(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
|
// If |provider_key_id| is used, encrypt the unwrapped key using the
|
||||||
// appropriate provider key. Otherwise, use |unwrapped_content_key| for the
|
// appropriate provider key. Otherwise, use |unwrapped_content_key| for the
|
||||||
// next step.
|
// next step.
|
||||||
@@ -353,7 +362,8 @@ void AddContentKeyToContainer(const ContentKeyData& key_data,
|
|||||||
key.insert(key.end(), padding.begin(), padding.end());
|
key.insert(key.end(), padding.begin(), padding.end());
|
||||||
|
|
||||||
auto wrapped_content_key =
|
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);
|
container->set_key(wrapped_content_key);
|
||||||
|
|
||||||
if (settings.content_key_key_size_override) {
|
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,
|
size_t provider_key_id,
|
||||||
const std::string& key_decryption_key,
|
const std::string& key_decryption_key,
|
||||||
const std::string& key_decryption_key_iv,
|
const std::string& key_decryption_key_iv,
|
||||||
|
video_widevine::License_KeyContainer_SecurityLevel security_level,
|
||||||
std::string* unwrapped_key) {
|
std::string* unwrapped_key) {
|
||||||
// provider keys are only applied on content keys.
|
// 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() &&
|
(provider_key_id >= 1 && provider_key_id <= provider_keys.size() &&
|
||||||
key_type == KeyType::kContentKey);
|
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.
|
// If |provider_key_id| is used and valid, then start by unmasking it.
|
||||||
std::string key = wrapped_key;
|
std::string key = wrapped_key;
|
||||||
if (provider_key_id_valid) {
|
if (provider_key_id_valid) {
|
||||||
|
|||||||
@@ -50,16 +50,18 @@ class LicenseParser {
|
|||||||
const std::string& encrypted,
|
const std::string& encrypted,
|
||||||
std::string* decrypted);
|
std::string* decrypted);
|
||||||
|
|
||||||
// Unwrap key |wrapped_key| using |key_type|, |provider_key_id| and
|
// Unwrap key |wrapped_key| using |key_type|, |provider_key_id|,
|
||||||
// |key_decryption_key|, as necessary. Returns true and
|
// |key_decryption_key| and |security_level|, as necessary. Returns true and
|
||||||
// |unwrapped_content_key| is updated on success, false otherwise.
|
// |unwrapped_content_key| is updated on success, false otherwise.
|
||||||
static bool UnwrapKey(KeyType key_type,
|
static bool UnwrapKey(
|
||||||
const std::string& wrapped_key,
|
KeyType key_type,
|
||||||
const std::vector<ProviderKey>& provider_keys,
|
const std::string& wrapped_key,
|
||||||
size_t provider_key_id,
|
const std::vector<ProviderKey>& provider_keys,
|
||||||
const std::string& key_decryption_key,
|
size_t provider_key_id,
|
||||||
const std::string& key_decryption_key_iv,
|
const std::string& key_decryption_key,
|
||||||
std::string* unwrapped_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.
|
// Creates and returns a InternalKey based on the values provided.
|
||||||
// |level| determines whether decrypt or masked_decrypt is allowed.
|
// |level| determines whether decrypt or masked_decrypt is allowed.
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ InternalKey OdkLicenseParser::ParseInternalKey(
|
|||||||
|
|
||||||
std::string unwrapped_key;
|
std::string unwrapped_key;
|
||||||
if (!UnwrapKey(key_type, wrapped_key, provider_keys, provider_key_id,
|
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.";
|
VLOG(3) << "Failed to decrypt key.";
|
||||||
return InternalKey();
|
return InternalKey();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ InternalKey ProtobufLicenseParser::ParseInternalKey(
|
|||||||
std::string wrapped_key = key.key().substr(0, key_size_without_padding);
|
std::string wrapped_key = key.key().substr(0, key_size_without_padding);
|
||||||
std::string unwrapped_key;
|
std::string unwrapped_key;
|
||||||
if (!UnwrapKey(key_type, wrapped_key, provider_keys, provider_key_id,
|
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.";
|
VLOG(3) << "Failed to decrypt content key.";
|
||||||
return InternalKey();
|
return InternalKey();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user