Add ODK query func and short-buffer for AEAD
This commit is contained in:
@@ -2,12 +2,13 @@
|
|||||||
|
|
||||||
module(name = "whitebox")
|
module(name = "whitebox")
|
||||||
|
|
||||||
bazel_dep(name = "abseil-cpp", version = "20240722.0.bcr.2")
|
# https://registry.bazel.build/
|
||||||
bazel_dep(name = "boringssl", version = "0.20241209.0")
|
bazel_dep(name = "abseil-cpp", version = "20250127.0")
|
||||||
|
bazel_dep(name = "boringssl", version = "0.20250212.0")
|
||||||
bazel_dep(name = "gflags", version = "2.2.2")
|
bazel_dep(name = "gflags", version = "2.2.2")
|
||||||
bazel_dep(name = "glog", version = "0.7.1")
|
bazel_dep(name = "glog", version = "0.7.1")
|
||||||
bazel_dep(name = "googletest", version = "1.15.2")
|
bazel_dep(name = "googletest", version = "1.16.0")
|
||||||
bazel_dep(name = "protobuf", version = "29.2")
|
bazel_dep(name = "protobuf", version = "29.3")
|
||||||
|
|
||||||
# The ODK library depends on proto files in the "chromium_deps" folder. Since
|
# The ODK library depends on proto files in the "chromium_deps" folder. Since
|
||||||
# this would create a circular dependency, this creates a new module for it.
|
# this would create a circular dependency, this creates a new module for it.
|
||||||
|
|||||||
@@ -283,6 +283,7 @@ cc_library(
|
|||||||
"license_whitebox_entitlement_content_key_test.cc",
|
"license_whitebox_entitlement_content_key_test.cc",
|
||||||
"license_whitebox_generic_crypto_test.cc",
|
"license_whitebox_generic_crypto_test.cc",
|
||||||
"license_whitebox_get_secret_string_test.cc",
|
"license_whitebox_get_secret_string_test.cc",
|
||||||
|
"license_whitebox_get_max_odk_version_test.cc",
|
||||||
"license_whitebox_key_control_block_test.cc",
|
"license_whitebox_key_control_block_test.cc",
|
||||||
"license_whitebox_license_key_mode.cc",
|
"license_whitebox_license_key_mode.cc",
|
||||||
"license_whitebox_masked_decrypt_test.cc",
|
"license_whitebox_masked_decrypt_test.cc",
|
||||||
|
|||||||
@@ -96,6 +96,8 @@ WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
|
|||||||
|
|
||||||
// Decrypts |input_data| and writes the plaintext to |output_data|. |input_data|
|
// Decrypts |input_data| and writes the plaintext to |output_data|. |input_data|
|
||||||
// must have been encrypted using WB_Aead_Encrypt() with the same |whitebox|.
|
// must have been encrypted using WB_Aead_Encrypt() with the same |whitebox|.
|
||||||
|
// |output_data| must be at least as big as |input_data|, this doesn't support
|
||||||
|
// WB_RESULT_BUFFER_TOO_SMALL.
|
||||||
//
|
//
|
||||||
// This must support |input_data| and |output_data| pointing to the same buffer
|
// This must support |input_data| and |output_data| pointing to the same buffer
|
||||||
// (in-place decrypt).
|
// (in-place decrypt).
|
||||||
@@ -111,7 +113,7 @@ WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
|
|||||||
//
|
//
|
||||||
// output_data_size (in/out) : As input, this contains the max number of bytes
|
// output_data_size (in/out) : As input, this contains the max number of bytes
|
||||||
// that can be written to |output_data|. As output, |output_data_size| is set
|
// that can be written to |output_data|. As output, |output_data_size| is set
|
||||||
// to the required size on WB_RESULT_OK and WB_RESULT_BUFFER_TOO_SMALL.
|
// to the required size on WB_RESULT_OK.
|
||||||
//
|
//
|
||||||
// Returns:
|
// Returns:
|
||||||
// WB_RESULT_OK if |input_data| was successfully decrypted.
|
// WB_RESULT_OK if |input_data| was successfully decrypted.
|
||||||
@@ -120,9 +122,6 @@ WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
|
|||||||
// null, if |input_data_size| was invalid, if |output_data| was null, or if
|
// null, if |input_data_size| was invalid, if |output_data| was null, or if
|
||||||
// |output_data_size| was null.
|
// |output_data_size| was null.
|
||||||
//
|
//
|
||||||
// WB_RESULT_BUFFER_TOO_SMALL if |output_data_size| (as input) was less than
|
|
||||||
// the required size.
|
|
||||||
//
|
|
||||||
// WB_RESULT_DATA_VERIFICATION_ERROR if |input_data| failed data verification.
|
// WB_RESULT_DATA_VERIFICATION_ERROR if |input_data| failed data verification.
|
||||||
// The state of |output_data| is undefined.
|
// The state of |output_data| is undefined.
|
||||||
WB_Result WB_Aead_Decrypt(const WB_Aead_Whitebox* whitebox,
|
WB_Result WB_Aead_Decrypt(const WB_Aead_Whitebox* whitebox,
|
||||||
|
|||||||
@@ -214,10 +214,9 @@ TEST_F(AeadWhiteboxDecryptTest, BufferTooSmall) {
|
|||||||
size_t plaintext_size = plaintext_.size() - 1;
|
size_t plaintext_size = plaintext_.size() - 1;
|
||||||
std::vector<uint8_t> plaintext(plaintext_size);
|
std::vector<uint8_t> plaintext(plaintext_size);
|
||||||
|
|
||||||
ASSERT_EQ(WB_Aead_Decrypt(whitebox_, ciphertext_.data(), ciphertext_.size(),
|
ASSERT_NE(WB_Aead_Decrypt(whitebox_, ciphertext_.data(), ciphertext_.size(),
|
||||||
plaintext.data(), &plaintext_size),
|
plaintext.data(), &plaintext_size),
|
||||||
WB_RESULT_BUFFER_TOO_SMALL);
|
WB_RESULT_OK);
|
||||||
ASSERT_EQ(plaintext_size, plaintext_.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AeadWhiteboxDecryptTest, DataVerificationError) {
|
TEST_F(AeadWhiteboxDecryptTest, DataVerificationError) {
|
||||||
|
|||||||
@@ -100,15 +100,6 @@ TEST_F(AeadWhiteboxEncryptTest, InvalidParameterForNullInputData) {
|
|||||||
WB_RESULT_INVALID_PARAMETER);
|
WB_RESULT_INVALID_PARAMETER);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AeadWhiteboxEncryptTest, InvalidParameterForZeroInputSize) {
|
|
||||||
size_t output_size = kDefaultOutputSize;
|
|
||||||
std::vector<uint8_t> output(output_size);
|
|
||||||
|
|
||||||
ASSERT_EQ(
|
|
||||||
WB_Aead_Encrypt(whitebox_, input_.data(), 0, output.data(), &output_size),
|
|
||||||
WB_RESULT_INVALID_PARAMETER);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AeadWhiteboxEncryptTest, InvalidParameterForNullOutputData) {
|
TEST_F(AeadWhiteboxEncryptTest, InvalidParameterForNullOutputData) {
|
||||||
size_t output_size = kDefaultOutputSize;
|
size_t output_size = kDefaultOutputSize;
|
||||||
std::vector<uint8_t> output(output_size);
|
std::vector<uint8_t> output(output_size);
|
||||||
@@ -141,4 +132,15 @@ TEST_F(AeadWhiteboxEncryptTest, BufferTooSmallForSmallOutputBuffer) {
|
|||||||
// only check that |output_size| is larger than |input_.size()|.
|
// only check that |output_size| is larger than |input_.size()|.
|
||||||
ASSERT_GT(output_size, input_.size());
|
ASSERT_GT(output_size, input_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(AeadWhiteboxEncryptTest, BufferTooSmallWithNullArgs) {
|
||||||
|
// Should calculate the required size even if 0 or null buffer arguments.
|
||||||
|
size_t output_size = 0;
|
||||||
|
|
||||||
|
ASSERT_EQ(
|
||||||
|
WB_Aead_Encrypt(whitebox_, nullptr, input_.size(), nullptr, &output_size),
|
||||||
|
WB_RESULT_BUFFER_TOO_SMALL);
|
||||||
|
ASSERT_GT(output_size, input_.size());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -23,14 +23,12 @@
|
|||||||
// defined, we will define non-versioned function names.
|
// defined, we will define non-versioned function names.
|
||||||
// #define WB_VERSION 28
|
// #define WB_VERSION 28
|
||||||
|
|
||||||
#ifdef WB_VERSION
|
|
||||||
// We do this triple-indirection here since the ## operator handles arguments
|
// We do this triple-indirection here since the ## operator handles arguments
|
||||||
// a bit weird and we want to expand the WB_RESULT as a value, not an identifier
|
// a bit weird and we want to expand the |version| as a value, not an identifier
|
||||||
//
|
#define WB_CONCAT_VERSION__(a, b) a ## b
|
||||||
|
#define WB_CONCAT_VERSION_(name, version) WB_CONCAT_VERSION__(name##_v, version)
|
||||||
|
#ifdef WB_VERSION
|
||||||
// WB_CONCAT_VERSION(Foo) -> Foo_v28
|
// WB_CONCAT_VERSION(Foo) -> Foo_v28
|
||||||
# define WB_CONCAT_VERSION__(a, b) a ## b
|
|
||||||
# define WB_CONCAT_VERSION_(name, version) \
|
|
||||||
WB_CONCAT_VERSION__(name ## _v, version)
|
|
||||||
# define WB_CONCAT_VERSION(name) WB_CONCAT_VERSION_(name, WB_VERSION)
|
# define WB_CONCAT_VERSION(name) WB_CONCAT_VERSION_(name, WB_VERSION)
|
||||||
#else
|
#else
|
||||||
# define WB_CONCAT_VERSION(name) name
|
# define WB_CONCAT_VERSION(name) name
|
||||||
@@ -44,6 +42,21 @@ extern "C" {
|
|||||||
typedef struct WB_CONCAT_VERSION(WB_License_Whitebox)
|
typedef struct WB_CONCAT_VERSION(WB_License_Whitebox)
|
||||||
WB_CONCAT_VERSION(WB_License_Whitebox);
|
WB_CONCAT_VERSION(WB_License_Whitebox);
|
||||||
|
|
||||||
|
// Returns the maximum supported version of ODK messages.
|
||||||
|
//
|
||||||
|
// Args:
|
||||||
|
// odk_major_version(out): Where to put the major ODK version that is supported
|
||||||
|
//
|
||||||
|
// odk_minor_version(out): Where to put the minor ODK version that is supported
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// WB_RESULT_OK on success.
|
||||||
|
//
|
||||||
|
// WB_RESULT_INVALID_PARAMETER if either argument was null.
|
||||||
|
WB_Result WB_CONCAT_VERSION(WB_License_GetMaxOdkVersion)(
|
||||||
|
uint16_t* odk_major_version,
|
||||||
|
uint16_t* odk_minor_version);
|
||||||
|
|
||||||
// Creates a new white-box instance using the implementation's internal private
|
// Creates a new white-box instance using the implementation's internal private
|
||||||
// key|. A pointer to the white-box instance will be returned via |whitebox|.
|
// key|. A pointer to the white-box instance will be returned via |whitebox|.
|
||||||
//
|
//
|
||||||
|
|||||||
29
whitebox/api/license_whitebox_get_max_odk_version_test.cc
Normal file
29
whitebox/api/license_whitebox_get_max_odk_version_test.cc
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2025 Google LLC. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "api/license_whitebox_latest.h"
|
||||||
|
#include "odk.h"
|
||||||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
|
||||||
|
TEST(LicenseWhiteboxGetMaxOdkVersionTest, Success) {
|
||||||
|
uint16_t major, minor;
|
||||||
|
ASSERT_EQ(WB_License_GetMaxOdkVersion(&major, &minor), WB_RESULT_OK);
|
||||||
|
EXPECT_GE(major, ODK_FIRST_VERSION);
|
||||||
|
EXPECT_LE(major, ODK_MAJOR_VERSION);
|
||||||
|
if (major == ODK_MAJOR_VERSION) {
|
||||||
|
EXPECT_LE(minor, ODK_MINOR_VERSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LicenseWhiteboxGetMaxOdkVersionTest, NullArguments) {
|
||||||
|
uint16_t major, minor;
|
||||||
|
EXPECT_EQ(WB_License_GetMaxOdkVersion(nullptr, nullptr),
|
||||||
|
WB_RESULT_INVALID_PARAMETER);
|
||||||
|
EXPECT_EQ(WB_License_GetMaxOdkVersion(nullptr, &minor),
|
||||||
|
WB_RESULT_INVALID_PARAMETER);
|
||||||
|
EXPECT_EQ(WB_License_GetMaxOdkVersion(&major, nullptr),
|
||||||
|
WB_RESULT_INVALID_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace widevine
|
||||||
@@ -13,6 +13,13 @@ extern "C" {
|
|||||||
|
|
||||||
typedef WB_CONCAT_VERSION(WB_License_Whitebox) WB_License_Whitebox;
|
typedef WB_CONCAT_VERSION(WB_License_Whitebox) WB_License_Whitebox;
|
||||||
|
|
||||||
|
inline WB_Result WB_License_GetMaxOdkVersion(
|
||||||
|
uint16_t* odk_major_version,
|
||||||
|
uint16_t* odk_minor_version) {
|
||||||
|
return WB_CONCAT_VERSION(WB_License_GetMaxOdkVersion)(odk_major_version,
|
||||||
|
odk_minor_version);
|
||||||
|
}
|
||||||
|
|
||||||
inline WB_Result WB_License_Create(
|
inline WB_Result WB_License_Create(
|
||||||
const uint8_t* whitebox_init_data,
|
const uint8_t* whitebox_init_data,
|
||||||
size_t whitebox_init_data_size,
|
size_t whitebox_init_data_size,
|
||||||
|
|||||||
360
whitebox/api/license_whitebox_wrapper.h
Normal file
360
whitebox/api/license_whitebox_wrapper.h
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
// Copyright 2025 Google LLC. All Rights Reserved.
|
||||||
|
|
||||||
|
#ifndef WHITEBOX_API_LICENSE_WHITEBOX_WRAPPER_H_
|
||||||
|
#define WHITEBOX_API_LICENSE_WHITEBOX_WRAPPER_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "api/license_whitebox.h"
|
||||||
|
#include "api/result.h"
|
||||||
|
|
||||||
|
/// Defines an interface for a wrapper type for interacting with different
|
||||||
|
/// versions of the whitebox. These wrappers should handle changes between
|
||||||
|
/// older API versions and will call into the specific versioned-APIs.
|
||||||
|
///
|
||||||
|
/// Creating an instance of a wrapper is done with the T::Create() method, a
|
||||||
|
/// static method that returns a WB_Result and gives the wrapper instance as
|
||||||
|
/// a smart pointer.
|
||||||
|
///
|
||||||
|
/// For example:
|
||||||
|
/// std::unique_ptr<LicenseWhiteboxWrapper> whitebox;
|
||||||
|
/// auto res = LicenseWhiteboxWrapper_v30::Create(nullptr, 0, &whitebox);
|
||||||
|
/// assert(res == WB_RESULT_OK);
|
||||||
|
/// whitebox->SignLicenseRequest(...);
|
||||||
|
class LicenseWhiteboxWrapper {
|
||||||
|
public:
|
||||||
|
LicenseWhiteboxWrapper() {}
|
||||||
|
LicenseWhiteboxWrapper(const LicenseWhiteboxWrapper&) = delete;
|
||||||
|
LicenseWhiteboxWrapper(LicenseWhiteboxWrapper&&) = delete;
|
||||||
|
virtual ~LicenseWhiteboxWrapper() {}
|
||||||
|
|
||||||
|
LicenseWhiteboxWrapper& operator=(const LicenseWhiteboxWrapper&) = delete;
|
||||||
|
LicenseWhiteboxWrapper& operator=(LicenseWhiteboxWrapper&&) = delete;
|
||||||
|
|
||||||
|
//// Implementations should also define the following static functions.
|
||||||
|
//static void Unmask(const uint8_t* masked_data,
|
||||||
|
// size_t offset,
|
||||||
|
// size_t size,
|
||||||
|
// const uint8_t* secret_string,
|
||||||
|
// size_t secret_string_size,
|
||||||
|
// uint8_t* unmasked_data);
|
||||||
|
//static WB_Result Create(const uint8_t* whitebox_init_data,
|
||||||
|
// size_t whitebox_init_data_size,
|
||||||
|
// std::unique_ptr<LicenseWhiteboxWrapper>* whitebox);
|
||||||
|
//static WB_Result Import(const uint8_t* buffer,
|
||||||
|
// size_t buffer_size,
|
||||||
|
// std::unique_ptr<LicenseWhiteboxWrapper>* whitebox);
|
||||||
|
//static WB_Result SignLicenseRequest_Init();
|
||||||
|
//static WB_Result ProcessLicenseResponse_Init();
|
||||||
|
|
||||||
|
virtual WB_Result ExportKeys(uint8_t* buffer, size_t* buffer_size) = 0;
|
||||||
|
virtual WB_Result SignLicenseRequest(const uint8_t* license_request,
|
||||||
|
size_t license_request_size,
|
||||||
|
uint8_t* signature,
|
||||||
|
size_t* signature_size) = 0;
|
||||||
|
virtual WB_Result ProcessLicenseResponse(WB_LicenseKeyMode license_key_mode,
|
||||||
|
const uint8_t* core_message,
|
||||||
|
size_t core_message_size,
|
||||||
|
const uint8_t* message,
|
||||||
|
size_t message_size,
|
||||||
|
const uint8_t* signature,
|
||||||
|
size_t signature_size,
|
||||||
|
const uint8_t* session_key,
|
||||||
|
size_t session_key_size,
|
||||||
|
size_t provider_key_id,
|
||||||
|
const uint8_t* license_request,
|
||||||
|
size_t license_request_size) = 0;
|
||||||
|
virtual WB_Result LoadEntitledContentKey(const uint8_t* entitlement_key_id,
|
||||||
|
size_t entitlement_key_id_size,
|
||||||
|
const uint8_t* content_key_id,
|
||||||
|
size_t content_key_id_size,
|
||||||
|
const uint8_t* iv,
|
||||||
|
size_t iv_size,
|
||||||
|
const uint8_t* key_data,
|
||||||
|
size_t key_data_size) = 0;
|
||||||
|
virtual WB_Result RemoveEntitledContentKey(const uint8_t* content_key_id,
|
||||||
|
size_t content_key_id_size) = 0;
|
||||||
|
virtual WB_Result QueryKeyStatus(WB_KeyQueryType type,
|
||||||
|
const uint8_t* key_id,
|
||||||
|
size_t key_id_size,
|
||||||
|
WB_KeyStatus* key_status) = 0;
|
||||||
|
virtual WB_Result SignRenewalRequest(const uint8_t* message,
|
||||||
|
size_t message_size,
|
||||||
|
uint8_t* signature,
|
||||||
|
size_t* signature_size) = 0;
|
||||||
|
virtual WB_Result SignPstReport(const uint8_t* message,
|
||||||
|
size_t message_size,
|
||||||
|
uint8_t* signature,
|
||||||
|
size_t* signature_size) = 0;
|
||||||
|
virtual WB_Result VerifyRenewalResponse(const uint8_t* message,
|
||||||
|
size_t message_size,
|
||||||
|
const uint8_t* signature,
|
||||||
|
size_t signature_size) = 0;
|
||||||
|
virtual WB_Result GetSecretString(WB_CipherMode mode,
|
||||||
|
const uint8_t* key_id,
|
||||||
|
size_t key_id_size,
|
||||||
|
uint8_t* secret_string,
|
||||||
|
size_t* secret_string_size) = 0;
|
||||||
|
virtual WB_Result GenericEncrypt(const uint8_t* key_id,
|
||||||
|
size_t key_id_size,
|
||||||
|
const uint8_t* input_data,
|
||||||
|
size_t input_data_size,
|
||||||
|
const uint8_t* iv,
|
||||||
|
size_t iv_size,
|
||||||
|
uint8_t* output_data,
|
||||||
|
size_t* output_data_size) = 0;
|
||||||
|
virtual WB_Result GenericDecrypt(const uint8_t* key_id,
|
||||||
|
size_t key_id_size,
|
||||||
|
const uint8_t* input_data,
|
||||||
|
size_t input_data_size,
|
||||||
|
const uint8_t* iv,
|
||||||
|
size_t iv_size,
|
||||||
|
uint8_t* output_data,
|
||||||
|
size_t* output_data_size) = 0;
|
||||||
|
virtual WB_Result GenericSign(const uint8_t* key_id,
|
||||||
|
size_t key_id_size,
|
||||||
|
const uint8_t* message,
|
||||||
|
size_t message_size,
|
||||||
|
uint8_t* output_data,
|
||||||
|
size_t* output_data_size) = 0;
|
||||||
|
virtual WB_Result GenericVerify(const uint8_t* key_id,
|
||||||
|
size_t key_id_size,
|
||||||
|
const uint8_t* message,
|
||||||
|
size_t message_size,
|
||||||
|
const uint8_t* signature,
|
||||||
|
size_t signature_size) = 0;
|
||||||
|
virtual WB_Result Decrypt(WB_CipherMode mode,
|
||||||
|
const uint8_t* key_id,
|
||||||
|
size_t key_id_size,
|
||||||
|
const uint8_t* input_data,
|
||||||
|
size_t input_data_size,
|
||||||
|
const uint8_t* iv,
|
||||||
|
size_t iv_size,
|
||||||
|
uint8_t* output_data,
|
||||||
|
size_t* output_data_size) = 0;
|
||||||
|
virtual WB_Result MaskedDecrypt(WB_CipherMode mode,
|
||||||
|
const uint8_t* key_id,
|
||||||
|
size_t key_id_size,
|
||||||
|
const uint8_t* input_data,
|
||||||
|
size_t input_data_size,
|
||||||
|
const uint8_t* iv,
|
||||||
|
size_t iv_size,
|
||||||
|
uint8_t* masked_output_data,
|
||||||
|
size_t* masked_output_data_size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WB_DEFINE_DEFAULT_LICENSE_WRAPPER(version) \
|
||||||
|
class WB_CONCAT_VERSION_(LicenseWhiteboxWrapper, version) \
|
||||||
|
: public LicenseWhiteboxWrapper { \
|
||||||
|
public: \
|
||||||
|
using this_type = WB_CONCAT_VERSION_(LicenseWhiteboxWrapper, version); \
|
||||||
|
~WB_CONCAT_VERSION_(LicenseWhiteboxWrapper, version)() override { \
|
||||||
|
WB_CONCAT_VERSION_(WB_License_Delete, version)(whitebox_); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static void Unmask(const uint8_t* masked_data, \
|
||||||
|
size_t offset, \
|
||||||
|
size_t size, \
|
||||||
|
const uint8_t* secret_string, \
|
||||||
|
size_t secret_string_size, \
|
||||||
|
uint8_t* unmasked_data) { \
|
||||||
|
WB_CONCAT_VERSION_(WB_License_Unmask, version)( \
|
||||||
|
masked_data, offset, size, secret_string, secret_string_size, \
|
||||||
|
unmasked_data); \
|
||||||
|
} \
|
||||||
|
static WB_Result Create( \
|
||||||
|
const uint8_t* whitebox_init_data, \
|
||||||
|
size_t whitebox_init_data_size, \
|
||||||
|
std::unique_ptr<LicenseWhiteboxWrapper>* whitebox) { \
|
||||||
|
std::unique_ptr<this_type> wb(new this_type); \
|
||||||
|
const auto result = WB_CONCAT_VERSION_(WB_License_Create, version)( \
|
||||||
|
whitebox_init_data, whitebox_init_data_size, &wb->whitebox_); \
|
||||||
|
*whitebox = std::move(wb); \
|
||||||
|
return result; \
|
||||||
|
} \
|
||||||
|
static WB_Result Import( \
|
||||||
|
const uint8_t* buffer, \
|
||||||
|
size_t buffer_size, \
|
||||||
|
std::unique_ptr<LicenseWhiteboxWrapper>* whitebox) { \
|
||||||
|
std::unique_ptr<this_type> wb(new this_type); \
|
||||||
|
const auto result = WB_CONCAT_VERSION_(WB_License_Import, version)( \
|
||||||
|
buffer, buffer_size, &wb->whitebox_); \
|
||||||
|
*whitebox = std::move(wb); \
|
||||||
|
return result; \
|
||||||
|
} \
|
||||||
|
static WB_Result SignLicenseRequest_Init() { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_SignLicenseRequest_Init, \
|
||||||
|
version)(); \
|
||||||
|
} \
|
||||||
|
static WB_Result ProcessLicenseResponse_Init() { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_ProcessLicenseResponse_Init, \
|
||||||
|
version)(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
WB_Result ExportKeys(uint8_t* buffer, size_t* buffer_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_ExportKeys, version)( \
|
||||||
|
whitebox_, buffer, buffer_size); \
|
||||||
|
} \
|
||||||
|
WB_Result SignLicenseRequest(const uint8_t* license_request, \
|
||||||
|
size_t license_request_size, \
|
||||||
|
uint8_t* signature, \
|
||||||
|
size_t* signature_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_SignLicenseRequest, version)( \
|
||||||
|
whitebox_, license_request, license_request_size, signature, \
|
||||||
|
signature_size); \
|
||||||
|
} \
|
||||||
|
WB_Result ProcessLicenseResponse(WB_LicenseKeyMode license_key_mode, \
|
||||||
|
const uint8_t* core_message, \
|
||||||
|
size_t core_message_size, \
|
||||||
|
const uint8_t* message, \
|
||||||
|
size_t message_size, \
|
||||||
|
const uint8_t* signature, \
|
||||||
|
size_t signature_size, \
|
||||||
|
const uint8_t* session_key, \
|
||||||
|
size_t session_key_size, \
|
||||||
|
size_t provider_key_id, \
|
||||||
|
const uint8_t* license_request, \
|
||||||
|
size_t license_request_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_ProcessLicenseResponse, version)( \
|
||||||
|
whitebox_, license_key_mode, core_message, core_message_size, \
|
||||||
|
message, message_size, signature, signature_size, session_key, \
|
||||||
|
session_key_size, provider_key_id, license_request, \
|
||||||
|
license_request_size); \
|
||||||
|
} \
|
||||||
|
WB_Result LoadEntitledContentKey(const uint8_t* entitlement_key_id, \
|
||||||
|
size_t entitlement_key_id_size, \
|
||||||
|
const uint8_t* content_key_id, \
|
||||||
|
size_t content_key_id_size, \
|
||||||
|
const uint8_t* iv, \
|
||||||
|
size_t iv_size, \
|
||||||
|
const uint8_t* key_data, \
|
||||||
|
size_t key_data_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_LoadEntitledContentKey, version)( \
|
||||||
|
whitebox_, entitlement_key_id, entitlement_key_id_size, \
|
||||||
|
content_key_id, content_key_id_size, iv, iv_size, key_data, \
|
||||||
|
key_data_size); \
|
||||||
|
} \
|
||||||
|
WB_Result RemoveEntitledContentKey(const uint8_t* content_key_id, \
|
||||||
|
size_t content_key_id_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_RemoveEntitledContentKey, version)( \
|
||||||
|
whitebox_, content_key_id, content_key_id_size); \
|
||||||
|
} \
|
||||||
|
WB_Result QueryKeyStatus(WB_KeyQueryType type, \
|
||||||
|
const uint8_t* key_id, \
|
||||||
|
size_t key_id_size, \
|
||||||
|
WB_KeyStatus* key_status) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_QueryKeyStatus, version)( \
|
||||||
|
whitebox_, type, key_id, key_id_size, key_status); \
|
||||||
|
} \
|
||||||
|
WB_Result SignRenewalRequest(const uint8_t* message, \
|
||||||
|
size_t message_size, \
|
||||||
|
uint8_t* signature, \
|
||||||
|
size_t* signature_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_SignRenewalRequest, version)( \
|
||||||
|
whitebox_, message, message_size, signature, signature_size); \
|
||||||
|
} \
|
||||||
|
WB_Result SignPstReport(const uint8_t* message, \
|
||||||
|
size_t message_size, \
|
||||||
|
uint8_t* signature, \
|
||||||
|
size_t* signature_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_SignPstReport, version)( \
|
||||||
|
whitebox_, message, message_size, signature, signature_size); \
|
||||||
|
} \
|
||||||
|
WB_Result VerifyRenewalResponse(const uint8_t* message, \
|
||||||
|
size_t message_size, \
|
||||||
|
const uint8_t* signature, \
|
||||||
|
size_t signature_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_VerifyRenewalResponse, version)( \
|
||||||
|
whitebox_, message, message_size, signature, signature_size); \
|
||||||
|
} \
|
||||||
|
WB_Result GetSecretString(WB_CipherMode mode, \
|
||||||
|
const uint8_t* key_id, \
|
||||||
|
size_t key_id_size, \
|
||||||
|
uint8_t* secret_string, \
|
||||||
|
size_t* secret_string_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_GetSecretString, version)( \
|
||||||
|
whitebox_, mode, key_id, key_id_size, secret_string, \
|
||||||
|
secret_string_size); \
|
||||||
|
} \
|
||||||
|
WB_Result GenericEncrypt(const uint8_t* key_id, \
|
||||||
|
size_t key_id_size, \
|
||||||
|
const uint8_t* input_data, \
|
||||||
|
size_t input_data_size, \
|
||||||
|
const uint8_t* iv, \
|
||||||
|
size_t iv_size, \
|
||||||
|
uint8_t* output_data, \
|
||||||
|
size_t* output_data_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_GenericEncrypt, version)( \
|
||||||
|
whitebox_, key_id, key_id_size, input_data, input_data_size, iv, \
|
||||||
|
iv_size, output_data, output_data_size); \
|
||||||
|
} \
|
||||||
|
WB_Result GenericDecrypt(const uint8_t* key_id, \
|
||||||
|
size_t key_id_size, \
|
||||||
|
const uint8_t* input_data, \
|
||||||
|
size_t input_data_size, \
|
||||||
|
const uint8_t* iv, \
|
||||||
|
size_t iv_size, \
|
||||||
|
uint8_t* output_data, \
|
||||||
|
size_t* output_data_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_GenericDecrypt, version)( \
|
||||||
|
whitebox_, key_id, key_id_size, input_data, input_data_size, iv, \
|
||||||
|
iv_size, output_data, output_data_size); \
|
||||||
|
} \
|
||||||
|
WB_Result GenericSign(const uint8_t* key_id, \
|
||||||
|
size_t key_id_size, \
|
||||||
|
const uint8_t* message, \
|
||||||
|
size_t message_size, \
|
||||||
|
uint8_t* output_data, \
|
||||||
|
size_t* output_data_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_GenericSign, version)( \
|
||||||
|
whitebox_, key_id, key_id_size, message, message_size, output_data, \
|
||||||
|
output_data_size); \
|
||||||
|
} \
|
||||||
|
WB_Result GenericVerify(const uint8_t* key_id, \
|
||||||
|
size_t key_id_size, \
|
||||||
|
const uint8_t* message, \
|
||||||
|
size_t message_size, \
|
||||||
|
const uint8_t* signature, \
|
||||||
|
size_t signature_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_GenericVerify, version)( \
|
||||||
|
whitebox_, key_id, key_id_size, message, message_size, signature, \
|
||||||
|
signature_size); \
|
||||||
|
} \
|
||||||
|
WB_Result Decrypt(WB_CipherMode mode, \
|
||||||
|
const uint8_t* key_id, \
|
||||||
|
size_t key_id_size, \
|
||||||
|
const uint8_t* input_data, \
|
||||||
|
size_t input_data_size, \
|
||||||
|
const uint8_t* iv, \
|
||||||
|
size_t iv_size, \
|
||||||
|
uint8_t* output_data, \
|
||||||
|
size_t* output_data_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_Decrypt, version)( \
|
||||||
|
whitebox_, mode, key_id, key_id_size, input_data, input_data_size, \
|
||||||
|
iv, iv_size, output_data, output_data_size); \
|
||||||
|
} \
|
||||||
|
WB_Result MaskedDecrypt(WB_CipherMode mode, \
|
||||||
|
const uint8_t* key_id, \
|
||||||
|
size_t key_id_size, \
|
||||||
|
const uint8_t* input_data, \
|
||||||
|
size_t input_data_size, \
|
||||||
|
const uint8_t* iv, \
|
||||||
|
size_t iv_size, \
|
||||||
|
uint8_t* masked_output_data, \
|
||||||
|
size_t* masked_output_data_size) override { \
|
||||||
|
return WB_CONCAT_VERSION_(WB_License_Decrypt, version)( \
|
||||||
|
whitebox_, mode, key_id, key_id_size, input_data, input_data_size, \
|
||||||
|
iv, iv_size, masked_output_data, masked_output_data_size); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
WB_CONCAT_VERSION_(LicenseWhiteboxWrapper, version)() {} \
|
||||||
|
WB_CONCAT_VERSION_(WB_License_Whitebox, version) * whitebox_ = nullptr; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WB_VERSION
|
||||||
|
WB_DEFINE_DEFAULT_LICENSE_WRAPPER(WB_VERSION);
|
||||||
|
using LicenseWhiteboxWrapperCurrent = WB_CONCAT_VERSION(LicenseWhiteboxWrapper);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // WHITEBOX_API_LICENSE_WHITEBOX_WRAPPER_H_
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
# Copyright 2025 Google LLC. All Rights Reserved.
|
# Copyright 2025 Google LLC. All Rights Reserved.
|
||||||
module(name = "chromium_deps")
|
module(name = "chromium_deps")
|
||||||
bazel_dep(name = "protobuf", version = "29.2")
|
bazel_dep(name = "protobuf", version = "29.3")
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#ifndef WHITEBOX_INIT_HELPER_H_
|
#ifndef WHITEBOX_INIT_HELPER_H_
|
||||||
#define WHITEBOX_INIT_HELPER_H_
|
#define WHITEBOX_INIT_HELPER_H_
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -13,18 +14,36 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include <api/license_whitebox.h>
|
#include <api/license_whitebox.h>
|
||||||
|
#include <api/license_whitebox_wrapper.h>
|
||||||
|
|
||||||
|
class WhiteboxInitHelperBase {
|
||||||
|
public:
|
||||||
|
WhiteboxInitHelperBase () {}
|
||||||
|
virtual ~WhiteboxInitHelperBase () {}
|
||||||
|
|
||||||
|
virtual void StartThread() = 0;
|
||||||
|
|
||||||
|
/** Blocks the current thread until the sign initialization has finished. */
|
||||||
|
virtual WB_Result EnsureSignReady() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks the current thread until the process initialization has finished.
|
||||||
|
*/
|
||||||
|
virtual WB_Result EnsureProcessReady() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a helper class to initialize the Zimperium whitebox. This spawns
|
* Defines a helper class to initialize the Zimperium whitebox. This spawns
|
||||||
* a background thread to initialize in the background.
|
* a background thread to initialize in the background.
|
||||||
*/
|
*/
|
||||||
template <typename Thread = std::thread,
|
template <typename Wrapper = LicenseWhiteboxWrapperCurrent,
|
||||||
|
typename Thread = std::thread,
|
||||||
typename Mutex = std::mutex,
|
typename Mutex = std::mutex,
|
||||||
typename ConditionVariable =
|
typename ConditionVariable =
|
||||||
typename std::conditional<std::is_same<Mutex, std::mutex>::value,
|
typename std::conditional<std::is_same<Mutex, std::mutex>::value,
|
||||||
std::condition_variable,
|
std::condition_variable,
|
||||||
std::condition_variable_any>::type>
|
std::condition_variable_any>::type>
|
||||||
class WhiteboxInitHelper final {
|
class WhiteboxInitHelper final : public WhiteboxInitHelperBase {
|
||||||
public:
|
public:
|
||||||
enum class State {
|
enum class State {
|
||||||
None,
|
None,
|
||||||
@@ -34,7 +53,7 @@ class WhiteboxInitHelper final {
|
|||||||
};
|
};
|
||||||
|
|
||||||
WhiteboxInitHelper() {}
|
WhiteboxInitHelper() {}
|
||||||
~WhiteboxInitHelper() {
|
~WhiteboxInitHelper() override {
|
||||||
if (thread_)
|
if (thread_)
|
||||||
thread_->join();
|
thread_->join();
|
||||||
}
|
}
|
||||||
@@ -50,7 +69,7 @@ class WhiteboxInitHelper final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Spawns the background thread and starts initializing. */
|
/** Spawns the background thread and starts initializing. */
|
||||||
void StartThread() {
|
void StartThread() override {
|
||||||
if (!thread_) {
|
if (!thread_) {
|
||||||
thread_.reset(
|
thread_.reset(
|
||||||
new Thread(std::bind(&WhiteboxInitHelper::ThreadMain, this)));
|
new Thread(std::bind(&WhiteboxInitHelper::ThreadMain, this)));
|
||||||
@@ -58,10 +77,11 @@ class WhiteboxInitHelper final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Blocks the current thread until the sign initialization has finished. */
|
/** Blocks the current thread until the sign initialization has finished. */
|
||||||
WB_Result EnsureSignReady() {
|
WB_Result EnsureSignReady() override {
|
||||||
|
StartThread();
|
||||||
std::unique_lock<Mutex> lock(mutex_);
|
std::unique_lock<Mutex> lock(mutex_);
|
||||||
while (state_ < State::SignReady) {
|
while (state_ < State::SignReady) {
|
||||||
cond_.wait(lock);
|
cond_.wait_for(lock, std::chrono::seconds(1));
|
||||||
}
|
}
|
||||||
return result_;
|
return result_;
|
||||||
}
|
}
|
||||||
@@ -69,17 +89,18 @@ class WhiteboxInitHelper final {
|
|||||||
/**
|
/**
|
||||||
* Blocks the current thread until the process initialization has finished.
|
* Blocks the current thread until the process initialization has finished.
|
||||||
*/
|
*/
|
||||||
WB_Result EnsureProcessReady() {
|
WB_Result EnsureProcessReady() override {
|
||||||
|
StartThread();
|
||||||
std::unique_lock<Mutex> lock(mutex_);
|
std::unique_lock<Mutex> lock(mutex_);
|
||||||
while (state_ < State::ProcessReady) {
|
while (state_ < State::ProcessReady) {
|
||||||
cond_.wait(lock);
|
cond_.wait_for(lock, std::chrono::seconds(1));
|
||||||
}
|
}
|
||||||
return result_;
|
return result_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ThreadMain() {
|
void ThreadMain() {
|
||||||
auto result = WB_License_SignLicenseRequest_Init();
|
auto result = Wrapper::SignLicenseRequest_Init();
|
||||||
{
|
{
|
||||||
std::unique_lock<Mutex> lock(mutex_);
|
std::unique_lock<Mutex> lock(mutex_);
|
||||||
state_ = result == WB_RESULT_OK ? State::SignReady : State::Error;
|
state_ = result == WB_RESULT_OK ? State::SignReady : State::Error;
|
||||||
@@ -89,7 +110,7 @@ class WhiteboxInitHelper final {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = WB_License_ProcessLicenseResponse_Init();
|
result = Wrapper::ProcessLicenseResponse_Init();
|
||||||
|
|
||||||
std::unique_lock<Mutex> lock(mutex_);
|
std::unique_lock<Mutex> lock(mutex_);
|
||||||
state_ = result == WB_RESULT_OK ? State::ProcessReady : State::Error;
|
state_ = result == WB_RESULT_OK ? State::ProcessReady : State::Error;
|
||||||
|
|||||||
@@ -110,41 +110,44 @@ WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
|
|||||||
size_t input_data_size,
|
size_t input_data_size,
|
||||||
uint8_t* output_data,
|
uint8_t* output_data,
|
||||||
size_t* output_data_size) {
|
size_t* output_data_size) {
|
||||||
if (!whitebox || !input_data || !output_data || !output_data_size) {
|
if (!whitebox || !output_data_size) {
|
||||||
DVLOG(1) << "Invalid parameter: null pointer.";
|
DVLOG(1) << "Invalid parameter: null pointer.";
|
||||||
return WB_RESULT_INVALID_PARAMETER;
|
return WB_RESULT_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input_data_size == 0) {
|
const size_t extra_size = EVP_AEAD_max_overhead(whitebox->algorithm);
|
||||||
DVLOG(1) << "Invalid parameter: array size 0.";
|
const size_t required_size =
|
||||||
|
input_data_size + whitebox->nonce_size + extra_size;
|
||||||
|
if (*output_data_size < required_size) {
|
||||||
|
DVLOG(1) << "Buffer too small: got=" << *output_data_size
|
||||||
|
<< ", needs=" << required_size << ".";
|
||||||
|
*output_data_size = required_size;
|
||||||
|
return WB_RESULT_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
if (!input_data || !output_data) {
|
||||||
|
DVLOG(1) << "Invalid parameter: null pointer.";
|
||||||
return WB_RESULT_INVALID_PARAMETER;
|
return WB_RESULT_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> nonce(whitebox->nonce_size);
|
std::vector<uint8_t> nonce(whitebox->nonce_size);
|
||||||
RAND_bytes(nonce.data(), nonce.size());
|
RAND_bytes(nonce.data(), nonce.size());
|
||||||
|
|
||||||
std::vector<uint8_t> output(input_data_size +
|
// This should support in-place seal:
|
||||||
EVP_AEAD_max_overhead(whitebox->algorithm));
|
// https://boringssl.googlesource.com/boringssl/+/refs/heads/master/include/openssl/aead.h#84
|
||||||
size_t sealed_size;
|
size_t sealed_size;
|
||||||
CHECK_EQ(EVP_AEAD_CTX_seal(&whitebox->context, output.data(), &sealed_size,
|
CHECK_EQ(EVP_AEAD_CTX_seal(&whitebox->context, output_data, &sealed_size,
|
||||||
output.size(), nonce.data(), nonce.size(),
|
*output_data_size, nonce.data(), nonce.size(),
|
||||||
input_data, input_data_size, nullptr, 0),
|
input_data, input_data_size, nullptr, 0),
|
||||||
kAeadSuccess);
|
kAeadSuccess);
|
||||||
output.resize(sealed_size);
|
|
||||||
|
|
||||||
// At this point, |output| will have the encrypted data and authentication
|
// At this point, |output_data| will have the encrypted data and
|
||||||
// tag, but in order to decrypt later, we will need the nonce, so append the
|
// authentication tag, but in order to decrypt later, we will need the nonce,
|
||||||
// nonce to the output.
|
// so append the nonce to the output.
|
||||||
output.insert(output.end(), nonce.begin(), nonce.end());
|
CHECK_LT(sealed_size, *output_data_size);
|
||||||
|
CHECK(widevine::MemCopy(nonce.data(), nonce.size(), output_data + sealed_size,
|
||||||
|
*output_data_size - sealed_size));
|
||||||
|
|
||||||
if (!widevine::MemCopy(output.data(), output.size(), output_data,
|
*output_data_size = sealed_size + nonce.size();
|
||||||
*output_data_size)) {
|
|
||||||
DVLOG(1) << "Buffer too small: output needs " << output.size() << ".";
|
|
||||||
*output_data_size = output.size();
|
|
||||||
return WB_RESULT_BUFFER_TOO_SMALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*output_data_size = output.size();
|
|
||||||
return WB_RESULT_OK;
|
return WB_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,32 +187,16 @@ WB_Result WB_Aead_Decrypt(const WB_Aead_Whitebox* whitebox,
|
|||||||
const uint8_t* nonce_start = payload_start + payload_size;
|
const uint8_t* nonce_start = payload_start + payload_size;
|
||||||
const size_t nonce_size = whitebox->nonce_size;
|
const size_t nonce_size = whitebox->nonce_size;
|
||||||
|
|
||||||
// Remember, the plaintext will be smaller than the payload, but we are going
|
// Since |*output_data_size| is passed by-value, it is a copy and will not
|
||||||
// to start with the payload size as it is our best estimate and will scale it
|
// cause a problem when it modifies |*output_data_size|.
|
||||||
// down when we have the final size.
|
// This should support in-place open:
|
||||||
std::vector<uint8_t> plaintext(payload_size);
|
// https://boringssl.googlesource.com/boringssl/+/refs/heads/master/include/openssl/aead.h#84
|
||||||
size_t plaintext_size;
|
|
||||||
|
|
||||||
const int result = EVP_AEAD_CTX_open(
|
const int result = EVP_AEAD_CTX_open(
|
||||||
&whitebox->context, plaintext.data(), &plaintext_size, plaintext.size(),
|
&whitebox->context, output_data, output_data_size, *output_data_size,
|
||||||
nonce_start, nonce_size, payload_start, payload_size, nullptr, 0);
|
nonce_start, nonce_size, payload_start, payload_size, nullptr, 0);
|
||||||
|
|
||||||
if (result != kAeadSuccess) {
|
if (result != kAeadSuccess) {
|
||||||
DVLOG(1) << "Data verification error: failed to verify input data.";
|
DVLOG(1) << "Data verification error: failed to verify input data";
|
||||||
return WB_RESULT_DATA_VERIFICATION_ERROR;
|
return WB_RESULT_DATA_VERIFICATION_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Know that EVP_AEAD_CTX_open() has opened the payload, we know the actual
|
|
||||||
// plaintext size and can now shrink the vector to the correct size.
|
|
||||||
plaintext.resize(plaintext_size);
|
|
||||||
|
|
||||||
if (!widevine::MemCopy(plaintext.data(), plaintext.size(), output_data,
|
|
||||||
*output_data_size)) {
|
|
||||||
DVLOG(1) << "Buffer too small: output needs " << plaintext.size() << ".";
|
|
||||||
*output_data_size = plaintext.size();
|
|
||||||
return WB_RESULT_BUFFER_TOO_SMALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*output_data_size = plaintext.size();
|
|
||||||
return WB_RESULT_OK;
|
return WB_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,6 +110,11 @@ std::string MakeString(const uint8_t* data, size_t size) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_IMPORT_EXPORT
|
||||||
|
# ifndef WB_VERSION
|
||||||
|
# error Must set WB_VERSION with export
|
||||||
|
# endif
|
||||||
|
|
||||||
struct WB_License_ExportedData_Key {
|
struct WB_License_ExportedData_Key {
|
||||||
std::array<uint8_t, 16> key_id;
|
std::array<uint8_t, 16> key_id;
|
||||||
uint8_t key_id_size;
|
uint8_t key_id_size;
|
||||||
@@ -124,8 +129,7 @@ struct WB_License_ExportedData {
|
|||||||
size_t num_generic_keys;
|
size_t num_generic_keys;
|
||||||
WB_License_ExportedData_Key keys[0];
|
WB_License_ExportedData_Key keys[0];
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
constexpr const uint8_t kExportedVersion = 1;
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -348,6 +352,18 @@ std::vector<widevine::LicenseParser::ProviderKey> CreateProviderKeys(
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
WB_Result WB_CONCAT_VERSION(WB_License_GetMaxOdkVersion)(
|
||||||
|
uint16_t* odk_major_version,
|
||||||
|
uint16_t* odk_minor_version) {
|
||||||
|
if (!odk_major_version || !odk_minor_version) {
|
||||||
|
DVLOG(1) << "Invalid parameter: null pointer.";
|
||||||
|
return WB_RESULT_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
*odk_major_version = ODK_MAJOR_VERSION;
|
||||||
|
*odk_minor_version = ODK_MINOR_VERSION;
|
||||||
|
return WB_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
WB_Result WB_CONCAT_VERSION(WB_License_Create)(
|
WB_Result WB_CONCAT_VERSION(WB_License_Create)(
|
||||||
const uint8_t* whitebox_init_data,
|
const uint8_t* whitebox_init_data,
|
||||||
size_t whitebox_init_data_size,
|
size_t whitebox_init_data_size,
|
||||||
@@ -406,7 +422,7 @@ WB_Result WB_CONCAT_VERSION(WB_License_Import)(
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* info = reinterpret_cast<const WB_License_ExportedData*>(buffer);
|
auto* info = reinterpret_cast<const WB_License_ExportedData*>(buffer);
|
||||||
if (info->version != kExportedVersion) {
|
if (info->version != WB_VERSION) {
|
||||||
DVLOG(1) << "Unsupported version of exported data.";
|
DVLOG(1) << "Unsupported version of exported data.";
|
||||||
return WB_RESULT_INVALID_PARAMETER;
|
return WB_RESULT_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
@@ -483,7 +499,7 @@ WB_Result WB_CONCAT_VERSION(WB_License_ExportKeys)(
|
|||||||
if (info->has_renewal) {
|
if (info->has_renewal) {
|
||||||
info->renewal_client = whitebox->renewal_key->client;
|
info->renewal_client = whitebox->renewal_key->client;
|
||||||
}
|
}
|
||||||
info->version = kExportedVersion;
|
info->version = WB_VERSION;
|
||||||
info->num_content_keys = whitebox->content_keys.size();
|
info->num_content_keys = whitebox->content_keys.size();
|
||||||
info->num_entitlement_keys = whitebox->entitlement_keys.size();
|
info->num_entitlement_keys = whitebox->entitlement_keys.size();
|
||||||
info->num_generic_keys = whitebox->generic_keys.size();
|
info->num_generic_keys = whitebox->generic_keys.size();
|
||||||
|
|||||||
@@ -71,7 +71,11 @@ bool HasEncryptedKeyControlBlock(const ODKContext& context) {
|
|||||||
size_t encrypted_count = 0;
|
size_t encrypted_count = 0;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < context.license.key_array_length; i++) {
|
for (uint32_t i = 0; i < context.license.key_array_length; i++) {
|
||||||
|
#if ODK_MAJOR_VERSION >= 20
|
||||||
|
const OEMCrypto_KeyObjectV2& key = context.license.key_array[i];
|
||||||
|
#else
|
||||||
const OEMCrypto_KeyObject& key = context.license.key_array[i];
|
const OEMCrypto_KeyObject& key = context.license.key_array[i];
|
||||||
|
#endif
|
||||||
|
|
||||||
if (key.key_control_iv.length > 0) {
|
if (key.key_control_iv.length > 0) {
|
||||||
encrypted_count++;
|
encrypted_count++;
|
||||||
|
|||||||
@@ -86,7 +86,11 @@ WB_Result OdkLicenseParser::Parse(const std::string& decryption_key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < odk_context.license.key_array_length; ++i) {
|
for (size_t i = 0; i < odk_context.license.key_array_length; ++i) {
|
||||||
|
#if ODK_MAJOR_VERSION >= 20
|
||||||
|
const OEMCrypto_KeyObjectV2& key = odk_context.license.key_array[i];
|
||||||
|
#else
|
||||||
const OEMCrypto_KeyObject& key = odk_context.license.key_array[i];
|
const OEMCrypto_KeyObject& key = odk_context.license.key_array[i];
|
||||||
|
#endif
|
||||||
const std::string key_id = ExtractItem(key.key_id, message);
|
const std::string key_id = ExtractItem(key.key_id, message);
|
||||||
|
|
||||||
// If there is no key id, we can't add an invalid entry since there would
|
// If there is no key id, we can't add an invalid entry since there would
|
||||||
@@ -198,7 +202,11 @@ InternalKey OdkLicenseParser::ParseInternalKey(
|
|||||||
KeyType key_type,
|
KeyType key_type,
|
||||||
const std::string& decryption_key,
|
const std::string& decryption_key,
|
||||||
const std::string& message,
|
const std::string& message,
|
||||||
|
#if ODK_MAJOR_VERSION >= 20
|
||||||
|
const OEMCrypto_KeyObjectV2& key,
|
||||||
|
#else
|
||||||
const OEMCrypto_KeyObject& key,
|
const OEMCrypto_KeyObject& key,
|
||||||
|
#endif
|
||||||
const std::vector<ProviderKey>& provider_keys,
|
const std::vector<ProviderKey>& provider_keys,
|
||||||
size_t provider_key_id) const {
|
size_t provider_key_id) const {
|
||||||
// This should have been verified before calling the parser.
|
// This should have been verified before calling the parser.
|
||||||
|
|||||||
@@ -32,7 +32,11 @@ class OdkLicenseParser : public LicenseParser {
|
|||||||
InternalKey ParseInternalKey(KeyType key_type,
|
InternalKey ParseInternalKey(KeyType key_type,
|
||||||
const std::string& decryption_key,
|
const std::string& decryption_key,
|
||||||
const std::string& message,
|
const std::string& message,
|
||||||
|
#if ODK_MAJOR_VERSION >= 20
|
||||||
|
const OEMCrypto_KeyObjectV2& key,
|
||||||
|
#else
|
||||||
const OEMCrypto_KeyObject& key,
|
const OEMCrypto_KeyObject& key,
|
||||||
|
#endif
|
||||||
const std::vector<ProviderKey>& provider_keys,
|
const std::vector<ProviderKey>& provider_keys,
|
||||||
size_t provider_key_id) const;
|
size_t provider_key_id) const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user