Encrypted Key Control Block

This change updates the external copy of the reference to match the
internal copy at commit cda42fa07b533f8aad3183cd7eb99ce553949f88 which
introduces the tests (and fix) to handle an encrypted key block.
This commit is contained in:
Aaron Vaage
2021-01-14 17:02:28 -08:00
parent 8ff9df8eeb
commit c1d449e809
29 changed files with 763 additions and 436 deletions

View File

@@ -70,7 +70,7 @@ http_archive(
new_git_repository(
name = "odk_repo",
build_file = "@whitebox_api_repo//external:odk.BUILD",
commit = "bee799748752fac84d9c3ecd549aa54f72c88d02",
commit = "565237f8e6900e467eb236040374428387e90bd0",
remote = "https://widevine-partner.googlesource.com/oemcrypto_core_message.git",
repo_mapping = {"@whitebox" : "@whitebox_api_repo"}
)

View File

@@ -70,7 +70,7 @@ http_archive(
new_git_repository(
name = "odk_repo",
build_file = "@whitebox_api_repo//external:odk.BUILD",
commit = "bee799748752fac84d9c3ecd549aa54f72c88d02",
commit = "565237f8e6900e467eb236040374428387e90bd0",
remote = "https://widevine-partner.googlesource.com/oemcrypto_core_message.git",
repo_mapping = {"@whitebox" : "@whitebox_api_repo"}
)

1
whitebox/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
bazel-*

View File

@@ -65,7 +65,7 @@ http_archive(
new_git_repository(
name = "odk_repo",
build_file = "//external:odk.BUILD",
commit = "bee799748752fac84d9c3ecd549aa54f72c88d02",
commit = "565237f8e6900e467eb236040374428387e90bd0",
remote = "https://widevine-partner.googlesource.com/oemcrypto_core_message.git",
)

View File

@@ -32,6 +32,14 @@ cc_library(
],
)
cc_library(
name = "test_key_types",
testonly = True,
hdrs = [
"test_key_types.h",
],
)
cc_library(
name = "test_public_key",
testonly = True,
@@ -60,6 +68,7 @@ cc_library(
"golden_data.h",
],
deps = [
":test_key_types",
"//chromium_deps/cdm/protos:license_protocol_proto",
],
)
@@ -71,6 +80,7 @@ cc_library(
hdrs = ["test_license_builder.h"],
visibility = ["//visibility:public"],
deps = [
":test_key_types",
"//chromium_deps/cdm/keys:dev_certs",
"//chromium_deps/cdm/protos:license_protocol_proto",
"//crypto_utils:aes_cbc_encryptor",
@@ -126,6 +136,7 @@ cc_library(
"license_whitebox_get_secret_string_test.cc",
"license_whitebox_masked_decrypt_test.cc",
"license_whitebox_process_license_response_core_message_test.cc",
"license_whitebox_process_license_response_with_encrypted_key_control_block.cc",
"license_whitebox_process_license_response_test.cc",
"license_whitebox_sign_license_request_test.cc",
"license_whitebox_sign_renewal_request_test.cc",
@@ -137,7 +148,6 @@ cc_library(
],
visibility = ["//visibility:public"],
deps = [
":aead_test_data",
":golden_data",
":license_whitebox",
":test_license_builder",
@@ -165,8 +175,8 @@ cc_library(
],
visibility = ["//visibility:public"],
deps = [
":aead_test_data",
":license_whitebox",
":test_key_types",
":test_license_builder",
":test_public_key",
"//benchmarking:data_source",

View File

@@ -83,10 +83,9 @@ GoldenData::GoldenData() {
};
}
void GoldenData::MakeKeyIdDifferent(std::vector<uint8_t>* key_id) const {
// All our internal key ids start with 0xFF, so pushing something that is not
// 0xFF to the front will ensure that they don't collide.
key_id->insert(key_id->begin(), 0xAB);
KeyId GoldenData::GetFreeId() {
// All our internal key ids start with 0xFF, so starting with 0xAB should
// avoid conflicts.
return {0xAB, 0, 0, next_id_++};
}
} // namespace widevine

View File

@@ -3,10 +3,11 @@
#ifndef WHITEBOX_API_GOLDEN_DATA_H_
#define WHITEBOX_API_GOLDEN_DATA_H_
#include <stdint.h>
#include <cstdint>
#include <memory>
#include <vector>
#include "api/test_key_types.h"
#include "cdm/protos/license_protocol.pb.h"
namespace widevine {
@@ -16,13 +17,13 @@ class GoldenData {
struct Content {
std::vector<uint8_t> plaintext;
std::vector<uint8_t> ciphertext;
std::vector<uint8_t> key;
std::vector<uint8_t> iv;
AesKey key;
AesIv iv;
};
struct Key {
video_widevine::License_KeyContainer_SecurityLevel level;
std::vector<uint8_t> id;
KeyId id;
const Content* content;
};
@@ -38,11 +39,7 @@ class GoldenData {
const Key& CTRDecodeKey() const { return ctr_decode_key_; }
const Key& CTRHardwareKey() const { return ctr_hardware_key_; }
// When a test needs to define a key id that does not conflict with any key
// ids defined in the golden data, it should use this to update their key id
// by prepending a single byte to ensure it won't collide with any of the
// internal key ids.
void MakeKeyIdDifferent(std::vector<uint8_t>* key_id) const;
KeyId GetFreeId();
private:
Content cbc_content_;
@@ -54,6 +51,8 @@ class GoldenData {
Key ctr_crypto_key_;
Key ctr_decode_key_;
Key ctr_hardware_key_;
uint8_t next_id_ = 0;
};
} // namespace widevine

View File

@@ -2,9 +2,8 @@
#include "api/license_whitebox_benchmark.h"
#include <stddef.h>
#include <stdint.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <vector>
@@ -21,9 +20,9 @@ constexpr size_t kBlockSize = 16; // This must align with the AES block size.
} // namespace
void LicenseWhiteboxBenchmark::SetUp() {
key_id_ = data_source_.Get(8); // The id size is not meaningful.
key_ = data_source_.Get(kBlockSize);
iv_ = data_source_.Get(kBlockSize);
key_id_ = data_source_.Get<4>(); // We use size=4 for all our test key ids.
key_ = data_source_.Get<kBlockSize>();
iv_ = data_source_.Get<kBlockSize>();
const auto public_key_data = GetLicensePublicKey();
public_key_.reset(widevine::RsaPublicKey::Create(
@@ -33,13 +32,12 @@ void LicenseWhiteboxBenchmark::SetUp() {
License LicenseWhiteboxBenchmark::CreateLicense() const {
widevine::TestLicenseBuilder license_builder;
license_builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey(),
TestLicenseBuilder::NoPadding());
license_builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey());
// Use secure crypto as it will work with both Decrypt() and
// MaskedDecrypt().
license_builder.AddContentKey(
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO,
key_id_, key_, TestLicenseBuilder::NoPadding());
key_id_, key_);
widevine::License license;
license_builder.Build(*public_key_, &license);

View File

@@ -9,6 +9,7 @@
#include <vector>
#include "api/license_whitebox.h"
#include "api/test_key_types.h"
#include "api/test_license_builder.h"
#include "benchmarking/data_source.h"
#include "crypto_utils/rsa_key.h"
@@ -27,19 +28,19 @@ class LicenseWhiteboxBenchmark : public ::testing::Test {
const RsaPublicKey* PublicKey() const { return public_key_.get(); }
const std::vector<uint8_t>& ContentKeyId() const { return key_id_; }
const KeyId& ContentKeyId() const { return key_id_; }
const std::vector<uint8_t>& ContentKey() const { return key_; }
const AesKey& ContentKey() const { return key_; }
const std::vector<uint8_t>& ContentIV() const { return iv_; }
const AesIv& ContentIV() const { return iv_; }
private:
DataSource data_source_;
std::unique_ptr<RsaPublicKey> public_key_;
std::vector<uint8_t> key_id_;
std::vector<uint8_t> key_;
std::vector<uint8_t> iv_;
KeyId key_id_;
AesKey key_;
AesIv iv_;
};
} // namespace widevine

View File

@@ -56,21 +56,18 @@ class LicenseWhiteboxChromeOSTest
// Only use CBC keys so that we can always use the CBC content.
builder.AddContentKey(golden_data_.CBCCryptoKey().level,
golden_data_.CBCCryptoKey().id,
golden_data_.CBCCryptoKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CBCCryptoKey().content->key);
builder.AddContentKey(golden_data_.CBCDecodeKey().level,
golden_data_.CBCDecodeKey().id,
golden_data_.CBCDecodeKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CBCDecodeKey().content->key);
builder.AddContentKey(golden_data_.CBCHardwareKey().level,
golden_data_.CBCHardwareKey().id,
golden_data_.CBCHardwareKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CBCHardwareKey().content->key);
builder.SetRemoteAttestation(remote_attestation_);
builder.SetVerificationStatus(verification_status_);
builder.GetSettings().remote_attestation = remote_attestation_;
builder.GetSettings().verification_status = verification_status_;
License license;
builder.Build(*public_key_, &license);

View File

@@ -25,28 +25,29 @@ class LicenseWhiteboxDecryptTest : public LicenseWhiteboxTestBase {
golden_data_.CTRContent().ciphertext.size());
plaintext_.resize(plaintext_size_);
golden_data_.MakeKeyIdDifferent(&non_content_key_id_);
golden_data_.MakeKeyIdDifferent(&missing_key_id_);
non_content_key_id_ = golden_data_.GetFreeId();
missing_key_id_ = golden_data_.GetFreeId();
}
void LoadLicense(const std::vector<uint8_t>& padding) {
void LoadLicense(TestLicenseBuilder::Padding padding) {
TestLicenseBuilder builder;
builder.GetSettings().padding = padding;
builder.AddContentKey(golden_data_.CBCCryptoKey().level,
golden_data_.CBCCryptoKey().id,
golden_data_.CBCCryptoKey().content->key, padding);
golden_data_.CBCCryptoKey().content->key);
builder.AddContentKey(golden_data_.CTRCryptoKey().level,
golden_data_.CTRCryptoKey().id,
golden_data_.CTRCryptoKey().content->key, padding);
golden_data_.CTRCryptoKey().content->key);
builder.AddContentKey(golden_data_.CBCDecodeKey().level,
golden_data_.CBCDecodeKey().id,
golden_data_.CBCDecodeKey().content->key, padding);
golden_data_.CBCDecodeKey().content->key);
builder.AddContentKey(golden_data_.CBCHardwareKey().level,
golden_data_.CBCHardwareKey().id,
golden_data_.CBCHardwareKey().content->key, padding);
golden_data_.CBCHardwareKey().content->key);
builder.AddOperatorSessionKey(non_content_key_id_);
@@ -65,8 +66,8 @@ class LicenseWhiteboxDecryptTest : public LicenseWhiteboxTestBase {
// We need two special keys for this test, one that will be used for a
// non-content key and one that will never be in the license.
std::vector<uint8_t> non_content_key_id_ = {0, 0, 0};
std::vector<uint8_t> missing_key_id_ = {1, 0, 0};
KeyId non_content_key_id_;
KeyId missing_key_id_;
// This is the buffer used to store the output of each decrypt call.
size_t plaintext_size_;
@@ -74,7 +75,7 @@ class LicenseWhiteboxDecryptTest : public LicenseWhiteboxTestBase {
};
TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCbcDataInCbcMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -91,7 +92,7 @@ TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCbcDataInCbcMode) {
}
TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCtrDataInCtrMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CTR,
@@ -110,7 +111,7 @@ TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCtrDataInCtrMode) {
// We try to decrypt CBC encrypted data in CTR mode. All operations should be
// successful, but the resulting plaintext should not match.
TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCbcDataInCtrMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CTR,
@@ -129,7 +130,7 @@ TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCbcDataInCtrMode) {
// We try to decrypt CTR encrypted data in CBC mode. All operations should be
// successful, but the resulting plaintext should not match.
TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCtrDataInCbcMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -146,7 +147,7 @@ TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCtrDataInCbcMode) {
}
TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCbcDataAndPKCS8Padding) {
LoadLicense(TestLicenseBuilder::PKSC8Padding());
LoadLicense(TestLicenseBuilder::Padding::kPKSC8);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -163,7 +164,7 @@ TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCbcDataAndPKCS8Padding) {
}
TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCtrDataAndPKCS8Padding) {
LoadLicense(TestLicenseBuilder::PKSC8Padding());
LoadLicense(TestLicenseBuilder::Padding::kPKSC8);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CTR,
@@ -182,7 +183,7 @@ TEST_F(LicenseWhiteboxDecryptTest, CryptoKeyWithCtrDataAndPKCS8Padding) {
// Try decrypting two different sets of content to make sure that two
// different keys can be used at the same time.
TEST_F(LicenseWhiteboxDecryptTest, SuccessWithMultipleKeys) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -218,7 +219,7 @@ TEST_F(LicenseWhiteboxDecryptTest, SuccessWithMultipleKeys) {
}
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullWhitebox) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(nullptr, WB_CIPHER_MODE_CBC,
@@ -233,7 +234,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullWhitebox) {
}
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForInvalidCipherMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
// In order to trick the compiler into letting us pass an invalid enum value
// to WB__License_Decrypt(), we need to cast it. If we don't do this, the
@@ -252,7 +253,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForInvalidCipherMode) {
}
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullKeyId) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC, nullptr,
@@ -266,7 +267,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullKeyId) {
}
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForZeroKeyIdSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -280,7 +281,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForZeroKeyIdSize) {
}
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullInputData) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -296,7 +297,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullInputData) {
// AES CBC requires that the input be block aligned (multiple of 16). CTR does
// not care.
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForInvalidCBCInputDataSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -311,7 +312,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForInvalidCBCInputDataSize) {
// The white-box (using any cipher mode) should reject input with size zero.
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForZeroInputDataSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -325,7 +326,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForZeroInputDataSize) {
}
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullIV) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(
@@ -340,7 +341,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullIV) {
// IV size should be 16. Any number other than 16 should fail.
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForInvalidIVSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -354,7 +355,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForInvalidIVSize) {
}
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullOutput) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -369,7 +370,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullOutput) {
}
TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullOutputSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -387,7 +388,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InvalidParameterForNullOutputSize) {
// in the license to start with. This is different than "non content key"
// and "dropped content key", as those keys were in the license but ignored.
TEST_F(LicenseWhiteboxDecryptTest, KeyUnavailableForMissingKeyId) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC, missing_key_id_.data(),
@@ -401,7 +402,7 @@ TEST_F(LicenseWhiteboxDecryptTest, KeyUnavailableForMissingKeyId) {
}
TEST_F(LicenseWhiteboxDecryptTest, KeyUnavailableForNonContentKey) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
@@ -418,7 +419,7 @@ TEST_F(LicenseWhiteboxDecryptTest, KeyUnavailableForNonContentKey) {
// to this rule is on ChromeOS with a special license.
TEST_F(LicenseWhiteboxDecryptTest,
InsufficientSecurityLevelForHardwareContentKey) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_Decrypt(
whitebox_, WB_CIPHER_MODE_CBC,
@@ -433,7 +434,7 @@ TEST_F(LicenseWhiteboxDecryptTest,
}
TEST_F(LicenseWhiteboxDecryptTest, InsufficientSecurityLevelForDecodeKey) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
// Use the software decode key as they are limited to
// WB_License_Decrypt().
@@ -450,7 +451,7 @@ TEST_F(LicenseWhiteboxDecryptTest, InsufficientSecurityLevelForDecodeKey) {
}
TEST_F(LicenseWhiteboxDecryptTest, BufferTooSmall) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
// Our ciphertext will be large enough that we should not need to worry about
// using a constant here.

View File

@@ -23,8 +23,8 @@ class LicenseWhiteboxGetSecretStringTest : public LicenseWhiteboxTestBase {
secret_string_size_ = 256;
secret_string_.resize(secret_string_size_);
golden_data_.MakeKeyIdDifferent(&non_content_key_id_);
golden_data_.MakeKeyIdDifferent(&missing_key_id_);
non_content_key_id_ = golden_data_.GetFreeId();
missing_key_id_ = golden_data_.GetFreeId();
}
void LoadLicense() {
@@ -32,18 +32,15 @@ class LicenseWhiteboxGetSecretStringTest : public LicenseWhiteboxTestBase {
builder.AddContentKey(golden_data_.CBCCryptoKey().level,
golden_data_.CBCCryptoKey().id,
golden_data_.CBCCryptoKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CBCCryptoKey().content->key);
builder.AddContentKey(golden_data_.CBCDecodeKey().level,
golden_data_.CBCDecodeKey().id,
golden_data_.CBCDecodeKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CBCDecodeKey().content->key);
builder.AddContentKey(golden_data_.CBCHardwareKey().level,
golden_data_.CBCHardwareKey().id,
golden_data_.CBCHardwareKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CBCHardwareKey().content->key);
builder.AddOperatorSessionKey(non_content_key_id_);
@@ -62,8 +59,8 @@ class LicenseWhiteboxGetSecretStringTest : public LicenseWhiteboxTestBase {
// We need two special keys for this test, one that will be used for a
// non-content key and one that will never be in the license.
std::vector<uint8_t> non_content_key_id_ = {0, 0, 0};
std::vector<uint8_t> missing_key_id_ = {1, 0, 0};
KeyId non_content_key_id_;
KeyId missing_key_id_;
size_t secret_string_size_;
std::vector<uint8_t> secret_string_;

View File

@@ -8,11 +8,6 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace widevine {
// This must be defined by the implementation as they are implementation
// specific. They must be defined so that they work with the test key used to
// generate the license request.
extern const uint8_t kLicenseWhiteboxInitData[];
extern const size_t kLicenseWhiteboxInitDataSize;
namespace {

View File

@@ -32,37 +32,33 @@ class LicenseWhiteboxMaskedDecryptTest : public LicenseWhiteboxTestBase {
secret_string_size_ = masked_text_size_;
secret_string_.resize(secret_string_size_);
golden_data_.MakeKeyIdDifferent(&non_content_key_id_);
golden_data_.MakeKeyIdDifferent(&missing_key_id_);
non_content_key_id_ = golden_data_.GetFreeId();
missing_key_id_ = golden_data_.GetFreeId();
}
void LoadLicense(const std::vector<uint8_t>& padding) {
void LoadLicense(TestLicenseBuilder::Padding padding) {
TestLicenseBuilder builder;
builder.GetSettings().padding = padding;
builder.AddContentKey(golden_data_.CBCCryptoKey().level,
golden_data_.CBCCryptoKey().id,
golden_data_.CBCCryptoKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CBCCryptoKey().content->key);
builder.AddContentKey(golden_data_.CTRCryptoKey().level,
golden_data_.CTRCryptoKey().id,
golden_data_.CTRCryptoKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CTRCryptoKey().content->key);
builder.AddContentKey(golden_data_.CBCDecodeKey().level,
golden_data_.CBCDecodeKey().id,
golden_data_.CBCDecodeKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CBCDecodeKey().content->key);
builder.AddContentKey(golden_data_.CTRDecodeKey().level,
golden_data_.CTRDecodeKey().id,
golden_data_.CTRDecodeKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CTRDecodeKey().content->key);
builder.AddContentKey(golden_data_.CBCHardwareKey().level,
golden_data_.CBCHardwareKey().id,
golden_data_.CBCHardwareKey().content->key,
TestLicenseBuilder::NoPadding());
golden_data_.CBCHardwareKey().content->key);
builder.AddOperatorSessionKey(non_content_key_id_);
@@ -81,8 +77,8 @@ class LicenseWhiteboxMaskedDecryptTest : public LicenseWhiteboxTestBase {
// We need two special keys for this test, one that will be used for a
// non-content key and one that will never be in the license.
std::vector<uint8_t> non_content_key_id_ = {0, 0, 0};
std::vector<uint8_t> missing_key_id_ = {1, 0, 0};
KeyId non_content_key_id_;
KeyId missing_key_id_;
size_t secret_string_size_;
std::vector<uint8_t> secret_string_;
@@ -94,7 +90,7 @@ class LicenseWhiteboxMaskedDecryptTest : public LicenseWhiteboxTestBase {
};
TEST_F(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCbcDataInCbcMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -132,7 +128,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCbcDataInCbcMode) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCtrDataInCtrMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -172,7 +168,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCtrDataInCtrMode) {
// We try to decrypt CBC encrypted data in CTR mode. All operations should be
// successful, but the resulting plaintext should not match.
TEST_F(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCbcDataInCtrMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -211,7 +207,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCbcDataInCtrMode) {
// We try to decrypt CTR encrypted data in CBC mode. All operations should be
// successful, but the resulting plaintext should not match.
TEST_F(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCtrDataInCbcMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -248,7 +244,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, DecodeKeyWithCtrDataInCbcMode) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataInCbcMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -286,7 +282,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataInCbcMode) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataInCtrMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -326,7 +322,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataInCtrMode) {
// We try to decrypt CBC encrypted data in CTR mode. All operations should be
// successful, but the resulting plaintext should not match.
TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataInCtrMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -365,7 +361,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataInCtrMode) {
// We try to decrypt CTR encrypted data in CBC mode. All operations should be
// successful, but the resulting plaintext should not match.
TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataInCbcMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -402,7 +398,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataInCbcMode) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataAndPKCS8Padding) {
LoadLicense(TestLicenseBuilder::PKSC8Padding());
LoadLicense(TestLicenseBuilder::Padding::kPKSC8);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -440,7 +436,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCbcDataAndPKCS8Padding) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataAndPKCS8Padding) {
LoadLicense(TestLicenseBuilder::PKSC8Padding());
LoadLicense(TestLicenseBuilder::Padding::kPKSC8);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -483,7 +479,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, CryptoKeyWithCtrDataAndPKCS8Padding) {
// Since we have two CBC keys, try using the decode key and then the crypto
// key.
TEST_F(LicenseWhiteboxMaskedDecryptTest, SuccessWithMultipleKeys) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -563,7 +559,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, SuccessWithMultipleKeys) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullWhitebox) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -578,7 +574,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullWhitebox) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForInvalidCipherMode) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
// In order to trick the compiler into letting us pass an invalid enum value
// to WB__License_MaskedDecrypt(), we need to cast it. If we don't do this,
@@ -597,7 +593,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForInvalidCipherMode) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullKeyId) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC, nullptr,
@@ -611,7 +607,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullKeyId) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullZeroKeyIdSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -625,7 +621,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullZeroKeyIdSize) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullInputData) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -642,7 +638,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullInputData) {
// not care.
TEST_F(LicenseWhiteboxMaskedDecryptTest,
InvalidParameterForInvalidCBCInputDataSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -657,7 +653,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest,
// The white-box (using any cipher mode) should reject input with size zero.
TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForZeroInputDataSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -671,7 +667,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForZeroInputDataSize) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullIV) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -686,7 +682,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullIV) {
// IV size should be 16. Any number other than 16 should fail.
TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForInvalidIVSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -700,7 +696,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForInvalidIVSize) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullOutput) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -715,7 +711,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullOutput) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullOutputSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(
@@ -733,7 +729,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidParameterForNullOutputSize) {
// in the license to start with. This is different than "non content key"
// and "dropped content key", as those keys were in the license but ignored.
TEST_F(LicenseWhiteboxMaskedDecryptTest, KeyUnavailableForMissingKeyId) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC, missing_key_id_.data(),
@@ -747,7 +743,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, KeyUnavailableForMissingKeyId) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, KeyUnavailableForNonContentKey) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC, non_content_key_id_.data(),
@@ -764,7 +760,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, KeyUnavailableForNonContentKey) {
// to this rule is on ChromeOS with a special license.
TEST_F(LicenseWhiteboxMaskedDecryptTest,
InsufficientSecurityLevelForHardwareContentKey) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_MaskedDecrypt(
whitebox_, WB_CIPHER_MODE_CBC,
@@ -795,7 +791,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, InvalidState) {
}
TEST_F(LicenseWhiteboxMaskedDecryptTest, BufferTooSmall) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
// Our ciphertext will be large enough that we should not need to worry about
// using a constant here.
@@ -821,7 +817,7 @@ TEST_F(LicenseWhiteboxMaskedDecryptTest, BufferTooSmall) {
// Check that the result of unmasking only a small portion of the data is the
// same as when we unmask the whole buffer.
TEST_F(LicenseWhiteboxMaskedDecryptTest, SuccessForSubRangeUnmask) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_MaskedDecrypt(

View File

@@ -9,22 +9,29 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace widevine {
using OdkVersion = TestLicenseBuilder::OdkVersion;
class LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest
: public LicenseWhiteboxTestBase {
protected:
void UseLicenseWithoutSigningKey(bool use_odk) {
void UseLicenseWithoutSigningKey(OdkVersion odk_version) {
TestLicenseBuilder builder;
builder.GetSettings().odk_version = odk_version;
builder.AddStubbedContentKey();
builder.SetUseODK(use_odk);
builder.Build(*public_key_, &license_);
}
void UseLicenseWithSigningKey(const std::vector<uint8_t>& padding,
bool use_odk) {
void UseLicenseWithSigningKey(TestLicenseBuilder::Padding padding,
OdkVersion odk_version) {
TestLicenseBuilder builder;
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey(), padding);
builder.GetSettings().padding = padding;
builder.GetSettings().odk_version = odk_version;
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey());
builder.AddStubbedContentKey();
builder.SetUseODK(use_odk);
builder.Build(*public_key_, &license_);
}
@@ -35,8 +42,7 @@ class LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
SuccessWithoutOdkAndWithoutSigningKey) {
UseLicenseWithoutSigningKey(/* use_odk = */ false);
UseLicenseWithoutSigningKey(OdkVersion::kNone);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, license_.core_message.data(), license_.core_message.size(),
@@ -48,9 +54,21 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
}
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
SuccessWithOdkAndWithoutSigningKey) {
UseLicenseWithoutSigningKey(/* use_odk = */ true);
SuccessWithOdk16_3AndWithoutSigningKey) {
UseLicenseWithoutSigningKey(OdkVersion::k16_3);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, 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(),
license_.request.data(), license_.request.size()),
WB_RESULT_OK);
}
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
SuccessWithOdk16_5AndWithoutSigningKey) {
UseLicenseWithoutSigningKey(OdkVersion::k16_5);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, license_.core_message.data(), license_.core_message.size(),
@@ -63,9 +81,8 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
SuccessWithoutOdkAndWithSigningKeyNoPadding) {
UseLicenseWithSigningKey(TestLicenseBuilder::NoPadding(),
/* use_odk = */ false);
UseLicenseWithSigningKey(TestLicenseBuilder::Padding::kNone,
OdkVersion::kNone);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, license_.core_message.data(), license_.core_message.size(),
@@ -77,10 +94,23 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
}
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
SuccessWithOdkAndWithSigningKeyNoPadding) {
UseLicenseWithSigningKey(TestLicenseBuilder::NoPadding(),
/* use_odk = */ true);
SuccessWithOdk16_3AndWithSigningKeyNoPadding) {
UseLicenseWithSigningKey(TestLicenseBuilder::Padding::kNone,
OdkVersion::k16_3);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, 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(),
license_.request.data(), license_.request.size()),
WB_RESULT_OK);
}
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
SuccessWithOdk16_5AndWithSigningKeyNoPadding) {
UseLicenseWithSigningKey(TestLicenseBuilder::Padding::kNone,
OdkVersion::k16_5);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, license_.core_message.data(), license_.core_message.size(),
@@ -93,9 +123,8 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
SuccessWithoutOdkAndWithSigningKeyPKSC8Padding) {
UseLicenseWithSigningKey(TestLicenseBuilder::PKSC8Padding(),
/* use_odk = */ false);
UseLicenseWithSigningKey(TestLicenseBuilder::Padding::kPKSC8,
OdkVersion::kNone);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, license_.core_message.data(), license_.core_message.size(),
@@ -107,10 +136,23 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
}
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
SuccessWithOdkAndWithSigningKeyPKSC8Padding) {
UseLicenseWithSigningKey(TestLicenseBuilder::PKSC8Padding(),
/* use_odk = */ true);
SuccessWithOdk16_3AndWithSigningKeyPKSC8Padding) {
UseLicenseWithSigningKey(TestLicenseBuilder::Padding::kPKSC8,
OdkVersion::k16_3);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, 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(),
license_.request.data(), license_.request.size()),
WB_RESULT_OK);
}
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
SuccessWithOdk16_5AndWithSigningKeyPKSC8Padding) {
UseLicenseWithSigningKey(TestLicenseBuilder::Padding::kPKSC8,
OdkVersion::k16_5);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, license_.core_message.data(), license_.core_message.size(),
@@ -123,31 +165,33 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
InvalidParameterForNullCoreMessage) {
UseLicenseWithoutSigningKey(/* use_odk = */ true);
ASSERT_EQ(WB_License_ProcessLicenseResponse(
whitebox_, nullptr, license_.core_message.size(),
license_.message.data(), license_.message.size(),
license_.signature.data(), license_.signature.size(),
license_.session_key.data(), license_.session_key.size(),
license_.request.data(), license_.request.size()),
WB_RESULT_INVALID_PARAMETER);
UseLicenseWithoutSigningKey(OdkVersion::k16_5);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, /*core_message=*/nullptr, license_.core_message.size(),
license_.message.data(), license_.message.size(),
license_.signature.data(), license_.signature.size(),
license_.session_key.data(), license_.session_key.size(),
license_.request.data(), license_.request.size()),
WB_RESULT_INVALID_PARAMETER);
}
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
InvalidSignatureWithZeroCoreMessageSize) {
UseLicenseWithoutSigningKey(/* use_odk = */ true);
UseLicenseWithoutSigningKey(OdkVersion::k16_5);
// |core_message_size| = 0 means the core message is not provided, so
// no parameter check will be done. However, since the license was created
// with one, signature checking will fail as there is no core message
// to be included when checking the signature.
ASSERT_EQ(WB_License_ProcessLicenseResponse(
whitebox_, license_.core_message.data(), 0,
license_.message.data(), license_.message.size(),
license_.signature.data(), license_.signature.size(),
license_.session_key.data(), license_.session_key.size(),
license_.request.data(), license_.request.size()),
WB_RESULT_INVALID_SIGNATURE);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, license_.core_message.data(), /*core_message_size=*/0,
license_.message.data(), license_.message.size(),
license_.signature.data(), license_.signature.size(),
license_.session_key.data(), license_.session_key.size(),
license_.request.data(), license_.request.size()),
WB_RESULT_INVALID_SIGNATURE);
}
} // namespace widevine

View File

@@ -28,9 +28,11 @@ class LicenseWhiteboxProcessLicenseResponseTest
builder.Build(*public_key_, &license_);
}
void UseLicenseWithSigningKey(const std::vector<uint8_t>& padding) {
void UseLicenseWithSigningKey(TestLicenseBuilder::Padding padding) {
TestLicenseBuilder builder;
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey(), padding);
builder.GetSettings().padding = padding;
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey());
builder.AddStubbedContentKey();
builder.Build(*public_key_, &license_);
}
@@ -53,7 +55,7 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseTest, SuccessWithoutSigningKey) {
TEST_F(LicenseWhiteboxProcessLicenseResponseTest,
SuccessWithSigningKeyNoPadding) {
UseLicenseWithSigningKey(TestLicenseBuilder::NoPadding());
UseLicenseWithSigningKey(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
@@ -67,7 +69,7 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseTest,
TEST_F(LicenseWhiteboxProcessLicenseResponseTest,
SuccessWithSigningKeyPKSC8Padding) {
UseLicenseWithSigningKey(TestLicenseBuilder::PKSC8Padding());
UseLicenseWithSigningKey(TestLicenseBuilder::Padding::kPKSC8);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
@@ -82,10 +84,10 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseTest,
TEST_F(LicenseWhiteboxProcessLicenseResponseTest,
InvalidParameterWithMultipleSigningKeys) {
TestLicenseBuilder builder;
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey(),
TestLicenseBuilder::PKSC8Padding());
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey(),
TestLicenseBuilder::PKSC8Padding());
builder.GetSettings().padding = TestLicenseBuilder::Padding::kPKSC8;
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey());
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey());
builder.AddStubbedContentKey();
builder.Build(*public_key_, &license_);

View File

@@ -0,0 +1,60 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#include "api/license_whitebox.h"
#include "api/license_whitebox_test_base.h"
#include "api/test_license_builder.h"
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace widevine {
class LicenseWhiteboxProcessLicenseResponseWithEncryptedKeyControlBlockTest
: public LicenseWhiteboxTestBase,
public testing::WithParamInterface<
std::tuple<TestLicenseBuilder::KeyControlBlock,
TestLicenseBuilder::OdkVersion>> {
protected:
void SetUp() override {
LicenseWhiteboxTestBase::SetUp();
std::tie(kcb_, odk_) = GetParam();
}
TestLicenseBuilder::KeyControlBlock kcb_;
TestLicenseBuilder::OdkVersion odk_;
};
// Even though we are saying to use the ODK, since the key control block is
// encrypted, it should either decrypt the key control block or fallback to
// using protobuf parsing. It does not matter which method is used as long
// as it handles it.
TEST_P(LicenseWhiteboxProcessLicenseResponseWithEncryptedKeyControlBlockTest,
Success) {
TestLicenseBuilder builder;
builder.GetSettings().key_control_block = kcb_;
builder.GetSettings().odk_version = odk_;
builder.AddStubbedContentKey();
License license;
builder.Build(*public_key_, &license);
ASSERT_EQ(
WB_License_ProcessLicenseResponse(
whitebox_, 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(),
license.request.data(), license.request.size()),
WB_RESULT_OK);
}
INSTANTIATE_TEST_SUITE_P(
AllCombination,
LicenseWhiteboxProcessLicenseResponseWithEncryptedKeyControlBlockTest,
::testing::Combine(
::testing::Values(TestLicenseBuilder::KeyControlBlock::kClear,
TestLicenseBuilder::KeyControlBlock::kEncrypted),
::testing::Values(TestLicenseBuilder::OdkVersion::kNone,
TestLicenseBuilder::OdkVersion::k16_3,
TestLicenseBuilder::OdkVersion::k16_5)));
} // namespace widevine

View File

@@ -25,9 +25,11 @@ class LicenseWhiteboxSignRenewalRequestTest : public LicenseWhiteboxTestBase {
signature_.resize(signature_size_);
}
void LoadLicense(const std::vector<uint8_t>& padding) {
void LoadLicense(TestLicenseBuilder::Padding padding) {
TestLicenseBuilder builder;
builder.AddSigningKey(signing_key_, padding);
builder.GetSettings().padding = padding;
builder.AddSigningKey(signing_key_);
// Add a throw away key. We just need a key in the license since a license
// should always have a content key.
builder.AddStubbedContentKey();
@@ -61,7 +63,7 @@ class LicenseWhiteboxSignRenewalRequestTest : public LicenseWhiteboxTestBase {
const std::string session_key_ = "0123456789ABCDEF";
const std::vector<uint8_t> signing_key_ =
const std::array<uint8_t, 64> signing_key_ =
TestLicenseBuilder::DefaultSigningKey();
size_t signature_size_;
@@ -77,7 +79,7 @@ class LicenseWhiteboxSignRenewalRequestTest : public LicenseWhiteboxTestBase {
};
TEST_F(LicenseWhiteboxSignRenewalRequestTest, SuccessWithInvalidRequest) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(),
garbage_request_.size(),
@@ -90,7 +92,7 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest, SuccessWithInvalidRequest) {
TEST_F(LicenseWhiteboxSignRenewalRequestTest,
SuccessWithSigningKeyPKSC8Padding) {
LoadLicense(TestLicenseBuilder::PKSC8Padding());
LoadLicense(TestLicenseBuilder::Padding::kPKSC8);
ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(),
garbage_request_.size(),
@@ -102,7 +104,7 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest,
}
TEST_F(LicenseWhiteboxSignRenewalRequestTest, InvalidParameterForNullWhitebox) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_SignRenewalRequest(nullptr, garbage_request_.data(),
garbage_request_.size(),
@@ -111,7 +113,7 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest, InvalidParameterForNullWhitebox) {
}
TEST_F(LicenseWhiteboxSignRenewalRequestTest, InvalidParameterForNullMessage) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_SignRenewalRequest(whitebox_, nullptr, garbage_request_.size(),
@@ -121,7 +123,7 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest, InvalidParameterForNullMessage) {
TEST_F(LicenseWhiteboxSignRenewalRequestTest,
InvalidParameterForZeroMessageSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), 0,
signature_.data(), &signature_size_),
@@ -130,7 +132,7 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest,
TEST_F(LicenseWhiteboxSignRenewalRequestTest,
InvalidParameterForNullSignature) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(),
garbage_request_.size(), nullptr,
@@ -140,7 +142,7 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest,
TEST_F(LicenseWhiteboxSignRenewalRequestTest,
InvalidParameterForNullSignatureSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(),
garbage_request_.size(),
@@ -149,7 +151,7 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest,
}
TEST_F(LicenseWhiteboxSignRenewalRequestTest, BufferTooSmall) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
// We need the signature to be too small. While it would be possible to use
// zero, using a non-zero value ensures that we are not combining "empty" and

View File

@@ -22,14 +22,16 @@ class LicenseWhiteboxVerifyRenewalResponseTest
garbage_renewal_signature_ = Sign(garbage_renewal_message_);
}
void LoadLicense(const std::vector<uint8_t>& padding) {
void LoadLicense(TestLicenseBuilder::Padding padding) {
const auto signing_key = TestLicenseBuilder::DefaultSigningKey();
// We need a license so that we can always have a valid signature for our
// message(s), but don't load the license as some test will need no
// license loaded.
TestLicenseBuilder builder;
builder.AddSigningKey(signing_key, padding);
builder.GetSettings().padding = padding;
builder.AddSigningKey(signing_key);
builder.AddStubbedContentKey();
License license;
@@ -84,7 +86,7 @@ class LicenseWhiteboxVerifyRenewalResponseTest
// SuccessForGarbageMessage - to use the real serialized response.
TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, SuccessForGarbageMessage) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_,
garbage_renewal_message_.data(),
@@ -96,7 +98,7 @@ TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, SuccessForGarbageMessage) {
TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
SuccessWithSigningKeyPKSC8Padding) {
LoadLicense(TestLicenseBuilder::PKSC8Padding());
LoadLicense(TestLicenseBuilder::Padding::kPKSC8);
ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_,
garbage_renewal_message_.data(),
@@ -108,7 +110,7 @@ TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
InvalidParameterForNullWhitebox) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(
WB_License_VerifyRenewalResponse(nullptr, garbage_renewal_message_.data(),
@@ -120,7 +122,7 @@ TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
InvalidParameterForNullMessage) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_, nullptr,
garbage_renewal_message_.size(),
@@ -131,7 +133,7 @@ TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
InvalidParameterForZeroMessageSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_,
garbage_renewal_message_.data(), 0,
@@ -142,7 +144,7 @@ TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
InvalidParameterForNullSignature) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_VerifyRenewalResponse(
whitebox_, garbage_renewal_message_.data(),
@@ -153,7 +155,7 @@ TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
InvalidParameterForInvalidSignatureSize) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
ASSERT_EQ(WB_License_VerifyRenewalResponse(
whitebox_, garbage_renewal_message_.data(),
@@ -164,7 +166,7 @@ TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
InvalidSignatureForModifiedMessage) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
Modify(&garbage_renewal_message_);
@@ -178,7 +180,7 @@ TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
TEST_F(LicenseWhiteboxVerifyRenewalResponseTest,
InvalidSignatureForModifiedSignature) {
LoadLicense(TestLicenseBuilder::NoPadding());
LoadLicense(TestLicenseBuilder::Padding::kNone);
Modify(&garbage_renewal_signature_);

View File

@@ -0,0 +1,23 @@
// Copyright 2021 Google LLC. All Rights Reserved.
#ifndef WHITEBOX_API_TEST_KEY_TYPES_H_
#define WHITEBOX_API_TEST_KEY_TYPES_H_
#include <array>
#include <cstdint>
namespace widevine {
// Key ids can be any non-zero length, normally they will be 16 bytes long,
// however, we use 4 in our tests since they are easier to set.
using KeyId = std::array<uint8_t, 4>;
// AES keys can only be 16 bytes.
using AesKey = std::array<uint8_t, 16>;
// AES IV can only be 16 bytes.
using AesIv = std::array<uint8_t, 16>;
} // namespace widevine
#endif // WHITEBOX_API_TEST_KEY_TYPES_H_

View File

@@ -2,6 +2,7 @@
#include "api/test_license_builder.h"
#include <array>
#include <ctime>
#include "base/check.h"
@@ -19,6 +20,8 @@ namespace widevine {
namespace {
using KeyControlBlock = std::array<uint8_t, 16>;
void InitializeRequest(video_widevine::LicenseRequest* request) {
request->set_request_time(std::time(nullptr)); // Use time=now.
@@ -84,26 +87,29 @@ void InitializeResponse(const video_widevine::LicenseRequest& request,
video_widevine::PlatformVerificationStatus::PLATFORM_UNVERIFIED);
}
std::string EncryptKey(const std::string& key,
const std::string& iv,
const std::vector<uint8_t>& plaintext) {
template <typename Key, typename IV, typename Plaintext>
std::string Encrypt(const Key& key, const IV& iv, const Plaintext& plaintext) {
std::vector<uint8_t> key_data(key.begin(), key.end());
std::vector<uint8_t> iv_data(iv.begin(), iv.end());
std::vector<uint8_t> plaintext_data(plaintext.begin(), plaintext.end());
AesCbcEncryptor encryptor;
encryptor.SetKey(reinterpret_cast<const uint8_t*>(key.data()), key.size());
encryptor.SetKey(key_data.data(), key_data.size());
std::vector<uint8_t> ciphertext(plaintext.size());
CHECK(encryptor.Encrypt(reinterpret_cast<const uint8_t*>(iv.data()),
iv.size(), plaintext.data(), plaintext.size(),
ciphertext.data()));
CHECK(encryptor.Encrypt(iv_data.data(), iv_data.size(), plaintext_data.data(),
plaintext_data.size(), ciphertext.data()));
return std::string(ciphertext.begin(), ciphertext.end());
}
std::string DeriveIV(const std::vector<uint8_t>& context) {
template <typename In>
std::string DeriveIV(const In& context) {
const std::string context_str(context.begin(), context.end());
return crypto_util::DeriveIv(context_str);
}
void UpdateKeyControlBlock(
KeyControlBlock CreateKeyControlBlock(
video_widevine::License_KeyContainer_SecurityLevel level,
video_widevine::License_KeyContainer_KeyControl* key_control) {
// The key control block is an 128 bit structure containing the following
@@ -119,7 +125,7 @@ void UpdateKeyControlBlock(
// 1 = SW_SECURE_DECODE
// 2 = HW_SECURE_CRYPTO
// 3 = HW_SECURE_DECODE or HW_SECURE_ALL
std::vector<uint8_t> key_control_block = {
KeyControlBlock key_control_block = {
'k', 'c', 't', 'l', 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
@@ -138,18 +144,16 @@ void UpdateKeyControlBlock(
break;
}
// Key Control Block is no longer encrypted, so no need to set IV.
key_control->set_key_control_block(key_control_block.data(),
key_control_block.size());
return key_control_block;
}
std::string GenerateCoreMessage(
const std::string& serialized_request,
const std::string& serialized_license_response) {
constexpr uint16_t api_major_version = 16;
constexpr uint16_t api_minor_version = 5;
static_assert(api_major_version == ODK_MAJOR_VERSION,
"Verify ODK library is compatible.");
std::string GenerateCoreMessage(const std::string& serialized_request,
const std::string& serialized_license_response,
uint16_t api_major_version,
uint16_t api_minor_version,
bool use_padding) {
DCHECK_EQ(api_major_version, ODK_MAJOR_VERSION)
<< "Verify ODK library is compatible.";
constexpr uint32_t session_id = 0xcafebabe;
constexpr uint32_t nonce = 0xdeadbeef;
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce,
@@ -188,27 +192,109 @@ std::string GenerateCoreMessage(
std::string oemcrypto_core_message;
CHECK(oemcrypto_core_message::serialize::CreateCoreLicenseResponseFromProto(
serialized_license_response, core_request, core_message_hash,
/* nonce_required= */ true, &oemcrypto_core_message));
/* nonce_required= */ true, use_padding, &oemcrypto_core_message));
return oemcrypto_core_message;
}
std::vector<uint8_t> GetPadding(TestLicenseBuilder::Padding padding) {
if (padding == TestLicenseBuilder::Padding::kPKSC8) {
return {
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
};
}
return {};
}
void AddContentKeyToContainer(const TestLicenseBuilder::ContentKey& key_data,
const TestLicenseBuilder::Settings& settings,
const std::string& container_key,
video_widevine::License_KeyContainer* container) {
container->set_type(video_widevine::License_KeyContainer_KeyType_CONTENT);
container->set_id(key_data.id.data(), key_data.id.size());
container->set_level(key_data.level);
// 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);
std::vector<uint8_t> key(key_data.key.begin(), key_data.key.end());
auto padding = GetPadding(settings.padding);
key.insert(key.end(), padding.begin(), padding.end());
container->set_key(Encrypt(container_key, key_iv, key));
const auto key_control_block =
CreateKeyControlBlock(key_data.level, container->mutable_key_control());
auto* key_control = container->mutable_key_control();
// 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.
if (settings.key_control_block ==
TestLicenseBuilder::KeyControlBlock::kEncrypted) {
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);
key_control->set_iv(key_control_block_iv);
key_control->set_key_control_block(encrypted_key_control_block.data(),
encrypted_key_control_block.size());
} else {
key_control->set_key_control_block(key_control_block.data(),
key_control_block.size());
}
}
void AddSigningKeyToContainer(const TestLicenseBuilder::SigningKey& key_data,
const TestLicenseBuilder::Settings& settings,
const std::string& container_key,
video_widevine::License_KeyContainer* container) {
container->set_type(video_widevine::License_KeyContainer_KeyType_SIGNING);
// 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);
container->set_iv(key_iv);
std::vector<uint8_t> key(key_data.begin(), key_data.end());
auto padding = GetPadding(settings.padding);
key.insert(key.end(), padding.begin(), padding.end());
container->set_key(Encrypt(container_key, key_iv, key));
}
void AddOperatorSessionKeyToContainer(
const KeyId& key_id,
video_widevine::License_KeyContainer* container) {
container->set_type(
video_widevine::License_KeyContainer_KeyType_OPERATOR_SESSION);
container->set_id(key_id.data(), key_id.size());
}
uint16_t GetOdkMinorVersion(TestLicenseBuilder::OdkVersion odk_version) {
switch (odk_version) {
case TestLicenseBuilder::OdkVersion::k16_3:
return 3;
case TestLicenseBuilder::OdkVersion::k16_5:
return 5;
case TestLicenseBuilder::OdkVersion::kNone:
DCHECK(false);
return 0;
}
}
} // namespace
// static
std::vector<uint8_t> TestLicenseBuilder::NoPadding() {
return {};
}
// static
std::vector<uint8_t> TestLicenseBuilder::PKSC8Padding() {
return {
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
};
}
// static
std::vector<uint8_t> TestLicenseBuilder::DefaultSigningKey() {
TestLicenseBuilder::SigningKey TestLicenseBuilder::DefaultSigningKey() {
return {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
@@ -232,118 +318,83 @@ TestLicenseBuilder::TestLicenseBuilder() {
crypto_util::kWrappingKeySizeBits);
}
void TestLicenseBuilder::AddSigningKey(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& padding) {
DCHECK_EQ(key.size(), 64u); // 512 bits
auto* container = response_.add_key();
container->set_type(video_widevine::License_KeyContainer_KeyType_SIGNING);
// 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);
container->set_iv(key_iv);
std::vector<uint8_t> final_key = key;
final_key.insert(final_key.end(), padding.begin(), padding.end());
container->set_key(EncryptKey(container_key_, key_iv, final_key));
void TestLicenseBuilder::AddSigningKey(const SigningKey& key) {
signing_keys_.push_back(key);
}
void TestLicenseBuilder::AddStubbedContentKey() {
const video_widevine::License_KeyContainer_SecurityLevel kLevel =
content_keys_.emplace_back();
auto& key_data = content_keys_.back();
key_data.level =
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO;
auto* container = response_.add_key();
container->set_type(video_widevine::License_KeyContainer_KeyType_CONTENT);
container->set_id("stubbed-content-key");
container->set_level(kLevel);
container->set_iv("0000000000000000");
// We don't bother encrypting the key, it should never be used and there is no
// way to verify it. Note that the ODK automatically strips padding, so
// this key needs to include 16 bytes of padding.
container->set_key("00000000000000000000000000000000");
UpdateKeyControlBlock(kLevel, container->mutable_key_control());
key_data.id = {0, 0, 0, 0};
key_data.key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
}
void TestLicenseBuilder::AddContentKey(
video_widevine::License_KeyContainer_SecurityLevel level,
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& key,
const std::vector<uint8_t>& padding) {
DCHECK_GT(key_id.size(), 0u);
DCHECK_EQ(key.size(), 16u);
auto* container = response_.add_key();
container->set_type(video_widevine::License_KeyContainer_KeyType_CONTENT);
container->set_id(key_id.data(), key_id.size());
container->set_level(level);
// 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);
container->set_iv(key_iv);
std::vector<uint8_t> final_key = key;
final_key.insert(final_key.end(), padding.begin(), padding.end());
container->set_key(EncryptKey(container_key_, key_iv, final_key));
UpdateKeyControlBlock(level, container->mutable_key_control());
const KeyId& id,
const AesKey& key) {
content_keys_.emplace_back();
auto& key_data = content_keys_.back();
key_data.level = level;
key_data.id = id;
key_data.key = key;
}
void TestLicenseBuilder::AddOperatorSessionKey(
const std::vector<uint8_t>& key_id) {
DCHECK_GT(key_id.size(), 0u);
// We only set the type and id because the key should not actually be used.
auto* container = response_.add_key();
container->set_type(
video_widevine::License_KeyContainer_KeyType_OPERATOR_SESSION);
container->set_id(key_id.data(), key_id.size());
}
void TestLicenseBuilder::SetRemoteAttestation(RemoteAttestation setting) {
switch (setting) {
case RemoteAttestation::kUnavailable:
response_.clear_remote_attestation_verified();
break;
case RemoteAttestation::kVerified:
response_.set_remote_attestation_verified(true);
break;
case RemoteAttestation::kUnverified:
response_.set_remote_attestation_verified(false);
break;
}
}
void TestLicenseBuilder::SetVerificationStatus(VerificationStatus setting) {
switch (setting) {
case VerificationStatus::kUnavailable:
response_.clear_platform_verification_status();
break;
case VerificationStatus::kHardwareVerified:
response_.set_platform_verification_status(
video_widevine::PLATFORM_HARDWARE_VERIFIED);
break;
case VerificationStatus::kOther:
response_.set_platform_verification_status(
video_widevine::PLATFORM_UNVERIFIED);
break;
}
}
void TestLicenseBuilder::SetUseODK(bool setting) {
use_odk_ = setting;
void TestLicenseBuilder::AddOperatorSessionKey(const KeyId& id) {
operator_session_keys_.push_back(id);
}
void TestLicenseBuilder::Build(const RsaPublicKey& public_key,
License* license) const {
DCHECK(license);
const std::string message_str = response_.SerializeAsString();
// Make a copy to allow us to maintain the const-correctness of this
// function.
video_widevine::License response = response_;
switch (settings_.remote_attestation) {
case RemoteAttestation::kUnavailable:
response.clear_remote_attestation_verified();
break;
case RemoteAttestation::kVerified:
response.set_remote_attestation_verified(true);
break;
case RemoteAttestation::kUnverified:
response.set_remote_attestation_verified(false);
break;
}
switch (settings_.verification_status) {
case VerificationStatus::kUnavailable:
response.clear_platform_verification_status();
break;
case VerificationStatus::kHardwareVerified:
response.set_platform_verification_status(
video_widevine::PLATFORM_HARDWARE_VERIFIED);
break;
case VerificationStatus::kOther:
response.set_platform_verification_status(
video_widevine::PLATFORM_UNVERIFIED);
break;
}
for (const auto& key : signing_keys_) {
AddSigningKeyToContainer(key, settings_, container_key_,
response.add_key());
}
for (const auto& key : content_keys_) {
AddContentKeyToContainer(key, settings_, container_key_,
response.add_key());
}
for (const auto& key : operator_session_keys_) {
AddOperatorSessionKeyToContainer(key, response.add_key());
}
const std::string message_str = response.SerializeAsString();
std::string signing_key = crypto_util::DeriveKey(
session_key_, crypto_util::kSigningKeyLabel, serialized_request_,
crypto_util::kSigningKeySizeBits * 2);
@@ -352,11 +403,16 @@ void TestLicenseBuilder::Build(const RsaPublicKey& public_key,
std::string session_key_str;
CHECK(public_key.Encrypt(session_key_, &session_key_str));
const std::string oemcrypto_core_message =
use_odk_ ? GenerateCoreMessage(serialized_request_, message_str)
: std::string();
std::string oemcrypto_core_message;
if (settings_.odk_version != OdkVersion::kNone) {
uint16_t api_major_version = 16;
uint16_t api_minor_version = GetOdkMinorVersion(settings_.odk_version);
oemcrypto_core_message = GenerateCoreMessage(
serialized_request_, message_str, api_major_version, api_minor_version,
settings_.padding != Padding::kNone);
}
// If |use_odk_| is false, |oemcrypto_core_message| will be empty.
// If |odk_version| is kNone, |oemcrypto_core_message| will be empty.
const std::string signature_str = crypto_util::CreateSignatureHmacSha256(
signing_key, oemcrypto_core_message + message_str);

View File

@@ -3,10 +3,11 @@
#ifndef WHITEBOX_API_LICENSE_BUILDER_H_
#define WHITEBOX_API_LICENSE_BUILDER_H_
#include <stdint.h>
#include <cstdint>
#include <string>
#include <vector>
#include "api/test_key_types.h"
#include "cdm/protos/license_protocol.pb.h"
#include "crypto_utils/rsa_key.h"
@@ -27,6 +28,23 @@ struct License {
class TestLicenseBuilder {
public:
struct ContentKey {
KeyId id;
AesKey key;
video_widevine::License_KeyContainer_SecurityLevel level =
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO;
};
// Signing keys must be 512 bits (64 bytes).
using SigningKey = std::array<uint8_t, 64>;
enum class Padding {
kNone,
kPKSC8,
};
enum class RemoteAttestation {
kUnavailable,
kVerified,
@@ -39,40 +57,48 @@ class TestLicenseBuilder {
kOther,
};
// Returns padding data the can be used as |padding| when calling
// AddSigningKey() or AddContentKey().
static std::vector<uint8_t> NoPadding();
static std::vector<uint8_t> PKSC8Padding();
// ODK version of the `core_message`.
enum class OdkVersion {
kNone, // No `core_message`
k16_3, // ODK version 16.3
k16_5, // ODK version 16.5
};
enum class KeyControlBlock {
kClear,
kEncrypted,
};
struct Settings {
Padding padding = Padding::kNone;
OdkVersion odk_version = OdkVersion::kNone;
KeyControlBlock key_control_block = KeyControlBlock::kClear;
RemoteAttestation remote_attestation = RemoteAttestation::kUnavailable;
VerificationStatus verification_status = VerificationStatus::kUnavailable;
};
// Returns a default signing key that can be used with AddSigningKey().
static std::vector<uint8_t> DefaultSigningKey();
static SigningKey DefaultSigningKey();
TestLicenseBuilder();
void AddSigningKey(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& padding);
void AddSigningKey(const SigningKey& key);
// Add a content key so that there is some key in the license. This should not
// be used with AddContentKey().
void AddStubbedContentKey();
void AddContentKey(video_widevine::License_KeyContainer_SecurityLevel level,
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& key,
const std::vector<uint8_t>& padding);
const KeyId& id,
const AesKey& 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.
void AddOperatorSessionKey(const std::vector<uint8_t>& key_id);
void AddOperatorSessionKey(const KeyId& key_id);
void SetRemoteAttestation(RemoteAttestation setting);
void SetVerificationStatus(VerificationStatus setting);
// If set, then Build() will populate |core_message| in License with the
// matching ODK core message. If not set, then |core_message| will be empty.
void SetUseODK(bool setting);
Settings& GetSettings() { return settings_; }
const Settings& GetSettings() const { return settings_; }
// Gets the serialized license request and response (in components) that would
// have been used in the license exchange.
@@ -85,7 +111,12 @@ class TestLicenseBuilder {
video_widevine::License response_;
std::string serialized_request_;
std::string container_key_;
bool use_odk_ = false;
Settings settings_;
std::vector<ContentKey> content_keys_;
std::vector<SigningKey> signing_keys_;
std::vector<KeyId> operator_session_keys_;
};
} // namespace widevine

View File

@@ -441,27 +441,19 @@ const size_t kGoldenDataSize = sizeof(kGoldenDataSize);
} // namespace
std::vector<uint8_t> DataSource::Get(size_t size) {
std::vector<uint8_t> buffer(size);
std::vector<uint8_t> data(size);
size_t write_head = 0;
while (write_head < size) {
const size_t remaining_read = kGoldenDataSize - read_head_;
const size_t remaining_write = size - write_head;
// Figure out how much more we can write. If we are nearing the end of the
// read buffer, we have to cut short our read so that we can loop back to
// the start of the read buffer.
size_t next_write = std::min(remaining_read, remaining_write);
memcpy(buffer.data() + write_head, kGoldenData + read_head_, next_write);
// Move both the read and write heads forward. Make sure to loop the read
// head back to the start so that we we can restart reading when necessary.
write_head += next_write;
read_head_ = (read_head_ + next_write) % kGoldenDataSize;
for (size_t i = 0; i < size; i++) {
data[i] = Get();
}
return buffer;
return data;
}
uint8_t DataSource::Get() {
uint8_t x = kGoldenData[read_head_];
read_head_ = (read_head_ + 1) % kGoldenDataSize;
return x;
}
} // namespace widevine

View File

@@ -3,18 +3,31 @@
#ifndef WHITEBOX_BENCHMARKING_DATA_SOURCE_H_
#define WHITEBOX_BENCHMARKING_DATA_SOURCE_H_
#include <stddef.h>
#include <stdint.h>
#include <array>
#include <cstddef>
#include <cstdint>
#include <vector>
namespace widevine {
class DataSource {
public:
template <size_t size>
std::array<uint8_t, size> Get() {
std::array<uint8_t, size> data;
for (size_t i = 0; i < size; i++) {
data[i] = Get();
}
return data;
}
std::vector<uint8_t> Get(size_t size);
private:
uint8_t Get();
size_t read_head_ = 0;
};

View File

@@ -23,6 +23,8 @@ cc_library(
"oemcrypto/odk/src/odk_timer.c",
"oemcrypto/odk/src/odk_util.c",
"oemcrypto/odk/src/odk_util.h",
"oemcrypto/odk/src/odk_message_priv.h",
"oemcrypto/odk/src/odk_message.c",
"oemcrypto/odk/src/serialization_base.c",
":odk_common_hdrs",
],
@@ -31,6 +33,8 @@ cc_library(
"oemcrypto/odk/include/odk.h",
"oemcrypto/odk/include/odk_structs.h",
"oemcrypto/odk/include/odk_target.h",
"oemcrypto/odk/include/odk_message.h",
"oemcrypto/odk/include/odk_attributes.h",
],
copts = ["-std=c99"],
includes = [

View File

@@ -19,6 +19,17 @@ cc_library(
],
)
cc_library(
name = "odk",
hdrs = ["odk.h",],
srcs = ["odk.cc",],
deps = [
"//api:result",
"//external:odk",
"//chromium_deps/base:glog",
],
)
cc_library(
name = "license_private_key",
hdrs = [
@@ -42,7 +53,7 @@ cc_library(
"//crypto_utils:aes_ctr_encryptor",
"//crypto_utils:crypto_util",
"//crypto_utils:rsa_key",
"//external:odk",
":odk",
],
)

View File

@@ -18,7 +18,9 @@
#include "crypto_utils/rsa_key.h"
#include "impl/reference/license_private_key.h"
#include "impl/reference/memory_util.h"
#include "impl/reference/odk.h"
#include "oemcrypto/odk/include/odk.h"
#include "oemcrypto/odk/include/odk_message.h"
#include "oemcrypto/odk/include/odk_structs.h"
#include "oemcrypto/odk/src/odk_serialize.h"
#include "oemcrypto/odk/src/serialization_base.h"
@@ -54,7 +56,9 @@ bool Decrypt(AesCbcDecryptor& decryptor,
const std::string& iv,
const std::string& encrypted,
std::string* decrypted) {
DCHECK_EQ(iv.size(), 16u);
DCHECK_GE(decrypted->size(), encrypted.size());
return decryptor.Decrypt(
reinterpret_cast<const uint8_t*>(iv.data()), iv.size(),
reinterpret_cast<const uint8_t*>(encrypted.data()), encrypted.size(),
@@ -77,8 +81,9 @@ std::string ExtractItem(const OEMCrypto_Substring& item,
return buffer.substr(item.offset, item.length);
}
video_widevine::License_KeyContainer_SecurityLevel ExtractLevel(
const std::string& key_control_block) {
bool ExtractLevel(
const std::string& key_control_block,
video_widevine::License_KeyContainer_SecurityLevel* security_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.
//
@@ -93,29 +98,30 @@ video_widevine::License_KeyContainer_SecurityLevel ExtractLevel(
// 2 = HW_SECURE_CRYPTO
// 3 = HW_SECURE_DECODE or HW_SECURE_ALL
// Limited checks to verify that this is proper key control block.
// If not valid, assume it's the highest level.
// Make sure this is a valid key control block. Ideally the signature
// verification should have taken care of this.
if ((key_control_block.size() != 16u) || (key_control_block[0] != 'k') ||
(key_control_block[1] != 'c')) {
return video_widevine::License_KeyContainer_SecurityLevel_HW_SECURE_DECODE;
return false;
}
// Extract bits 26..27 from Control Bits.
int security_level = (key_control_block[12] & 0x0C) >> 2;
switch (security_level) {
switch ((key_control_block[12] & 0x0C) >> 2) {
case 0:
return video_widevine::
License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO;
*security_level =
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO;
case 1:
return video_widevine::
License_KeyContainer_SecurityLevel_SW_SECURE_DECODE;
*security_level =
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_DECODE;
case 2:
return video_widevine::
License_KeyContainer_SecurityLevel_HW_SECURE_CRYPTO;
*security_level =
video_widevine::License_KeyContainer_SecurityLevel_HW_SECURE_CRYPTO;
default:
return video_widevine::
License_KeyContainer_SecurityLevel_HW_SECURE_DECODE;
*security_level =
video_widevine::License_KeyContainer_SecurityLevel_HW_SECURE_DECODE;
}
return true;
}
// Creates and returns a ContentKey based on the values provided.
@@ -218,13 +224,13 @@ const uint8_t kCTRSecretStringPattern[] = {
};
std::vector<uint8_t> GetSecretStringFor(WB_CipherMode mode) {
return mode == WB_CIPHER_MODE_CBC ?
std::vector<uint8_t>(
kCBCSecretStringPattern,
kCBCSecretStringPattern + sizeof(kCBCSecretStringPattern)) :
std::vector<uint8_t>(
kCTRSecretStringPattern,
kCTRSecretStringPattern + sizeof(kCTRSecretStringPattern));
return mode == WB_CIPHER_MODE_CBC
? std::vector<uint8_t>(
kCBCSecretStringPattern,
kCBCSecretStringPattern + sizeof(kCBCSecretStringPattern))
: std::vector<uint8_t>(
kCTRSecretStringPattern,
kCTRSecretStringPattern + sizeof(kCTRSecretStringPattern));
}
const ContentKey* FindKey(const WB_License_Whitebox* whitebox,
@@ -497,35 +503,14 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
return WB_RESULT_INVALID_SIGNATURE;
}
// If |core_message| is provided, parse it into |parsed_license| and validate
// that it's an appropriate version.
uint16_t odk_major_version = 0;
uint16_t odk_minor_version = 0;
ODK_ParsedLicense parsed_license;
ODKContext odk_context;
if (core_message_size > 0) {
// Decode |core_message|.
Message* msg = NULL;
AllocateMessage(&msg, message_block);
InitMessage(msg,
reinterpret_cast<uint8_t*>(
const_cast<char*>(combined_message_str.data())),
combined_message_str.size());
// The core message is at the beginning of the buffer, and is the part to be
// parsed.
SetSize(msg, core_message_size);
auto result =
GetODKContext(combined_message_str, core_message_size, &odk_context);
ODK_LicenseResponse license_response = {{{0}}, &parsed_license, {0}};
Unpack_ODK_LicenseResponse(msg, &license_response);
odk_major_version =
license_response.request.core_message.nonce_values.api_major_version;
odk_minor_version =
license_response.request.core_message.nonce_values.api_minor_version;
if ((GetStatus(msg) != MESSAGE_STATUS_OK) ||
(license_response.request.core_message.message_type !=
ODK_License_Response_Type)) {
DVLOG(1) << "Failed to validate core message.";
return WB_RESULT_INVALID_SIGNATURE;
if (result != WB_RESULT_OK) {
return result;
}
}
@@ -539,14 +524,16 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
std::vector<std::string> client_renewal_keys;
// Even if |core_message| is provided, only ODK v16.5 and later support the
// fields needed. If an older API is used, ignore it and use the protobuf
// as if |core_message| was not provided.
if (IsOdkVersionSupported(odk_major_version, odk_minor_version)) {
// fields needed. If an older API is used, ignore it and use the protobuf as
// if |core_message| was not provided.
if (odk_context.is_valid && !HasEncryptedKeyControlBlock(odk_context) &&
IsOdkVersionSupported(odk_context.major_version,
odk_context.minor_version)) {
// Start by extracting the signing key.
const std::string signing_key_encrypted =
ExtractItem(parsed_license.enc_mac_keys, message_str);
ExtractItem(odk_context.license.enc_mac_keys, message_str);
const std::string signing_key_iv =
ExtractItem(parsed_license.enc_mac_keys_iv, message_str);
ExtractItem(odk_context.license.enc_mac_keys_iv, message_str);
if (!signing_key_encrypted.empty() && !signing_key_iv.empty()) {
std::string unwrapped_signing_key(signing_key_encrypted);
@@ -568,14 +555,19 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
}
// Now extract all the content keys.
for (size_t i = 0; i < parsed_license.key_array_length; ++i) {
const OEMCrypto_KeyObject& key = parsed_license.key_array[i];
for (size_t i = 0; i < odk_context.license.key_array_length; ++i) {
const OEMCrypto_KeyObject& key = odk_context.license.key_array[i];
const std::string key_id = ExtractItem(key.key_id, message_str);
DCHECK_GT(key_id.size(), 0u);
const std::string iv = ExtractItem(key.key_data_iv, message_str);
const std::string wrapped_key = ExtractItem(key.key_data, message_str);
std::string unwrapped_key(wrapped_key);
DCHECK_EQ(iv.size(), 16u);
const std::string wrapped_key = ExtractItem(key.key_data, message_str);
DCHECK_EQ(wrapped_key.size(), 16u);
std::string unwrapped_key(wrapped_key);
if (!Decrypt(decryptor, iv, wrapped_key, &unwrapped_key)) {
DVLOG(1) << "Invalid parameter: Invalid key.key_data.";
return WB_RESULT_INVALID_PARAMETER;
@@ -595,9 +587,12 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
// this.
const std::string key_control_block =
ExtractItem(key.key_control, message_str);
content_keys[key_id] =
CreateContentKey(ExtractLevel(key_control_block),
/* is_hw_verified */ false, unwrapped_key);
video_widevine::License_KeyContainer_SecurityLevel security_level;
CHECK(ExtractLevel(key_control_block, &security_level));
content_keys[key_id] = CreateContentKey(
security_level, /* is_hw_verified */ false, unwrapped_key);
}
} else {
// Core message not provided or an old version, so extract the keys from

View File

@@ -0,0 +1,73 @@
// cOpyright 2021 Google LLC. All Rights Reserved.
#include "impl/reference/odk.h"
#include <vector>
#include "base/check.h"
#include "base/check_op.h"
#include "base/logging.h"
#include "oemcrypto/odk/include/OEMCryptoCENCCommon.h"
#include "oemcrypto/odk/include/odk.h"
#include "oemcrypto/odk/include/odk_message.h"
#include "oemcrypto/odk/src/odk_serialize.h"
#include "oemcrypto/odk/src/serialization_base.h"
// Most of the logic to parse the core message comes from `ODK_ParseResponse()`.
// We copy the logic since the function as a whole is not compatible with what
// we need to do here.
WB_Result GetODKContext(const std::string& combined_message,
size_t core_message_size,
ODKContext* context) {
// ODK_Message requires a mutable buffer and the buffer must exist as long as
// the message exists.
std::vector<uint8_t> mutable_message(combined_message.begin(),
combined_message.end());
ODK_Message msg =
ODK_Message_Create(mutable_message.data(), mutable_message.size());
ODK_Message_SetSize(&msg, core_message_size);
const ODK_MessageStatus message_status = ODK_Message_GetStatus(&msg);
if (message_status != MESSAGE_STATUS_OK) {
DVLOG(1) << "Invalid core message status: " << message_status;
return WB_RESULT_INVALID_SIGNATURE;
}
ODK_LicenseResponse license_response{{{0, 0, {}}}, NULL, {0}};
license_response.parsed_license = &(context->license);
Unpack_ODK_LicenseResponse(&msg, &license_response);
const auto& core_message = license_response.request.core_message;
if (core_message.message_type != ODK_License_Response_Type) {
DVLOG(1) << "Failed core message type: " << core_message.message_type;
return WB_RESULT_INVALID_SIGNATURE;
}
context->major_version = core_message.nonce_values.api_major_version;
context->minor_version = core_message.nonce_values.api_minor_version;
// Now that it is initialized, mark it as valid.
context->is_valid = true;
return WB_RESULT_OK;
}
bool HasEncryptedKeyControlBlock(const ODKContext& context) {
size_t encrypted_count = 0;
for (uint32_t i = 0; i < context.license.key_array_length; i++) {
const OEMCrypto_KeyObject& key = context.license.key_array[i];
if (key.key_control_iv.length > 0) {
encrypted_count++;
}
}
// Either no key control block should be encrypted or all of them should be.
// There is no case where only a subset of the keys should have encrypted key
// control blocks.
return encrypted_count > 0;
}

View File

@@ -0,0 +1,25 @@
// Copyright 2021 Google LLC. All Rights Reserved.
#ifndef WHITEBOX_IMPL_REFERENCE_ODK_H_
#define WHITEBOX_IMPL_REFERENCE_ODK_H_
#include <cstdint>
#include <string>
#include "api/result.h"
#include "oemcrypto/odk/include/odk_structs.h"
struct ODKContext {
bool is_valid = false;
uint16_t major_version = 0;
uint16_t minor_version = 0;
ODK_ParsedLicense license;
};
WB_Result GetODKContext(const std::string& combined_message,
size_t core_message_size,
ODKContext* context);
bool HasEncryptedKeyControlBlock(const ODKContext& context);
#endif // WHITEBOX_IMPL_REFERENCE_ODK_H_