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:
Hua Wu
2024-04-24 10:03:33 -07:00
parent 6ee87589be
commit 8471679a9f
10 changed files with 184 additions and 22 deletions

View File

@@ -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

View File

@@ -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"],

View File

@@ -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(

View File

@@ -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.";

View File

@@ -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) {

View 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_

View File

@@ -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) {

View File

@@ -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.

View File

@@ -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();
}

View File

@@ -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();
}