Update partner repo

This adds:
- Requires WB_RESULT_NOT_IMPLEMENTED for masked in CE
- WB_License_RemoveEntitledContentKey
- WB_License_Generic* methods
This commit is contained in:
Jacob Trimble
2022-11-16 11:37:39 -08:00
parent 791eafa4bc
commit 66820d41c5
30 changed files with 2326 additions and 602 deletions

View File

@@ -56,9 +56,9 @@ git_repository(
http_archive(
name = "zlib",
build_file = "@com_google_protobuf//:third_party/zlib.BUILD",
sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1",
strip_prefix = "zlib-1.2.11",
urls = ["https://zlib.net/zlib-1.2.11.tar.gz"],
sha256 = "b3a24de97a8fdbc835b9833169501030b8977031bcb54b3b3ac13740f846ab30",
strip_prefix = "zlib-1.2.13",
urls = ["https://zlib.net/zlib-1.2.13.tar.gz"],
)
# ODK

View File

@@ -11,11 +11,12 @@ cc_library(
}) + select({
"//:is_ce": [
"ALWAYS_DECRYPT_TO_CLEAR",
"HAS_GENERIC_CRYPTO",
"HAS_SIGN_PST_REPORT",
],
"//:is_old_api": [],
"//:is_old_vmpra": [],
"//conditions:default": [
"//conditions:default": [ # Chrome
# Comment out HAS_PROVIDER_KEYS temporarily
# "HAS_PROVIDER_KEYS",
],
@@ -160,6 +161,7 @@ cc_library(
"golden_data.h",
],
deps = [
":license_whitebox",
":shared_settings",
":test_key_types",
"//chromium_deps/cdm/protos:license_protocol_proto",
@@ -258,6 +260,7 @@ cc_library(
"license_whitebox_create_test.cc",
"license_whitebox_decrypt_test.cc",
"license_whitebox_entitlement_content_key_test.cc",
"license_whitebox_generic_crypto_test.cc",
"license_whitebox_get_secret_string_test.cc",
"license_whitebox_key_control_block_test.cc",
"license_whitebox_license_key_mode.cc",

View File

@@ -2,6 +2,8 @@
#include "api/golden_data.h"
#include "api/license_whitebox.h"
namespace widevine {
namespace {
@@ -134,6 +136,70 @@ GoldenData::GoldenData() {
0xc9, 0xfc, 0x7b, 0x7d, 0x00, 0xf8, 0x75, 0xef,
0xde, 0xd2, 0xd9, 0xdd, 0x8c, 0xcd, 0x20, 0x49
};
generic_.plaintext = {
'T', 'h', 'i', 'r', 't', 'y', '-', 't',
'w', 'o', ' ', 'b', 'y', 't', 'e', 's',
' ', 'o', 'f', ' ', 'r', 'a', 'n', 'd',
'o', 'm', ' ', 'd', 'a', 't', 'a', '.',
};
generic_.iv = {
0xad, 0x40, 0xb9, 0xeb, 0x61, 0x2e, 0x55, 0xee,
0x12, 0x88, 0x62, 0xfe, 0x13, 0xc8, 0xec, 0x56,
};
// Generated with:
// openssl aes-128-cbc -e -in data.text
// -K 69b6db52866148a169a261908397bbb6
// -iv ad40b9eb612e55ee128862fe13c8ec56 | xxd -i
generic_.encrypted = {
0x42, 0xcf, 0x7f, 0xf0, 0xae, 0x8c, 0x44, 0xa5,
0xda, 0x95, 0xa0, 0x05, 0x8c, 0xbd, 0xb9, 0x15,
0x2f, 0xbd, 0x09, 0xe0, 0x5e, 0x7e, 0x91, 0x19,
0x36, 0x11, 0x1c, 0xe3, 0xb5, 0xc6, 0xfd, 0xa0,
};
// Generated with:
// cat data.text |
// openssl dgst -sha256
// -hmac 569c4ba12b3e7834d2a6573cbc8a8d73ce8d240d1ae25c2cdb1b6cd5da16cf01
// | xxd -i
generic_.signature = {
0x20, 0x63, 0xf9, 0x6b, 0xbb, 0x6a, 0xe6, 0x75,
0x5e, 0x24, 0x5e, 0x45, 0xab, 0xda, 0x4a, 0xf1,
0xbd, 0x99, 0x28, 0x27, 0x90, 0x83, 0xd6, 0x1b,
0xef, 0x40, 0xad, 0x05, 0x2c, 0x1c, 0x05, 0x36,
};
generic_.encrypt_decrypt_key.id = GetFreeId();
generic_.encrypt_decrypt_key.kcb_flags =
WB_KCB_FLAGS_ALLOW_DECRYPT | WB_KCB_FLAGS_ALLOW_ENCRYPT;
generic_.encrypt_decrypt_key.key_size = 16u;
generic_.encrypt_decrypt_key.key = {
0x69, 0xb6, 0xdb, 0x52, 0x86, 0x61, 0x48, 0xa1,
0x69, 0xa2, 0x61, 0x90, 0x83, 0x97, 0xbb, 0xb6,
};
generic_.encrypt_key = generic_.encrypt_decrypt_key;
generic_.encrypt_key.id = GetFreeId();
generic_.encrypt_key.kcb_flags = WB_KCB_FLAGS_ALLOW_ENCRYPT;
generic_.decrypt_key = generic_.encrypt_decrypt_key;
generic_.decrypt_key.id = GetFreeId();
generic_.decrypt_key.kcb_flags = WB_KCB_FLAGS_ALLOW_DECRYPT;
generic_.sign_verify_key.id = GetFreeId();
generic_.sign_verify_key.kcb_flags =
WB_KCB_FLAGS_ALLOW_SIGN | WB_KCB_FLAGS_ALLOW_VERIFY;
generic_.sign_verify_key.key_size = 32u;
generic_.sign_verify_key.key = {
0x56, 0x9c, 0x4b, 0xa1, 0x2b, 0x3e, 0x78, 0x34,
0xd2, 0xa6, 0x57, 0x3c, 0xbc, 0x8a, 0x8d, 0x73,
0xce, 0x8d, 0x24, 0x0d, 0x1a, 0xe2, 0x5c, 0x2c,
0xdb, 0x1b, 0x6c, 0xd5, 0xda, 0x16, 0xcf, 0x01,
};
generic_.sign_key = generic_.sign_verify_key;
generic_.sign_key.id = GetFreeId();
generic_.sign_key.kcb_flags = WB_KCB_FLAGS_ALLOW_SIGN;
generic_.verify_key = generic_.sign_verify_key;
generic_.verify_key.id = GetFreeId();
generic_.verify_key.kcb_flags = WB_KCB_FLAGS_ALLOW_VERIFY;
}
KeyId GoldenData::GetFreeId() {

View File

@@ -43,6 +43,25 @@ class GoldenData {
EntitlementKeyData entitlement_key;
};
struct GenericContent {
std::vector<uint8_t> plaintext;
// |plaintext| encrypted with |encryption_key|
std::vector<uint8_t> encrypted;
// |plaintext| signed with |signing_key|
std::vector<uint8_t> signature;
// IV used to encrypt the plaintext.
AesIv iv;
// All these keys have the same key value but different key usage and key ID
GenericKeyData encrypt_decrypt_key;
GenericKeyData decrypt_key;
GenericKeyData encrypt_key;
GenericKeyData sign_verify_key;
GenericKeyData sign_key;
GenericKeyData verify_key;
};
GoldenData();
@@ -52,12 +71,15 @@ class GoldenData {
const EntitlementContent& EntitlementContent() const { return entitlement_; }
const GenericContent& GenericContent() const { return generic_; }
KeyId GetFreeId();
private:
Content cbc_content_;
Content ctr_content_;
struct EntitlementContent entitlement_;
struct GenericContent generic_;
uint8_t next_id_ = 0;
};

View File

@@ -23,8 +23,20 @@ typedef enum {
typedef enum {
WB_KEY_QUERY_TYPE_SIGNING_KEY,
WB_KEY_QUERY_TYPE_CONTENT_KEY,
WB_KEY_QUERY_TYPE_GENERIC_KEY,
} WB_KeyQueryType;
typedef enum {
WB_KCB_FLAGS_ALLOW_ENCRYPT = (1u << 8),
WB_KCB_FLAGS_ALLOW_DECRYPT = (1u << 7),
WB_KCB_FLAGS_ALLOW_SIGN = (1u << 6),
WB_KCB_FLAGS_ALLOW_VERIFY = (1u << 5),
WB_KCB_FLAGS_GENERIC_MASK = 0x1e0,
WB_KCB_FLAGS_SECURITY_LEVEL_SHIFT = 26,
WB_KCB_FLAGS_SECURITY_LEVEL_MASK = 0x3 << WB_KCB_FLAGS_SECURITY_LEVEL_SHIFT,
} WB_KcbFlags;
typedef enum {
// The key was found in the license but there was something wrong it and could
// not be loaded.
@@ -124,7 +136,7 @@ WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox,
//
// Extracts and loads content and signing keys for use. Any content keys that
// exceed the security levels permitted by the instance, will be thrown away,
// but the key ids are retained (see WB_RESULT_INSUFFICIENT_SECURITY_LEVEL). All
// but the key ids are retained (see WB_RESULT_INSUFFICIENT_PERMISSIONS ). All
// non-content keys and non-signing keys will be thrown away.
//
// This function can only be called once per white-box instance. To parse a new
@@ -252,6 +264,27 @@ WB_Result WB_License_LoadEntitledContentKey(WB_License_Whitebox* whitebox,
const uint8_t* key_data,
size_t key_data_size);
// Removes a content key that was previously loaded from an entitlement key.
//
// Args:
// whitebox (in) : An initialized white-box instance.
//
// content_key_id (in) : The ID of the content key.
//
// content_key_id_size (in) : The number of bytes in |content_key_id|.
//
// Returns:
// WB_RESULT_OK if the key was loaded successfully.
//
// WB_INVALID_PARAMETER if any of the pointers are null.
//
// WB_RESULT_KEY_UNAVAILABLE if the requested key was not added.
//
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
WB_Result WB_License_RemoveEntitledContentKey(WB_License_Whitebox* whitebox,
const uint8_t* content_key_id,
size_t content_key_id_size);
// Queries the white-box to know whether or not the white-box loaded a specific
// key and to know what operations can be performed with that key.
//
@@ -427,7 +460,7 @@ WB_Result WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox,
// if |key_id| was null, if |key_id_size| was zero, if |secret_string| was
// null, or if |secret_string_size| was null.
//
// WB_RESULT_INSUFFICIENT_SECURITY_LEVEL if |key_id| referred to a key from
// WB_RESULT_INSUFFICIENT_PERMISSIONS if |key_id| referred to a key from
// the license, but the |whitebox| was not allowed to use it.
//
// WB_RESULT_KEY_UNAVAILABLE if |key_id| did not match a content key from the
@@ -444,6 +477,222 @@ WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox,
uint8_t* secret_string,
size_t* secret_string_size);
// Performs a generic crypto "encrypt" operation to encrypt |input_data| and
// places the result in |output_data|.
//
// This must support |input_data| and |output_data| pointing to the same buffer
// (in-place operation).
//
// Args:
// whitebox (in) : The white-box containing the keys needed to decrypt
// |input_data|.
//
// key_id (in) : The identifier for which key in |whitebox| to use to decrypt
// |input_data|.
//
// key_id_size (in) : The number of bytes in |key_id|.
//
// input_data (in) : The ciphertext.
//
// input_data_size (in) : The number of bytes in |input_data|.
//
// iv(in) This is the IV.
//
// iv_size (in) : The number of bytes in |iv|.
//
// output_data (out) : The output parameter for the output.
//
// 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
// to the required size on WB_RESULT_OK and WB_RESULT_BUFFER_TOO_SMALL.
//
// Returns:
// WB_RESULT_OK if |input_data| was successfully decrypted.
//
// WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |mode| was invalid,
// if |key_id| was null, if |key_id_size| was zero, if |input_data| was null,
// if |input_data_size| was invalid, if |iv| was null, if |iv_size| was
// invalid, if |output_data| was null, or if |output_data_size| was null.
//
// WB_RESULT_KEY_UNAVAILABLE if |key_id| did not match a generic key from the
// loaded license.
//
// WB_RESULT_BUFFER_TOO_SMALL if |output_data_size| (as input) was less than
// the required size.
//
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
//
// WB_RESULT_INVALID_SIGNATURE if the |mode| is Verify and the calculated
// signature doesn't match the value given in |output_data|.
//
// WB_RESULT_INSUFFICIENT_PERMISSIONS if the key doesn't have the correct
// permission bit sets in the KCB to allow encrypt.
WB_Result WB_License_GenericEncrypt(const WB_License_Whitebox* whitebox,
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);
// Performs a generic crypto "decrypt" operation to decrypt |input_data| and
// places the result in |output_data|.
//
// This must support |input_data| and |output_data| pointing to the same buffer
// (in-place operation).
//
// Args:
// whitebox (in) : The white-box containing the keys needed to decrypt
// |input_data|.
//
// key_id (in) : The identifier for which key in |whitebox| to use to decrypt
// |input_data|.
//
// key_id_size (in) : The number of bytes in |key_id|.
//
// input_data (in) : The ciphertext.
//
// input_data_size (in) : The number of bytes in |input_data|.
//
// iv(in) This is the IV.
//
// iv_size (in) : The number of bytes in |iv|.
//
// output_data (out) : The output parameter for the output.
//
// 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
// to the required size on WB_RESULT_OK and WB_RESULT_BUFFER_TOO_SMALL.
//
// Returns:
// WB_RESULT_OK if |input_data| was successfully decrypted.
//
// WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |mode| was invalid,
// if |key_id| was null, if |key_id_size| was zero, if |input_data| was null,
// if |input_data_size| was invalid, if |iv| was null, if |iv_size| was
// invalid, if |output_data| was null, or if |output_data_size| was null.
//
// WB_RESULT_KEY_UNAVAILABLE if |key_id| did not match a generic key from the
// loaded license.
//
// WB_RESULT_BUFFER_TOO_SMALL if |output_data_size| (as input) was less than
// the required size.
//
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
//
// WB_RESULT_INVALID_SIGNATURE if the |mode| is Verify and the calculated
// signature doesn't match the value given in |output_data|.
//
// WB_RESULT_INSUFFICIENT_PERMISSIONS if the key doesn't have the correct
// permission bit sets in the KCB to allow decrypt.
WB_Result WB_License_GenericDecrypt(const WB_License_Whitebox* whitebox,
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);
// Performs a generic crypto "sign" operation that takes the given message in
// |input_data| and places the signature in |output_data|.
//
// Args:
// whitebox (in) : The white-box containing the keys needed to decrypt
// |input_data|.
//
// mode (in) : The type of generic crypto operation to perform.
//
// key_id (in) : The identifier for which key in |whitebox| to use to decrypt
// |input_data|.
//
// key_id_size (in) : The number of bytes in |key_id|.
//
// message (in) : The input message.
//
// message_data_size (in) : The number of bytes in |message|.
//
// output_data (out) : The output parameter for the plaintext.
//
// 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
// to the required size on WB_RESULT_OK and WB_RESULT_BUFFER_TOO_SMALL.
//
// Returns:
// WB_RESULT_OK if |input_data| was successfully decrypted.
//
// WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |mode| was invalid,
// if |key_id| was null, if |key_id_size| was zero, if |input_data| was null,
// if |input_data_size| was invalid, if |iv| was null, if |iv_size| was
// invalid, if |output_data| was null, or if |output_data_size| was null.
//
// WB_RESULT_KEY_UNAVAILABLE if |key_id| did not match a generic key from the
// loaded license.
//
// WB_RESULT_BUFFER_TOO_SMALL if |message_size| (as input) was less than
// the required size.
//
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
//
// WB_RESULT_INSUFFICIENT_PERMISSIONS if the key doesn't have the correct
// permission bit sets in the KCB to allow sign.
WB_Result WB_License_GenericSign(const WB_License_Whitebox* whitebox,
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);
// Performs a generic crypto "verify" operation that takes |message| and
// verifies the signature matches |signature|.
//
// Args:
// whitebox (in) : The white-box containing the keys needed to decrypt
// |input_data|.
//
// key_id (in) : The identifier for which key in |whitebox| to use to decrypt
// |input_data|.
//
// key_id_size (in) : The number of bytes in |key_id|.
//
// message (in) : The input message.
//
// message_size (in) : The number of bytes in |message|.
//
// signature (in) : The input signature to verify.
//
// signature_size (in) : The number of bytes in |signature|.
//
// Returns:
// WB_RESULT_OK if |input_data| was successfully decrypted.
//
// WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |mode| was invalid,
// if |key_id| was null, if |key_id_size| was zero, if |input_data| was null,
// if |input_data_size| was invalid, if |iv| was null, if |iv_size| was
// invalid, if |output_data| was null, or if |output_data_size| was null.
//
// WB_RESULT_KEY_UNAVAILABLE if |key_id| did not match a generic key from the
// loaded license.
//
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
//
// WB_RESULT_INVALID_SIGNATURE if the |mode| is Verify and the calculated
// signature doesn't match the value given in |output_data|.
//
// WB_RESULT_INSUFFICIENT_PERMISSIONS if the key doesn't have the correct
// permission bit sets in the KCB to allow verify.
WB_Result WB_License_GenericVerify(const WB_License_Whitebox* whitebox,
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);
// Decrypts |input_data| and writes the plaintext to |output_data|.
//
// This must support |input_data| and |output_data| pointing to the same buffer
@@ -485,7 +734,7 @@ WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox,
// if |input_data_size| was invalid, if |iv| was null, if |iv_size| was
// invalid, if |output_data| was null, or if |output_data_size| was null.
//
// WB_RESULT_INSUFFICIENT_SECURITY_LEVEL if |key_id| referred to a key from
// WB_RESULT_INSUFFICIENT_PERMISSIONS if |key_id| referred to a key from
// the license, but the |whitebox| was not allowed to use it.
//
// WB_RESULT_KEY_UNAVAILABLE if |key_id| did not match a content key from the
@@ -552,7 +801,7 @@ WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox,
// invalid, if |masked_output_data| was null, or if |masked_output_data_size|
// was null.
//
// WB_RESULT_INSUFFICIENT_SECURITY_LEVEL if |key_id| referred to a key from
// WB_RESULT_INSUFFICIENT_PERMISSIONS if |key_id| referred to a key from
// the license, but the |whitebox| was not allowed to use it.
//
// WB_RESULT_KEY_UNAVAILABLE if |key_id| did not match a content key from the

View File

@@ -109,6 +109,7 @@ TEST_P(LicenseWhiteboxDecryptBenchmark, DecryptCTRThroughput) {
PrettyPrint("License Decrypt CTR Throughput", throughput, ciphertext_.size());
}
#ifndef ALWAYS_DECRYPT_TO_CLEAR
TEST_P(LicenseWhiteboxDecryptBenchmark, MaskedDecryptCBCThroughput) {
std::vector<uint8_t> mask(kMaskSize);
size_t mask_size = mask.size();
@@ -172,6 +173,7 @@ TEST_P(LicenseWhiteboxDecryptBenchmark, MaskedDecryptCTRThroughput) {
PrettyPrint("License Masked Decrypt CTR Throughput", throughput,
ciphertext_.size());
}
#endif
// The first value is the number of blocks. Each block is 16 bytes.
INSTANTIATE_TEST_SUITE_P(

View File

@@ -497,7 +497,7 @@ TEST_P(LicenseWhiteboxDecryptTest,
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(),
plaintext_.data(), &plaintext_size_),
WB_RESULT_INSUFFICIENT_SECURITY_LEVEL);
WB_RESULT_INSUFFICIENT_PERMISSIONS);
}
TEST_P(LicenseWhiteboxDecryptTest, InsufficientSecurityLevelForDecodeKey) {
@@ -510,7 +510,7 @@ TEST_P(LicenseWhiteboxDecryptTest, InsufficientSecurityLevelForDecodeKey) {
#ifdef ALWAYS_DECRYPT_TO_CLEAR
const auto expected = WB_RESULT_OK;
#else
const auto expected = WB_RESULT_INSUFFICIENT_SECURITY_LEVEL;
const auto expected = WB_RESULT_INSUFFICIENT_PERMISSIONS;
#endif
ASSERT_EQ(WB_License_Decrypt(
whitebox_, WB_CIPHER_MODE_CBC,

View File

@@ -77,4 +77,51 @@ TEST_F(LicenseWhiteboxEntitlementContentKeyTest, Decrypt) {
EXPECT_EQ(decrypted, content.plaintext);
}
TEST_F(LicenseWhiteboxEntitlementContentKeyTest, Remove) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_ENTITLEMENT
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
const KeyId key_id = golden_data_.GetFreeId();
auto& content = golden_data_.EntitlementContent();
result = WB_License_LoadEntitledContentKey(
whitebox_, content.entitlement_key.id.data(),
content.entitlement_key.id.size(), key_id.data(), key_id.size(),
content.key_data_iv.data(), content.key_data_iv.size(),
content.key_data.data(), content.key_data.size());
#ifndef HAS_ENTITLEMENT
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
ASSERT_EQ(WB_License_RemoveEntitledContentKey(whitebox_,key_id.data(),
key_id.size()),
WB_RESULT_OK);
std::vector<uint8_t> decrypted(content.plaintext.size());
size_t decrypted_size = decrypted.size();
ASSERT_EQ(WB_License_Decrypt(
whitebox_,
WB_CIPHER_MODE_CTR,
key_id.data(),
key_id.size(),
content.ciphertext.data(),
content.ciphertext.size(),
content.iv.data(),
content.iv.size(),
&decrypted[0],
&decrypted_size),
WB_RESULT_KEY_UNAVAILABLE);
}
} // namespace widevine

View File

@@ -0,0 +1,699 @@
// Copyright 2021 Google LLC. All Rights Reserved.
#include "api/license_whitebox.h"
#include <string>
#include <vector>
#include "api/golden_data.h"
#include "api/license_whitebox_test_base.h"
#include "api/test_license_builder.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace widevine {
class LicenseWhiteboxGenericCryptoInvalidTest
: public LicenseWhiteboxTestBase, public testing::WithParamInterface<int> {
protected:
void SetUp() {
LicenseWhiteboxTestBase::SetUp();
server_ = TestServer::CreateDualKey();
}
std::unique_ptr<TestServer> server_;
License license_;
};
TEST_P(LicenseWhiteboxGenericCryptoInvalidTest, Test) {
auto& content = golden_data_.GenericContent();
GenericKeyData key_data;
switch (GetParam()) {
case 0:
key_data = content.sign_verify_key;
key_data.kcb_flags = WB_KCB_FLAGS_ALLOW_ENCRYPT | WB_KCB_FLAGS_ALLOW_SIGN;
break;
case 1:
key_data = content.encrypt_key;
key_data.key_size = 32u;
break;
case 2:
key_data = content.encrypt_key;
key_data.key_size = 12u;
break;
case 3:
key_data = content.sign_key;
key_data.key_size = 12u;
break;
case 4:
key_data = content.sign_key;
key_data.key_size = 16u;
break;
case 5:
key_data = content.sign_key;
key_data.key_size = 24u;
break;
default:
FAIL();
}
TestLicenseBuilder builder;
builder.GetSettings().odk_version = TestLicenseBuilder::OdkVersion::k16_5;
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey());
builder.AddGenericKey(key_data);
builder.Build(*server_, &license_);
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
// Can return an error while loading, or return success and skip the key
if (result != WB_RESULT_OK)
return;
WB_KeyStatus status;
EXPECT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_GENERIC_KEY,
key_data.id.data(), key_data.id.size(),
&status),
WB_RESULT_KEY_UNAVAILABLE);
}
INSTANTIATE_TEST_SUITE_P(All, LicenseWhiteboxGenericCryptoInvalidTest,
testing::Range(0, 6));
class LicenseWhiteboxGenericCryptoTest
: public LicenseWhiteboxTestBase, public testing::WithParamInterface<bool> {
protected:
void SetUp() {
LicenseWhiteboxTestBase::SetUp();
server_ = TestServer::CreateDualKey();
TestLicenseBuilder builder;
builder.GetSettings().odk_version = TestLicenseBuilder::OdkVersion::k16_5;
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey());
if (GetParam()) {
builder.AddGenericKey(golden_data_.GenericContent().encrypt_decrypt_key);
builder.AddGenericKey(golden_data_.GenericContent().sign_verify_key);
} else {
builder.AddGenericKey(golden_data_.GenericContent().encrypt_key);
builder.AddGenericKey(golden_data_.GenericContent().decrypt_key);
builder.AddGenericKey(golden_data_.GenericContent().sign_key);
builder.AddGenericKey(golden_data_.GenericContent().verify_key);
}
builder.Build(*server_, &license_);
}
std::unique_ptr<TestServer> server_;
License license_;
};
TEST_P(LicenseWhiteboxGenericCryptoTest, NoContentDecrypt) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id;
std::vector<uint8_t> actual(content.plaintext.size());
size_t actual_size = actual.size();
result = WB_License_Decrypt(
whitebox_, WB_CIPHER_MODE_CTR, key_id.data(), key_id.size(),
content.encrypted.data(), content.encrypted.size(), content.iv.data(),
content.iv.size(), actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, NoGenericWithContent) {
auto& content = golden_data_.CTRContent();
auto& key = content.software_crypto_key;
TestLicenseBuilder builder;
builder.GetSettings().odk_version = TestLicenseBuilder::OdkVersion::k16_5;
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey());
builder.AddContentKey(key);
builder.Build(*server_, &license_);
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
std::vector<uint8_t> actual(content.plaintext.size());
size_t actual_size = actual.size();
result = WB_License_GenericDecrypt(
whitebox_, key.id.data(), key.id.size(), content.ciphertext.data(),
content.ciphertext.size(), content.iv.data(), content.iv.size(),
actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, Decrypt) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id;
std::vector<uint8_t> actual(content.plaintext.size());
size_t actual_size = actual.size();
result = WB_License_GenericDecrypt(
whitebox_, key_id.data(), key_id.size(), content.encrypted.data(),
content.encrypted.size(), content.iv.data(), content.iv.size(),
actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
ASSERT_LE(actual_size, actual.size());
actual.resize(actual_size);
EXPECT_EQ(actual, content.plaintext);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptShortBuffer) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id;
size_t actual_size = 0;
result = WB_License_GenericDecrypt(
whitebox_, key_id.data(), key_id.size(), content.encrypted.data(),
content.encrypted.size(), content.iv.data(), content.iv.size(),
nullptr, &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_BUFFER_TOO_SMALL);
ASSERT_GT(actual_size, 0u);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptMissingKey) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
!GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id;
std::vector<uint8_t> actual(content.plaintext.size());
size_t actual_size = actual.size();
result = WB_License_GenericDecrypt(
whitebox_, key_id.data(), key_id.size(), content.encrypted.data(),
content.encrypted.size(), content.iv.data(), content.iv.size(),
actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptKeyUsage) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.sign_verify_key.id : content.sign_key.id;
std::vector<uint8_t> actual(content.plaintext.size());
size_t actual_size = actual.size();
result = WB_License_GenericDecrypt(
whitebox_, key_id.data(), key_id.size(), content.encrypted.data(),
content.encrypted.size(), content.iv.data(), content.iv.size(),
actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_INSUFFICIENT_PERMISSIONS);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptDataSize) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id;
std::vector<uint8_t> actual(content.plaintext.size());
size_t actual_size = actual.size();
// Input size should be a multiple of 16
result = WB_License_GenericDecrypt(
whitebox_, key_id.data(), key_id.size(), content.encrypted.data(),
content.encrypted.size() - 5, content.iv.data(), content.iv.size(),
actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, Encrypt) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.encrypt_decrypt_key.id : content.encrypt_key.id;
std::vector<uint8_t> actual(content.encrypted.size());
size_t actual_size = actual.size();
result = WB_License_GenericEncrypt(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), content.iv.data(), content.iv.size(),
actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
ASSERT_LE(actual_size, actual.size());
actual.resize(actual_size);
EXPECT_EQ(actual, content.encrypted);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptShortBuffer) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.encrypt_decrypt_key.id : content.encrypt_key.id;
size_t actual_size = 0;
result = WB_License_GenericEncrypt(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), content.iv.data(), content.iv.size(),
nullptr, &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_BUFFER_TOO_SMALL);
ASSERT_GT(actual_size, 0u);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptMissingKey) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
!GetParam() ? content.encrypt_decrypt_key.id : content.encrypt_key.id;
std::vector<uint8_t> actual(content.encrypted.size());
size_t actual_size = actual.size();
result = WB_License_GenericEncrypt(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), content.iv.data(), content.iv.size(),
actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptKeyUsage) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.sign_verify_key.id : content.sign_key.id;
std::vector<uint8_t> actual(content.encrypted.size());
size_t actual_size = actual.size();
result = WB_License_GenericEncrypt(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), content.iv.data(), content.iv.size(),
actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_INSUFFICIENT_PERMISSIONS);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptDataSize) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.encrypt_decrypt_key.id : content.encrypt_key.id;
std::vector<uint8_t> actual(content.encrypted.size());
size_t actual_size = actual.size();
// Input size should be a multiple of 16
result = WB_License_GenericEncrypt(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size() - 5, content.iv.data(), content.iv.size(),
actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, Sign) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.sign_verify_key.id : content.sign_key.id;
std::vector<uint8_t> actual(content.signature.size());
size_t actual_size = actual.size();
result = WB_License_GenericSign(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
ASSERT_LE(actual_size, actual.size());
actual.resize(actual_size);
EXPECT_EQ(actual, content.signature);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, SignShortBuffer) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.sign_verify_key.id : content.sign_key.id;
size_t actual_size = 0;
result = WB_License_GenericSign(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), nullptr, &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_BUFFER_TOO_SMALL);
ASSERT_GT(actual_size, 0u);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, SignMissingKey) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
!GetParam() ? content.sign_verify_key.id : content.sign_key.id;
std::vector<uint8_t> actual(content.signature.size());
size_t actual_size = actual.size();
result = WB_License_GenericSign(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, SignKeyUsage) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id;
std::vector<uint8_t> actual(content.signature.size());
size_t actual_size = actual.size();
result = WB_License_GenericSign(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), actual.data(), &actual_size);
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_INSUFFICIENT_PERMISSIONS);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, Verify) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.sign_verify_key.id : content.verify_key.id;
auto temp_signature = content.signature;
// Test once successfully, then make the signature invalid and test again.
for (int i = 0; i < 2; i++) {
result = WB_License_GenericVerify(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), temp_signature.data(), temp_signature.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, i == 0 ? WB_RESULT_OK : WB_RESULT_INVALID_SIGNATURE);
temp_signature[2] ^= 0xaa;
}
}
TEST_P(LicenseWhiteboxGenericCryptoTest, VerifyMissingKey) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
!GetParam() ? content.sign_verify_key.id : content.verify_key.id;
auto temp_signature = content.signature;
result = WB_License_GenericVerify(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), temp_signature.data(), temp_signature.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
}
TEST_P(LicenseWhiteboxGenericCryptoTest, VerifyKeyUsage) {
auto result = WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(),
license_.core_message.size(), license_.message.data(),
license_.message.size(), license_.signature.data(),
license_.signature.size(), license_.session_key.data(),
license_.session_key.size(), kNoProviderKeyId, license_.request.data(),
license_.request.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_OK);
auto& content = golden_data_.GenericContent();
auto& key_id =
GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id;
auto temp_signature = content.signature;
result = WB_License_GenericVerify(
whitebox_, key_id.data(), key_id.size(), content.plaintext.data(),
content.plaintext.size(), temp_signature.data(), temp_signature.size());
#ifndef HAS_GENERIC_CRYPTO
if (result == WB_RESULT_NOT_IMPLEMENTED)
GTEST_SKIP();
#endif
ASSERT_EQ(result, WB_RESULT_INSUFFICIENT_PERMISSIONS);
}
INSTANTIATE_TEST_SUITE_P(All, LicenseWhiteboxGenericCryptoTest,
testing::Bool());
} // namespace widevine

View File

@@ -69,64 +69,84 @@ TEST_F(LicenseWhiteboxGetSecretStringTest, SuccessForCBCWithCryptoKey) {
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_OK);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
ASSERT_GT(secret_string_size_, 0u);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, SuccessForCTRWithCryptoKey) {
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CTR,
golden_data_.CTRContent().software_crypto_key.id.data(),
golden_data_.CTRContent().software_crypto_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_OK);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
ASSERT_GT(secret_string_size_, 0u);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, SuccessForCBCWithDecodeKey) {
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_OK);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
ASSERT_GT(secret_string_size_, 0u);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, SuccessForCTRWithDecodeKey) {
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CTR,
golden_data_.CTRContent().software_decode_key.id.data(),
golden_data_.CTRContent().software_decode_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_OK);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
ASSERT_GT(secret_string_size_, 0u);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, InvalidParameterForNullWhitebox) {
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
nullptr, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_INVALID_PARAMETER);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest,
@@ -139,34 +159,46 @@ TEST_F(LicenseWhiteboxGetSecretStringTest,
// compiler tries to save us.
const WB_CipherMode invalid_mode = static_cast<WB_CipherMode>(0xFF);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, invalid_mode,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_INVALID_PARAMETER);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, InvalidParameterForNullKeyId) {
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC, nullptr,
golden_data_.CBCContent().software_crypto_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_INVALID_PARAMETER);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, InvalidParameterForZeroKeyIdSize) {
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(), 0,
secret_string_.data(), &secret_string_size_),
WB_RESULT_INVALID_PARAMETER);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, CanProbeSizeWithNullString) {
@@ -174,13 +206,17 @@ TEST_F(LicenseWhiteboxGetSecretStringTest, CanProbeSizeWithNullString) {
LoadLicense(settings);
secret_string_size_ = 0;
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
nullptr, &secret_string_size_),
WB_RESULT_BUFFER_TOO_SMALL);
golden_data_.CBCContent().software_crypto_key.id.size(), nullptr,
&secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_BUFFER_TOO_SMALL);
ASSERT_GT(secret_string_size_, 0);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest,
@@ -188,12 +224,16 @@ TEST_F(LicenseWhiteboxGetSecretStringTest,
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
nullptr, &secret_string_size_),
WB_RESULT_INVALID_PARAMETER);
golden_data_.CBCContent().software_crypto_key.id.size(), nullptr,
&secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest,
@@ -201,12 +241,16 @@ TEST_F(LicenseWhiteboxGetSecretStringTest,
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
secret_string_.data(), nullptr),
WB_RESULT_INVALID_PARAMETER);
secret_string_.data(), nullptr);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
// For this test, "missing key id" specifically means a key id that was never
@@ -216,22 +260,28 @@ TEST_F(LicenseWhiteboxGetSecretStringTest, KeyUnavailableForMissingKeyId) {
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC,
missing_key_id_.data(), missing_key_id_.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_KEY_UNAVAILABLE);
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC, missing_key_id_.data(),
missing_key_id_.size(), secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, KeyUnavailableForNonContentKey) {
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC, non_content_key_id_.data(),
non_content_key_id_.size(), secret_string_.data(),
&secret_string_size_),
WB_RESULT_KEY_UNAVAILABLE);
non_content_key_id_.size(), secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
#endif
}
// Under normal circumstances, a hardware key should be dropped. The exception
@@ -241,12 +291,16 @@ TEST_F(LicenseWhiteboxGetSecretStringTest,
TestLicenseBuilder::Settings settings;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().hardware_key.id.data(),
golden_data_.CBCContent().hardware_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_INSUFFICIENT_SECURITY_LEVEL);
golden_data_.CBCContent().hardware_key.id.size(), secret_string_.data(),
&secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INSUFFICIENT_PERMISSIONS);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, BufferTooSmall) {
@@ -258,29 +312,37 @@ TEST_F(LicenseWhiteboxGetSecretStringTest, BufferTooSmall) {
// as it would not introduce enough variation to be effective. We avoid using
// zero here so that we can verify that we are not just checking for zero.
secret_string_size_ = 1;
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_BUFFER_TOO_SMALL);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_BUFFER_TOO_SMALL);
// Make sure that the output included the required size. We don't know what
// it is, so we rely on checking that it is just bigger than the "too small"
// size.
ASSERT_GT(secret_string_size_, 1u);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, InvalidState) {
// Purposely do not load a license so that we won't have any keys, causing
// use to be in an invalid state.
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_INVALID_STATE);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_STATE);
#endif
}
TEST_F(LicenseWhiteboxGetSecretStringTest, KeyUnavailableForInvalidKey) {
@@ -291,12 +353,16 @@ TEST_F(LicenseWhiteboxGetSecretStringTest, KeyUnavailableForInvalidKey) {
settings.include_content_key_iv = false;
LoadLicense(settings);
ASSERT_EQ(WB_License_GetSecretString(
auto result = WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
secret_string_.data(), &secret_string_size_),
WB_RESULT_KEY_UNAVAILABLE);
secret_string_.data(), &secret_string_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
#endif
}
} // namespace widevine

View File

@@ -66,6 +66,7 @@ TEST_P(LicenseWhiteboxKeyControlBlockTest, Decrypt) {
WB_RESULT_OK);
}
#ifndef ALWAYS_DECRYPT_TO_CLEAR
TEST_P(LicenseWhiteboxKeyControlBlockTest, MaskedDecrypt) {
TestLicenseBuilder builder;
builder.GetSettings().key_control_block = kcb_;
@@ -100,6 +101,7 @@ TEST_P(LicenseWhiteboxKeyControlBlockTest, MaskedDecrypt) {
&plaintext_size),
WB_RESULT_OK);
}
#endif
INSTANTIATE_TEST_SUITE_P(
AllCombination,
@@ -110,4 +112,49 @@ INSTANTIATE_TEST_SUITE_P(
::testing::Values(TestLicenseBuilder::OdkVersion::kNone,
TestLicenseBuilder::OdkVersion::k16_3,
TestLicenseBuilder::OdkVersion::k16_5)));
class LicenseWhiteboxKeyControlBlockSingleTest
: public LicenseWhiteboxTestBase {
protected:
void SetUp() override {
LicenseWhiteboxTestBase::SetUp();
server_ = TestServer::CreateDualKey();
}
std::unique_ptr<TestServer> server_;
};
TEST_F(LicenseWhiteboxKeyControlBlockSingleTest, KcbHeaderError) {
TestLicenseBuilder builder;
builder.GetSettings().odk_version = TestLicenseBuilder::OdkVersion::k16_5;
builder.GetSettings().kcb_header_error = true;
const auto& content = golden_data_.CBCContent();
const auto& key = content.software_crypto_key;
builder.AddContentKey(key);
License license;
builder.Build(*server_, &license);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license.core_message.data(),
license.core_message.size(), license.message.data(),
license.message.size(), license.signature.data(),
license.signature.size(), license.session_key.data(),
license.session_key.size(), kNoProviderKeyId, license.request.data(),
license.request.size()),
WB_RESULT_OK);
std::vector<uint8_t> plaintext(content.ciphertext.size());
size_t plaintext_size = plaintext.size();
auto result = WB_License_Decrypt(
whitebox_, WB_CIPHER_MODE_CBC, key.id.data(), key.id.size(),
content.ciphertext.data(), content.ciphertext.size(), content.iv.data(),
content.iv.size(), plaintext.data(), &plaintext_size);
// Either it works or the key should be skipped.
if (result != WB_RESULT_OK)
EXPECT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
}
} // namespace widevine

View File

@@ -113,16 +113,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCbcDataInCbcMode) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Returned data is masked, so it should be the correct size but not
@@ -145,6 +147,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCbcDataInCbcMode) {
plaintext_.data());
ASSERT_EQ(plaintext_, golden_data_.CBCContent().plaintext);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyInPlaceCbc) {
@@ -156,15 +159,17 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyInPlaceCbc) {
memcpy(masked_text_.data(), golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size());
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
masked_text_.data(), masked_text_.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Returned data is masked, so it should be the correct size but not
@@ -187,6 +192,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyInPlaceCbc) {
plaintext_.data());
ASSERT_EQ(plaintext_, golden_data_.CBCContent().plaintext);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCtrDataInCtrMode) {
@@ -195,16 +201,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCtrDataInCtrMode) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CTR,
golden_data_.CTRContent().software_decode_key.id.data(),
golden_data_.CTRContent().software_decode_key.id.size(),
golden_data_.CTRContent().ciphertext.data(),
golden_data_.CTRContent().ciphertext.size(),
golden_data_.CTRContent().iv.data(),
golden_data_.CTRContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CTRContent().iv.data(), golden_data_.CTRContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Returned data is masked, so it should be the correct size but not
@@ -227,6 +235,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCtrDataInCtrMode) {
plaintext_.data());
ASSERT_EQ(plaintext_, golden_data_.CTRContent().plaintext);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyInPlaceCtr) {
@@ -238,15 +247,17 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyInPlaceCtr) {
memcpy(masked_text_.data(), golden_data_.CTRContent().ciphertext.data(),
golden_data_.CTRContent().ciphertext.size());
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CTR,
golden_data_.CTRContent().software_decode_key.id.data(),
golden_data_.CTRContent().software_decode_key.id.size(),
masked_text_.data(), masked_text_.size(),
golden_data_.CTRContent().iv.data(),
golden_data_.CTRContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CTRContent().iv.data(), golden_data_.CTRContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Returned data is masked, so it should be the correct size but not
@@ -269,6 +280,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyInPlaceCtr) {
plaintext_.data());
ASSERT_EQ(plaintext_, golden_data_.CTRContent().plaintext);
#endif
}
// We try to decrypt CBC encrypted data in CTR mode. All operations should be
@@ -279,16 +291,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCbcDataInCtrMode) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CTR,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Whatever is returned must not be the original text.
@@ -310,6 +324,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCbcDataInCtrMode) {
plaintext_.data());
ASSERT_NE(masked_text_, golden_data_.CBCContent().plaintext);
#endif
}
// We try to decrypt CTR encrypted data in CBC mode. All operations should be
@@ -320,16 +335,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCtrDataInCbcMode) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CTRContent().software_decode_key.id.data(),
golden_data_.CTRContent().software_decode_key.id.size(),
golden_data_.CTRContent().ciphertext.data(),
golden_data_.CTRContent().ciphertext.size(),
golden_data_.CTRContent().iv.data(),
golden_data_.CTRContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CTRContent().iv.data(), golden_data_.CTRContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Whatever is returned must not be the original text.
@@ -351,6 +368,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCtrDataInCbcMode) {
plaintext_.data());
ASSERT_NE(masked_text_, golden_data_.CTRContent().plaintext);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataInCbcMode) {
@@ -359,16 +377,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataInCbcMode) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Returned data is masked, so it should be the correct size but not
@@ -391,6 +411,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataInCbcMode) {
plaintext_.data());
ASSERT_EQ(plaintext_, golden_data_.CBCContent().plaintext);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataInCtrMode) {
@@ -399,16 +420,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataInCtrMode) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CTR,
golden_data_.CTRContent().software_crypto_key.id.data(),
golden_data_.CTRContent().software_crypto_key.id.size(),
golden_data_.CTRContent().ciphertext.data(),
golden_data_.CTRContent().ciphertext.size(),
golden_data_.CTRContent().iv.data(),
golden_data_.CTRContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CTRContent().iv.data(), golden_data_.CTRContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Returned data is masked, so it should be the correct size but not
@@ -431,6 +454,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataInCtrMode) {
plaintext_.data());
ASSERT_EQ(plaintext_, golden_data_.CTRContent().plaintext);
#endif
}
// We try to decrypt CBC encrypted data in CTR mode. All operations should be
@@ -441,16 +465,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataInCtrMode) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CTR,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Whatever is returned must not be the original text.
@@ -472,6 +498,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataInCtrMode) {
plaintext_.data());
ASSERT_NE(masked_text_, golden_data_.CBCContent().plaintext);
#endif
}
// We try to decrypt CTR encrypted data in CBC mode. All operations should be
@@ -482,16 +509,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataInCbcMode) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CTRContent().software_crypto_key.id.data(),
golden_data_.CTRContent().software_crypto_key.id.size(),
golden_data_.CTRContent().ciphertext.data(),
golden_data_.CTRContent().ciphertext.size(),
golden_data_.CTRContent().iv.data(),
golden_data_.CTRContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CTRContent().iv.data(), golden_data_.CTRContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Whatever is returned must not be the original text.
@@ -513,6 +542,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataInCbcMode) {
plaintext_.data());
ASSERT_NE(masked_text_, golden_data_.CTRContent().plaintext);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataAndPKCS8Padding) {
@@ -521,16 +551,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataAndPKCS8Padding) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_crypto_key.id.data(),
golden_data_.CBCContent().software_crypto_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Returned data is masked, so it should be the correct size but not
@@ -553,6 +585,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataAndPKCS8Padding) {
plaintext_.data());
ASSERT_EQ(plaintext_, golden_data_.CBCContent().plaintext);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataAndPKCS8Padding) {
@@ -561,16 +594,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataAndPKCS8Padding) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CTR,
golden_data_.CTRContent().software_crypto_key.id.data(),
golden_data_.CTRContent().software_crypto_key.id.size(),
golden_data_.CTRContent().ciphertext.data(),
golden_data_.CTRContent().ciphertext.size(),
golden_data_.CTRContent().iv.data(),
golden_data_.CTRContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CTRContent().iv.data(), golden_data_.CTRContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Returned data is masked, so it should be the correct size but not
@@ -593,6 +628,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataAndPKCS8Padding) {
plaintext_.data());
ASSERT_EQ(plaintext_, golden_data_.CTRContent().plaintext);
#endif
}
// Try decrypting two different sets of content to make sure that two
@@ -606,16 +642,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, SuccessWithMultipleKeys) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Returned data is masked, so it should be the correct size but not
@@ -679,6 +717,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, SuccessWithMultipleKeys) {
plaintext_.data());
ASSERT_EQ(plaintext_, golden_data_.CTRContent().plaintext);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullWhitebox) {
@@ -687,16 +726,19 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullWhitebox) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
nullptr, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_INVALID_PARAMETER);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForInvalidCipherMode) {
@@ -710,16 +752,19 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForInvalidCipherMode) {
// the compiler tries to save us.
const WB_CipherMode invalid_mode = static_cast<WB_CipherMode>(0xFF);
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, invalid_mode,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_INVALID_PARAMETER);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullKeyId) {
@@ -728,15 +773,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullKeyId) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC, nullptr,
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_INVALID_PARAMETER);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullZeroKeyIdSize) {
@@ -745,15 +793,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullZeroKeyIdSize) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(), 0,
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_INVALID_PARAMETER);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullInputData) {
@@ -762,15 +813,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullInputData) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
nullptr, golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_INVALID_PARAMETER);
golden_data_.CBCContent().software_decode_key.id.size(), nullptr,
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
// AES CBC requires that the input be block aligned (multiple of 16). CTR does
@@ -782,15 +836,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest,
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(), 14,
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_INVALID_PARAMETER);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
// The white-box (using any cipher mode) should reject input with size zero.
@@ -800,15 +857,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForZeroInputDataSize) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(), 0,
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_INVALID_PARAMETER);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullIV) {
@@ -817,15 +877,19 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullIV) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(), nullptr,
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_INVALID_PARAMETER);
&masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
// IV size should be 16. Any number other than 16 should fail.
@@ -835,15 +899,19 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForInvalidIVSize) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(), 9, masked_text_.data(),
&masked_text_size_),
WB_RESULT_INVALID_PARAMETER);
&masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullOutput) {
@@ -852,16 +920,19 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullOutput) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(
WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), nullptr, &masked_text_size_),
WB_RESULT_INVALID_PARAMETER);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
nullptr, &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullOutputSize) {
@@ -870,16 +941,19 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullOutputSize) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(
WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(), nullptr),
WB_RESULT_INVALID_PARAMETER);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), nullptr);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_PARAMETER);
#endif
}
// For this test, "missing key id" specifically means a key id that was never
@@ -891,15 +965,17 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, KeyUnavailableForMissingKeyId) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(
WB_License_MaskedDecrypt(whitebox_, WB_CIPHER_MODE_CBC,
missing_key_id_.data(), missing_key_id_.size(),
golden_data_.CBCContent().ciphertext.data(),
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC, missing_key_id_.data(),
missing_key_id_.size(), golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_),
WB_RESULT_KEY_UNAVAILABLE);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, KeyUnavailableForNonContentKey) {
@@ -908,15 +984,17 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, KeyUnavailableForNonContentKey) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC, non_content_key_id_.data(),
non_content_key_id_.size(),
golden_data_.CBCContent().ciphertext.data(),
non_content_key_id_.size(), golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_KEY_UNAVAILABLE);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
#endif
}
// Under normal circumstances, a hardware key should be dropped. The exception
@@ -928,32 +1006,38 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest,
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(
WB_License_MaskedDecrypt(whitebox_, WB_CIPHER_MODE_CBC,
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().hardware_key.id.data(),
golden_data_.CBCContent().hardware_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_),
WB_RESULT_INSUFFICIENT_SECURITY_LEVEL);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INSUFFICIENT_PERMISSIONS);
#endif
}
// Unlike the other tests, we do not call LoadLicense() as the criteria for
// WB_RESULT_INVALID_STATE is that no key can be found and keys are provided
// via a license.
TEST_P(LicenseWhiteboxMaskedDecryptTest, InvalidState) {
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_INVALID_STATE);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_INVALID_STATE);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, BufferTooSmall) {
@@ -966,20 +1050,23 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, BufferTooSmall) {
// using a constant here.
masked_text_size_ = 8;
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_BUFFER_TOO_SMALL);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_BUFFER_TOO_SMALL);
// We don't use padding so the reported plaintext size should be the same as
// the cipher text size.
ASSERT_EQ(masked_text_size_, golden_data_.CBCContent().ciphertext.size());
#endif
}
// Check that the result of unmasking only a small portion of the data is the
@@ -990,16 +1077,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, SuccessForSubRangeUnmask) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
ASSERT_EQ(WB_License_GetSecretString(
whitebox_, WB_CIPHER_MODE_CBC,
@@ -1022,6 +1111,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, SuccessForSubRangeUnmask) {
ASSERT_EQ(full_unmask[4], partial_unmask[0]);
ASSERT_EQ(full_unmask[5], partial_unmask[1]);
ASSERT_EQ(full_unmask[6], partial_unmask[2]);
#endif
}
TEST_P(LicenseWhiteboxMaskedDecryptTest, KeyUnavailableForInvalidKey) {
@@ -1033,16 +1123,19 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, KeyUnavailableForInvalidKey) {
if (!LoadLicense(settings, provider_key_id_))
GTEST_SKIP();
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_KEY_UNAVAILABLE);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE);
#endif
}
// For this test, we create a license using the test specified Provider Key
@@ -1072,16 +1165,18 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, MismatchProviderKeyId) {
GTEST_SKIP();
// Decryption should succeed, but the plaintext should be incorrect.
ASSERT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
golden_data_.CBCContent().software_decode_key.id.data(),
golden_data_.CBCContent().software_decode_key.id.size(),
golden_data_.CBCContent().ciphertext.data(),
golden_data_.CBCContent().ciphertext.size(),
golden_data_.CBCContent().iv.data(),
golden_data_.CBCContent().iv.size(), masked_text_.data(),
&masked_text_size_),
WB_RESULT_OK);
golden_data_.CBCContent().iv.data(), golden_data_.CBCContent().iv.size(),
masked_text_.data(), &masked_text_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
masked_text_.resize(masked_text_size_);
// Returned data is masked, so it should be the correct size but not
@@ -1105,6 +1200,7 @@ TEST_P(LicenseWhiteboxMaskedDecryptTest, MismatchProviderKeyId) {
plaintext_.data());
ASSERT_NE(plaintext_, golden_data_.CBCContent().plaintext);
#endif
}
INSTANTIATE_TEST_SUITE_P(

View File

@@ -80,6 +80,50 @@ WEAK WB_Result WB_License_SignPstReport(const WB_License_Whitebox* whitebox,
return WB_RESULT_NOT_IMPLEMENTED;
}
WEAK WB_Result WB_License_GenericEncrypt(const WB_License_Whitebox* whitebox,
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) {
return WB_RESULT_NOT_IMPLEMENTED;
}
WEAK WB_Result WB_License_GenericDecrypt(const WB_License_Whitebox* whitebox,
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) {
return WB_RESULT_NOT_IMPLEMENTED;
}
WEAK WB_Result WB_License_GenericSign(const WB_License_Whitebox* whitebox,
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) {
return WB_RESULT_NOT_IMPLEMENTED;
}
WEAK WB_Result WB_License_GenericVerify(const WB_License_Whitebox* whitebox,
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) {
return WB_RESULT_NOT_IMPLEMENTED;
}
namespace widevine {
WEAK std::vector<uint8_t> GetLicenseWhiteboxProviderKeysInitData() {

View File

@@ -91,12 +91,15 @@ TEST_P(LicenseWhiteboxSecurityLevelTest, CanLoadAndUseKey) {
plaintext_size_ = content.ciphertext.size();
plaintext_.resize(plaintext_size_);
EXPECT_EQ(WB_License_MaskedDecrypt(
auto result = WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC, key->id.data(), key->id.size(),
content.ciphertext.data(), content.ciphertext.size(),
content.iv.data(), content.iv.size(), plaintext_.data(),
&plaintext_size_),
WB_RESULT_OK);
content.ciphertext.data(), content.ciphertext.size(), content.iv.data(),
content.iv.size(), plaintext_.data(), &plaintext_size_);
#ifdef ALWAYS_DECRYPT_TO_CLEAR
ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED);
#else
ASSERT_EQ(result, WB_RESULT_OK);
#endif
}
INSTANTIATE_TEST_SUITE_P(

View File

@@ -316,23 +316,6 @@ INSTANTIATE_TEST_SUITE_P(
RemoteAttestation::kUnavailable,
VerificationStatus::kUnavailable,
Mode::kDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
NoRemoteAttestationNoVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kUnavailable,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kUnavailable,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kUnavailable,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
UnverifiedRemoteAttestationNoVerificationDecrypt,
@@ -352,24 +335,6 @@ INSTANTIATE_TEST_SUITE_P(
VerificationStatus::kUnavailable,
Mode::kDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
UnverifiedRemoteAttestationNoVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kUnverified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kUnverified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kUnverified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
VerifiedRemoteAttestationNoVerificationDecrypt,
RemoteAttestationAndVerificationTest,
@@ -388,24 +353,6 @@ INSTANTIATE_TEST_SUITE_P(
VerificationStatus::kUnavailable,
Mode::kDecryptPass))));
INSTANTIATE_TEST_SUITE_P(
VerifiedRemoteAttestationNoVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kVerified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kVerified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kVerified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass))));
INSTANTIATE_TEST_SUITE_P(
NoRemoteAttestationHardwareVerificationDecrypt,
RemoteAttestationAndVerificationTest,
@@ -424,24 +371,6 @@ INSTANTIATE_TEST_SUITE_P(
VerificationStatus::kHardwareVerified,
Mode::kDecryptPass))));
INSTANTIATE_TEST_SUITE_P(
NoRemoteAttestationHardwareVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kUnavailable,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kUnavailable,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kUnavailable,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass))));
INSTANTIATE_TEST_SUITE_P(
UnverifiedRemoteAttestationHardwareVerificationDecrypt,
RemoteAttestationAndVerificationTest,
@@ -460,24 +389,6 @@ INSTANTIATE_TEST_SUITE_P(
VerificationStatus::kHardwareVerified,
Mode::kDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
UnverifiedRemoteAttestationHardwareVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kUnverified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kUnverified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kUnverified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
VerifiedRemoteAttestationHardwareVerificationDecrypt,
RemoteAttestationAndVerificationTest,
@@ -496,24 +407,6 @@ INSTANTIATE_TEST_SUITE_P(
VerificationStatus::kHardwareVerified,
Mode::kDecryptPass))));
INSTANTIATE_TEST_SUITE_P(
VerifiedRemoteAttestationHardwareVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kVerified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kVerified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kVerified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass))));
INSTANTIATE_TEST_SUITE_P(
NoRemoteAttestationOtherVerificationDecrypt,
RemoteAttestationAndVerificationTest,
@@ -532,24 +425,6 @@ INSTANTIATE_TEST_SUITE_P(
VerificationStatus::kOther,
Mode::kDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
NoRemoteAttestationOtherVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kUnavailable,
VerificationStatus::kOther,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kUnavailable,
VerificationStatus::kOther,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kUnavailable,
VerificationStatus::kOther,
Mode::kMaskedDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
UnverifiedRemoteAttestationOtherVerificationDecrypt,
RemoteAttestationAndVerificationTest,
@@ -568,6 +443,151 @@ INSTANTIATE_TEST_SUITE_P(
VerificationStatus::kOther,
Mode::kDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
VerifiedRemoteAttestationOtherVerificationDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kVerified,
VerificationStatus::kOther,
Mode::kDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kVerified,
VerificationStatus::kOther,
Mode::kDecryptFail),
std::make_tuple(Key::kHardware,
RemoteAttestation::kVerified,
VerificationStatus::kOther,
Mode::kDecryptFail))));
#ifndef ALWAYS_DECRYPT_TO_CLEAR
INSTANTIATE_TEST_SUITE_P(
NoRemoteAttestationNoVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kUnavailable,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kUnavailable,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kUnavailable,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
UnverifiedRemoteAttestationNoVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kUnverified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kUnverified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kUnverified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
VerifiedRemoteAttestationNoVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kVerified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kVerified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kVerified,
VerificationStatus::kUnavailable,
Mode::kMaskedDecryptPass))));
INSTANTIATE_TEST_SUITE_P(
NoRemoteAttestationHardwareVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kUnavailable,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kUnavailable,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kUnavailable,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass))));
INSTANTIATE_TEST_SUITE_P(
UnverifiedRemoteAttestationHardwareVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kUnverified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kUnverified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kUnverified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
VerifiedRemoteAttestationHardwareVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kVerified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kVerified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kVerified,
VerificationStatus::kHardwareVerified,
Mode::kMaskedDecryptPass))));
INSTANTIATE_TEST_SUITE_P(
NoRemoteAttestationOtherVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kUnavailable,
VerificationStatus::kOther,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kUnavailable,
VerificationStatus::kOther,
Mode::kMaskedDecryptPass),
std::make_tuple(Key::kHardware,
RemoteAttestation::kUnavailable,
VerificationStatus::kOther,
Mode::kMaskedDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
UnverifiedRemoteAttestationOtherVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
@@ -586,24 +606,6 @@ INSTANTIATE_TEST_SUITE_P(
VerificationStatus::kOther,
Mode::kMaskedDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
VerifiedRemoteAttestationOtherVerificationDecrypt,
RemoteAttestationAndVerificationTest,
::testing::Combine(
::testing::Values(Padding::kNone, Padding::kPKSC8),
::testing::Values(std::make_tuple(Key::kCrypto,
RemoteAttestation::kVerified,
VerificationStatus::kOther,
Mode::kDecryptPass),
std::make_tuple(Key::kDecode,
RemoteAttestation::kVerified,
VerificationStatus::kOther,
Mode::kDecryptFail),
std::make_tuple(Key::kHardware,
RemoteAttestation::kVerified,
VerificationStatus::kOther,
Mode::kDecryptFail))));
INSTANTIATE_TEST_SUITE_P(
VerifiedRemoteAttestationOtherVerificationMaskedDecrypt,
RemoteAttestationAndVerificationTest,
@@ -621,4 +623,5 @@ INSTANTIATE_TEST_SUITE_P(
RemoteAttestation::kVerified,
VerificationStatus::kOther,
Mode::kMaskedDecryptFail))));
#endif
} // namespace widevine

View File

@@ -33,8 +33,9 @@ typedef enum {
// exists for the given key id.
WB_RESULT_KEY_UNAVAILABLE = 6,
// The requested key's security level is not sufficient for the operation.
WB_RESULT_INSUFFICIENT_SECURITY_LEVEL = 7,
// The requested key's security level or flags do not allow the operation.
WB_RESULT_INSUFFICIENT_PERMISSIONS = 7,
WB_RESULT_INSUFFICIENT_SECURITY_LEVEL = WB_RESULT_INSUFFICIENT_PERMISSIONS,
// The input data failed to be verified. This may happen if the data was
// corrupted or tampered.

View File

@@ -49,6 +49,16 @@ struct EntitlementKeyData {
Aes256Key key;
};
struct GenericKeyData {
// The unique key id for this key. Any instance with this id should contain
// the same level and key as this.
KeyId id;
Aes256Key key;
uint32_t kcb_flags = 0;
uint8_t key_size = 32u;
};
} // namespace widevine
#endif // WHITEBOX_API_TEST_KEY_TYPES_H_

View File

@@ -5,6 +5,7 @@
#include <array>
#include <ctime>
#include <map>
#include <type_traits>
#include "api/test_license_provider_keys.h"
#include "base/check.h"
@@ -140,8 +141,7 @@ video_widevine::License_KeyContainer_SecurityLevel SecurityLevelToProto(
}
KeyControlBlock CreateKeyControlBlock(
video_widevine::License_KeyContainer_SecurityLevel level,
video_widevine::License_KeyContainer_KeyControl* key_control) {
video_widevine::License_KeyContainer_SecurityLevel level) {
// The key control block is an 128 bit structure containing the following
// fields. The fields are defined to be in big-endian byte order.
//
@@ -331,10 +331,13 @@ void AddContentKeyToContainer(const ContentKeyData& key_data,
break;
case TestLicenseBuilder::KeyControlBlock::kClear: {
auto* key_control = container->mutable_key_control();
const auto key_control_block = CreateKeyControlBlock(
SecurityLevelToProto(key_data.level), key_control);
auto key_control_block =
CreateKeyControlBlock(SecurityLevelToProto(key_data.level));
if (settings.kcb_header_error) {
key_control_block[0] ^= 0xaa;
}
auto* key_control = container->mutable_key_control();
key_control->set_key_control_block(key_control_block.data(),
key_control_block.size());
@@ -345,14 +348,17 @@ void AddContentKeyToContainer(const ContentKeyData& key_data,
// It is only when the key control block is encrypted will the IV be set.
// The key control block is encrypted with the content key. This will no
// longer be the case in OEMCrypto 17.
auto* key_control = container->mutable_key_control();
const auto key_control_block = CreateKeyControlBlock(
SecurityLevelToProto(key_data.level), key_control);
auto key_control_block =
CreateKeyControlBlock(SecurityLevelToProto(key_data.level));
if (settings.kcb_header_error) {
key_control_block[0] ^= 0xaa;
}
const auto key_control_block_iv = DeriveIV(key_control_block);
const auto encrypted_key_control_block =
Encrypt(key_data.key, key_control_block_iv, key_control_block);
auto* key_control = container->mutable_key_control();
key_control->set_iv(key_control_block_iv);
key_control->set_key_control_block(encrypted_key_control_block.data(),
encrypted_key_control_block.size());
@@ -381,9 +387,39 @@ void AddEntitlementKeyToContainer(
auto encrypted_key = Encrypt(container_key, key_iv, key);
container->set_key(encrypted_key);
auto* key_control = container->mutable_key_control();
const auto key_control_block =
CreateKeyControlBlock(SecurityLevelToProto(key_data.level), key_control);
CreateKeyControlBlock(SecurityLevelToProto(key_data.level));
auto* key_control = container->mutable_key_control();
key_control->set_key_control_block(key_control_block.data(),
key_control_block.size());
}
void AddGenericKeyToContainer(
const GenericKeyData& key_data, const std::string& container_key,
video_widevine::License_KeyContainer* container) {
container->set_type(
video_widevine::License_KeyContainer_KeyType_OPERATOR_SESSION);
container->set_id(key_data.id.data(), key_data.id.size());
// To avoid having to define a key iv for each key, derive a key iv from the
// key. This will allows us to have a different IVs between keys but keep it
// deterministic.
const auto key_iv = DeriveIV(key_data.key);
container->set_iv(key_iv);
auto encrypted_key = Encrypt(container_key, key_iv, key_data.key);
CHECK_LE(key_data.key_size, encrypted_key.size());
encrypted_key.resize(key_data.key_size);
container->set_key(encrypted_key);
auto key_control_block = CreateKeyControlBlock(
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO);
key_control_block[12] |= key_data.kcb_flags >> 24;
key_control_block[13] |= key_data.kcb_flags >> 16;
key_control_block[14] |= key_data.kcb_flags >> 8;
key_control_block[15] |= key_data.kcb_flags;
auto* key_control = container->mutable_key_control();
key_control->set_key_control_block(key_control_block.data(),
key_control_block.size());
}
@@ -485,6 +521,10 @@ void TestLicenseBuilder::AddEntitlementKey(const EntitlementKeyData& key) {
entitlement_keys_.push_back(key);
}
void TestLicenseBuilder::AddGenericKey(const GenericKeyData& key) {
generic_keys_.push_back(key);
}
void TestLicenseBuilder::AddOperatorSessionKey(const KeyId& id) {
operator_session_keys_.push_back(id);
}
@@ -532,8 +572,12 @@ void TestLicenseBuilder::Build(const TestServer& server,
response.add_key());
}
// Cannot have both content keys and entitlement keys.
CHECK(content_keys_.empty() || entitlement_keys_.empty());
// Can only have one of content, entitlement, or generic keys.
const int num_key_types =
(content_keys_.empty() ? 0 : 1) +
(entitlement_keys_.empty() ? 0 : 1) +
(generic_keys_.empty() ? 0 : 1);
CHECK_LE(num_key_types, 1);
for (const auto& key : content_keys_) {
AddContentKeyToContainer(key, settings_, container_key_,
@@ -542,6 +586,9 @@ void TestLicenseBuilder::Build(const TestServer& server,
for (const auto& key : entitlement_keys_) {
AddEntitlementKeyToContainer(key, container_key_, response.add_key());
}
for (const auto& key : generic_keys_) {
AddGenericKeyToContainer(key, container_key_, response.add_key());
}
for (const auto& key : operator_session_keys_) {
AddOperatorSessionKeyToContainer(key, response.add_key());

View File

@@ -86,6 +86,9 @@ class TestLicenseBuilder {
bool include_signing_key_key = true;
bool include_signing_key_type = true;
// Whether to insert an error in the KCB header
bool kcb_header_error = false;
// Our content key's key and ivs should always be 16 bytes (see AesKey
// definition), but we can use these controls to cut them short. If these
// values are larger than 16, the key/iv with be padded. In order to
@@ -122,6 +125,8 @@ class TestLicenseBuilder {
void AddEntitlementKey(const EntitlementKeyData& key);
void AddGenericKey(const GenericKeyData& key);
// The key id will matter as we will need to reference it, but the key won't
// matter since we are only using it as a means to verify that a non-content
// key can't be used as a content key.
@@ -149,6 +154,7 @@ class TestLicenseBuilder {
std::vector<ContentKeyData> content_keys_;
std::vector<EntitlementKeyData> entitlement_keys_;
std::vector<GenericKeyData> generic_keys_;
std::vector<SigningKey> signing_keys_;
std::vector<KeyId> operator_session_keys_;
};

View File

@@ -41,6 +41,7 @@ const int kAes128KeySizeBits = 128;
const int kAes128KeySizeBytes = 16;
const int kAes256KeySizeBytes = 32;
const char kKeyboxV3Label[] = "Keyboxv3";
const int kSha256HmacSizeBytes = SHA256_DIGEST_LENGTH;
const int kAesBlockSizeBits = AES_BLOCK_SIZE * 8;
const int kAesMaxDerivedBlocks = 255;

View File

@@ -35,6 +35,7 @@ extern const int kIvSizeBits;
extern const int kAes128KeySizeBits;
extern const int kAes128KeySizeBytes;
extern const char kKeyboxV3Label[];
extern const int kSha256HmacSizeBytes;
extern const uint32_t kCENCSchemeID; // 'cenc' (AES-CTR): 0x63656E63
extern const uint32_t kCBC1SchemeID; // 'cbc1' (AES-CBC): 0x63626331

View File

@@ -174,6 +174,7 @@ cc_library(
"//chromium_deps/cdm/keys:dev_certs",
"//chromium_deps/cdm/protos:license_protocol_proto",
"//crypto_utils:aes_cbc_decryptor",
"//crypto_utils:aes_cbc_encryptor",
"//crypto_utils:aes_ctr_encryptor",
"//crypto_utils:crypto_util",
"//crypto_utils:rsa_key",

View File

@@ -16,6 +16,7 @@ enum class KeyType {
kInvalid,
kContentKey,
kEntitlementKey,
kGenericCryptoKey,
};
struct InternalKey {
@@ -23,6 +24,7 @@ struct InternalKey {
WB_KeyStatus status = WB_KEY_STATUS_INVALID;
KeyType type = KeyType::kInvalid;
std::array<uint8_t, 32u> key;
uint32_t kcb_flags = 0;
// These are the permission flags that will be used internally to check if
// we can use a key.

View File

@@ -103,10 +103,14 @@ WB_KeyStatus LicenseParser::GetKeyStatus(
InternalKey LicenseParser::CreateInternalKey(
KeyType key_type, video_widevine::License_KeyContainer_SecurityLevel level,
bool is_hw_verified, const std::string& key) {
bool is_hw_verified, const std::string& key, uint32_t kcb_flags) {
CHECK((kcb_flags & WB_KCB_FLAGS_GENERIC_MASK) == 0 ||
key_type == KeyType::kGenericCryptoKey);
InternalKey internal_key;
internal_key.type = key_type;
internal_key.status = GetKeyStatus(level, is_hw_verified);
internal_key.kcb_flags = kcb_flags;
// Unless we are going to use the key, we don't want to save this key as it
// will only risk exposing it. We only have an entry for it so we can handle

View File

@@ -42,6 +42,7 @@ class LicenseParser {
virtual const std::map<std::string, InternalKey>& GetContentKeys() const = 0;
virtual const std::map<std::string, InternalKey>&
GetEntitlementKeys() const = 0;
virtual const std::map<std::string, InternalKey>& GetGenericKeys() const = 0;
protected:
static bool Decrypt(const std::string& key,
@@ -69,7 +70,8 @@ class LicenseParser {
KeyType key_type,
video_widevine::License_KeyContainer_SecurityLevel level,
bool is_hw_verified,
const std::string& key);
const std::string& key,
uint32_t kcb_flags = 0);
static WB_KeyStatus GetKeyStatus(
video_widevine::License_KeyContainer_SecurityLevel level,

View File

@@ -13,6 +13,7 @@
#include "base/check_op.h"
#include "base/logging.h"
#include "crypto_utils/aes_cbc_decryptor.h"
#include "crypto_utils/aes_cbc_encryptor.h"
#include "crypto_utils/aes_ctr_encryptor.h"
#include "crypto_utils/crypto_util.h"
#include "crypto_utils/rsa_key.h"
@@ -40,6 +41,7 @@
namespace {
using AesCbcDecryptor = widevine::AesCbcDecryptor;
using AesCbcEncryptor = widevine::AesCbcEncryptor;
using AesCtrDecryptor = widevine::AesCtrEncryptor;
using KeyContainer = video_widevine::License_KeyContainer;
using RsaPrivateKey = widevine::RsaPrivateKey;
@@ -113,6 +115,7 @@ struct WB_License_Whitebox {
std::map<std::string, widevine::InternalKey> content_keys;
std::map<std::string, widevine::InternalKey> entitlement_keys;
std::map<std::string, widevine::InternalKey> generic_keys;
std::vector<widevine::LicenseParser::ProviderKey> provider_keys;
};
@@ -495,6 +498,7 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
whitebox->content_keys = parser->GetContentKeys();
whitebox->entitlement_keys = parser->GetEntitlementKeys();
whitebox->generic_keys = parser->GetGenericKeys();
whitebox->initialized = true;
@@ -561,6 +565,30 @@ WB_Result WB_License_LoadEntitledContentKey(WB_License_Whitebox* whitebox,
return WB_RESULT_OK;
}
WB_Result WB_License_RemoveEntitledContentKey(WB_License_Whitebox* whitebox,
const uint8_t* content_key_id,
size_t content_key_id_size) {
if (!whitebox || !content_key_id) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (!whitebox->initialized) {
DVLOG(1) << "Invalid state: no license loaded.";
return WB_RESULT_INVALID_STATE;
}
if (whitebox->entitlement_keys.empty()) {
DVLOG(1) << "Invalid state: can only remove when using entitlement keys.";
return WB_RESULT_INVALID_STATE;
}
if (whitebox->content_keys.erase(MakeString(content_key_id,
content_key_id_size)) == 0) {
DVLOG(1) << "Content key not found.";
return WB_RESULT_KEY_UNAVAILABLE;
}
return WB_RESULT_OK;
}
WB_Result WB_License_QueryKeyStatus(const WB_License_Whitebox* whitebox,
WB_KeyQueryType type,
@@ -587,6 +615,27 @@ WB_Result WB_License_QueryKeyStatus(const WB_License_Whitebox* whitebox,
return WB_RESULT_OK;
}
case WB_KEY_QUERY_TYPE_GENERIC_KEY: {
if (key_id == nullptr) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (key_id_size == 0) {
DVLOG(1) << "Invalid parameter: array size 0.";
return WB_RESULT_INVALID_PARAMETER;
}
auto it = whitebox->generic_keys.find({key_id, key_id + key_id_size});
if (it == whitebox->generic_keys.end()) {
return WB_RESULT_KEY_UNAVAILABLE;
}
*key_status = it->second.status;
return WB_RESULT_OK;
}
case WB_KEY_QUERY_TYPE_CONTENT_KEY: {
if (key_id == nullptr) {
DVLOG(1) << "Invalid parameter: null pointer.";
@@ -740,6 +789,9 @@ WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox,
size_t key_id_size,
uint8_t* secret_string,
size_t* secret_string_size) {
#ifdef ALWAYS_DECRYPT_TO_CLEAR
return WB_RESULT_NOT_IMPLEMENTED;
#else
if (!whitebox || !key_id || !secret_string_size) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
@@ -787,12 +839,213 @@ WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox,
if (!content_key->can_masked_decrypt()) {
DVLOG(1) << "Insufficient security level: key policy does not allow use "
"with MaskedDecrypt().";
return WB_RESULT_INSUFFICIENT_SECURITY_LEVEL;
return WB_RESULT_INSUFFICIENT_PERMISSIONS;
}
CHECK(widevine::MemCopy(secret_pattern.data(), secret_pattern.size(),
secret_string, *secret_string_size));
return WB_RESULT_OK;
#endif
}
WB_Result WB_License_GenericEncrypt(const WB_License_Whitebox* whitebox,
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) {
if (!whitebox || !key_id || !output_data_size) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (!CheckAndUpdateSize(input_data_size, output_data_size)) {
return WB_RESULT_BUFFER_TOO_SMALL;
}
if (!whitebox->initialized) {
DVLOG(1) << "Invalid state: no license loaded.";
return WB_RESULT_INVALID_STATE;
}
if (key_id_size == 0) {
DVLOG(1) << "Invalid parameter: array size 0.";
return WB_RESULT_INVALID_PARAMETER;
}
auto it = whitebox->generic_keys.find({key_id, key_id + key_id_size});
if (it == whitebox->generic_keys.end()) {
DVLOG(1) << "Generic crypto key not found.";
return WB_RESULT_KEY_UNAVAILABLE;
}
if (!it->second.is_valid()) {
DVLOG(1) << "Generic crypto key not valid.";
return WB_RESULT_KEY_UNAVAILABLE;
}
if (!(it->second.kcb_flags & WB_KCB_FLAGS_ALLOW_ENCRYPT)) {
return WB_RESULT_INSUFFICIENT_PERMISSIONS;
}
AesCbcEncryptor encryptor;
if (!encryptor.SetKey(it->second.key.data(), 16u)) {
DVLOG(1) << "Error setting AES key.";
return WB_RESULT_INVALID_STATE;
}
if (!encryptor.Encrypt(iv, iv_size, input_data, input_data_size,
output_data)) {
DVLOG(1) << "Error encrypting data.";
return WB_RESULT_INVALID_PARAMETER;
}
return WB_RESULT_OK;
}
WB_Result WB_License_GenericDecrypt(const WB_License_Whitebox* whitebox,
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) {
if (!whitebox || !key_id || !output_data_size) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (!CheckAndUpdateSize(input_data_size, output_data_size)) {
return WB_RESULT_BUFFER_TOO_SMALL;
}
if (!whitebox->initialized) {
DVLOG(1) << "Invalid state: no license loaded.";
return WB_RESULT_INVALID_STATE;
}
if (key_id_size == 0) {
DVLOG(1) << "Invalid parameter: array size 0.";
return WB_RESULT_INVALID_PARAMETER;
}
auto it = whitebox->generic_keys.find({key_id, key_id + key_id_size});
if (it == whitebox->generic_keys.end()) {
DVLOG(1) << "Generic crypto key not found.";
return WB_RESULT_KEY_UNAVAILABLE;
}
if (!it->second.is_valid()) {
DVLOG(1) << "Generic crypto key not valid.";
return WB_RESULT_KEY_UNAVAILABLE;
}
if (!(it->second.kcb_flags & WB_KCB_FLAGS_ALLOW_DECRYPT)) {
return WB_RESULT_INSUFFICIENT_PERMISSIONS;
}
AesCbcDecryptor decryptor;
if (!decryptor.SetKey(it->second.key.data(), 16u)) {
DVLOG(1) << "Error setting AES key.";
return WB_RESULT_INVALID_STATE;
}
if (!decryptor.Decrypt(iv, iv_size, input_data, input_data_size,
output_data)) {
DVLOG(1) << "Error decrypting data.";
return WB_RESULT_INVALID_PARAMETER;
}
return WB_RESULT_OK;
}
WB_Result WB_License_GenericSign(const WB_License_Whitebox* whitebox,
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) {
if (!whitebox || !key_id || !message || !output_data_size) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (!CheckAndUpdateSize(widevine::crypto_util::kSha256HmacSizeBytes,
output_data_size)) {
return WB_RESULT_BUFFER_TOO_SMALL;
}
if (!output_data) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (!whitebox->initialized) {
DVLOG(1) << "Invalid state: no license loaded.";
return WB_RESULT_INVALID_STATE;
}
if (key_id_size == 0) {
DVLOG(1) << "Invalid parameter: array size 0.";
return WB_RESULT_INVALID_PARAMETER;
}
auto it = whitebox->generic_keys.find({key_id, key_id + key_id_size});
if (it == whitebox->generic_keys.end()) {
DVLOG(1) << "Generic crypto key not found.";
return WB_RESULT_KEY_UNAVAILABLE;
}
if (!it->second.is_valid()) {
DVLOG(1) << "Generic crypto key not valid.";
return WB_RESULT_KEY_UNAVAILABLE;
}
if (!(it->second.kcb_flags & WB_KCB_FLAGS_ALLOW_SIGN)) {
return WB_RESULT_INSUFFICIENT_PERMISSIONS;
}
std::string result = widevine::crypto_util::CreateSignatureHmacSha256(
MakeString(it->second.key.data(), it->second.key.size()),
MakeString(message, message_size));
memcpy(output_data, result.data(), result.size());
return WB_RESULT_OK;
}
WB_Result WB_License_GenericVerify(const WB_License_Whitebox* whitebox,
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) {
if (!whitebox || !key_id || !message || !signature) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (!whitebox->initialized) {
DVLOG(1) << "Invalid state: no license loaded.";
return WB_RESULT_INVALID_STATE;
}
if (key_id_size == 0) {
DVLOG(1) << "Invalid parameter: array size 0.";
return WB_RESULT_INVALID_PARAMETER;
}
auto it = whitebox->generic_keys.find({key_id, key_id + key_id_size});
if (it == whitebox->generic_keys.end()) {
DVLOG(1) << "Generic crypto key not found.";
return WB_RESULT_KEY_UNAVAILABLE;
}
if (!it->second.is_valid()) {
DVLOG(1) << "Generic crypto key not valid.";
return WB_RESULT_KEY_UNAVAILABLE;
}
if (!(it->second.kcb_flags & WB_KCB_FLAGS_ALLOW_VERIFY)) {
return WB_RESULT_INSUFFICIENT_PERMISSIONS;
}
if (!widevine::crypto_util::VerifySignatureHmacSha256(
MakeString(it->second.key.data(), it->second.key.size()),
MakeString(signature, signature_size),
MakeString(message, message_size))) {
return WB_RESULT_INVALID_SIGNATURE;
}
return WB_RESULT_OK;
}
WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox,
@@ -835,7 +1088,7 @@ WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox,
if (!content_key->can_decrypt()) {
DVLOG(1) << "Insufficient security level: key policy does not allow use "
"with Decrypt().";
return WB_RESULT_INSUFFICIENT_SECURITY_LEVEL;
return WB_RESULT_INSUFFICIENT_PERMISSIONS;
}
// DecryptBuffer() will validate the remaining decryption parameters.
@@ -854,6 +1107,9 @@ WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox,
size_t iv_size,
uint8_t* masked_output_data,
size_t* masked_output_data_size) {
#ifdef ALWAYS_DECRYPT_TO_CLEAR
return WB_RESULT_NOT_IMPLEMENTED;
#else
if (!whitebox || !key_id || !masked_output_data || !masked_output_data_size) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
@@ -884,7 +1140,7 @@ WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox,
if (!content_key->can_masked_decrypt()) {
DVLOG(1) << "Insufficient security level: key policy does not allow use "
"with MaskedDecrypt().";
return WB_RESULT_INSUFFICIENT_SECURITY_LEVEL;
return WB_RESULT_INSUFFICIENT_PERMISSIONS;
}
// DecryptBuffer() will validate all the parameters, so just make sure it is
@@ -914,6 +1170,7 @@ WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox,
}
return WB_RESULT_OK;
#endif
}
void WB_License_Unmask(const uint8_t* masked_data,

View File

@@ -9,9 +9,10 @@
namespace widevine {
namespace {
bool ExtractLevel(
bool ExtractKcbFields(
const std::string& key_control_block,
video_widevine::License_KeyContainer_SecurityLevel* security_level) {
video_widevine::License_KeyContainer_SecurityLevel* security_level,
uint32_t* kcb_flags) {
// The key control block is an 128 bit structure containing the following
// fields. The fields are defined to be in big-endian byte order.
//
@@ -33,8 +34,12 @@ bool ExtractLevel(
return false;
}
auto* kcb = reinterpret_cast<const uint8_t*>(key_control_block.data());
*kcb_flags = (kcb[12] << 24u) | (kcb[13] << 16u) | (kcb[14] << 8u) | kcb[15];
// Extract bits 26..27 from Control Bits.
switch ((key_control_block[12] & 0x0C) >> 2) {
switch ((*kcb_flags & WB_KCB_FLAGS_SECURITY_LEVEL_MASK) >>
WB_KCB_FLAGS_SECURITY_LEVEL_SHIFT) {
case 0:
*security_level =
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO;
@@ -94,11 +99,17 @@ WB_Result OdkLicenseParser::Parse(const std::string& decryption_key,
// Add the key right away. The key will be invalid, so if we fail to
// parse the key, we'll already have an entry for the invalid key.
switch (odk_context.license.license_type) {
case OEMCrypto_ContentLicense:
content_keys_[key_id] = ParseInternalKey(
case OEMCrypto_ContentLicense: {
auto temp_key = ParseInternalKey(
KeyType::kContentKey, decryption_key, message, key, provider_keys,
provider_key_id);
if (temp_key.type == KeyType::kGenericCryptoKey) {
generic_keys_[key_id] = temp_key;
} else {
content_keys_[key_id] = temp_key;
}
break;
}
case OEMCrypto_EntitlementLicense:
entitlement_keys_[key_id] = ParseInternalKey(
KeyType::kEntitlementKey, decryption_key, message, key,
@@ -128,6 +139,11 @@ OdkLicenseParser::GetEntitlementKeys() const {
return entitlement_keys_;
}
const std::map<std::string, InternalKey>&
OdkLicenseParser::GetGenericKeys() const {
return generic_keys_;
}
RenewalKey OdkLicenseParser::ParseSigningKeys(const std::string& decryption_key,
const std::string& key,
const std::string& iv) const {
@@ -176,6 +192,19 @@ InternalKey OdkLicenseParser::ParseInternalKey(
// This should have been verified before calling the parser.
CHECK_EQ(decryption_key.size(), 16u) << "Incorrect decryption key size.";
const std::string key_control_block = ExtractItem(key.key_control, message);
if (key_control_block.empty()) {
VLOG(3) << "Empty key control block.";
return InternalKey();
}
video_widevine::License_KeyContainer_SecurityLevel security_level;
uint32_t kcb_flags;
if (!ExtractKcbFields(key_control_block, &security_level, &kcb_flags)) {
VLOG(3) << "Invalid KCB.";
return InternalKey();
}
const std::string iv = ExtractItem(key.key_data_iv, message);
if (iv.size() != 16u) {
@@ -186,8 +215,23 @@ InternalKey OdkLicenseParser::ParseInternalKey(
std::string wrapped_key = ExtractItem(key.key_data, message);
// Unlike with protobufs, we don't need to handle padding here. The ODK will
// not include the padding as part of the key's size.
const size_t key_size = key_type == KeyType::kEntitlementKey ? 32u : 16u;
// not include the padding as part of the key's size. Additionally, generic
// keys look like content keys, but can have either 16 or 32 byte key.
size_t key_size;
if (kcb_flags & WB_KCB_FLAGS_GENERIC_MASK) {
const bool is_aes =
kcb_flags & (WB_KCB_FLAGS_ALLOW_ENCRYPT | WB_KCB_FLAGS_ALLOW_DECRYPT);
const bool is_hmac =
kcb_flags & (WB_KCB_FLAGS_ALLOW_SIGN | WB_KCB_FLAGS_ALLOW_VERIFY);
if (is_aes && is_hmac) {
VLOG(3) << "Cannot use both encrypt/decrypt and sign/verify";
return InternalKey();
}
key_type = KeyType::kGenericCryptoKey;
key_size = is_aes ? 16u : 32u;
} else {
key_size = key_type == KeyType::kContentKey ? 16u : 32u;
}
if (wrapped_key.size() != key_size) {
VLOG(3) << "Invalid key size (" << wrapped_key.size() << ").";
return InternalKey();
@@ -200,22 +244,13 @@ InternalKey OdkLicenseParser::ParseInternalKey(
return InternalKey();
}
const std::string key_control_block = ExtractItem(key.key_control, message);
if (key_control_block.empty()) {
VLOG(3) << "Empty key control block.";
return InternalKey();
}
video_widevine::License_KeyContainer_SecurityLevel security_level;
CHECK(ExtractLevel(key_control_block, &security_level));
// When the platform is hardware verified, all keys are unlocked and are
// available to be used with either decrypt function. The license server
// adjusts the level returned inside the key control block to handle
// this.
const bool is_hw_verified = false;
return CreateInternalKey(
key_type, security_level, is_hw_verified, unwrapped_key);
key_type, security_level, is_hw_verified, unwrapped_key, kcb_flags);
}
} // namespace widevine

View File

@@ -22,6 +22,7 @@ class OdkLicenseParser : public LicenseParser {
const std::map<std::string, InternalKey>& GetContentKeys() const override;
const std::map<std::string, InternalKey>& GetEntitlementKeys() const override;
const std::map<std::string, InternalKey>& GetGenericKeys() const override;
private:
RenewalKey ParseSigningKeys(const std::string& decryption_key,
@@ -39,6 +40,7 @@ class OdkLicenseParser : public LicenseParser {
std::vector<widevine::RenewalKey> renewal_keys_;
std::map<std::string, InternalKey> content_keys_;
std::map<std::string, InternalKey> entitlement_keys_;
std::map<std::string, InternalKey> generic_keys_;
};
} // namespace widevine

View File

@@ -149,6 +149,12 @@ ProtobufLicenseParser::GetEntitlementKeys() const {
return entitlement_keys_;
}
const std::map<std::string, InternalKey>&
ProtobufLicenseParser::GetGenericKeys() const {
static std::map<std::string, InternalKey> ret;
return ret;
}
RenewalKey ProtobufLicenseParser::ParseSigningKey(
const std::string& decryption_key,
const video_widevine::License_KeyContainer& key) const {

View File

@@ -22,6 +22,8 @@ class ProtobufLicenseParser : public LicenseParser {
const std::map<std::string, InternalKey>& GetContentKeys() const override;
const std::map<std::string, InternalKey>&
GetEntitlementKeys() const override;
const std::map<std::string, InternalKey>&
GetGenericKeys() const override;
RenewalKey ParseSigningKey(
const std::string& decryption_key,