ODK and Shared Libraries
In this code drop we introduce the ODK dependency. The reference implementation has been updated to make use of the ODK and the related tests have been included. In addition, we have included an example of how a shared libraries can be created. This will allow make it easier to test and verify different implementations of the API. Most other changes introduce by this code drop were made to clean-up the reference implementation and limit dependencies.
This commit is contained in:
26
api/BUILD
26
api/BUILD
@@ -10,6 +10,12 @@ cc_library(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "export",
|
||||
hdrs = ["export.h"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "aead_whitebox",
|
||||
hdrs = [
|
||||
@@ -17,6 +23,7 @@ cc_library(
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":export",
|
||||
":result",
|
||||
],
|
||||
)
|
||||
@@ -28,6 +35,7 @@ cc_library(
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":export",
|
||||
":result",
|
||||
],
|
||||
)
|
||||
@@ -67,6 +75,7 @@ cc_library(
|
||||
"//crypto_utils:aes_cbc_encryptor",
|
||||
"//crypto_utils:crypto_util",
|
||||
"//crypto_utils:rsa_key",
|
||||
"//external:odk",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -135,6 +144,23 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
# TODO(jrummell): Move sources into "license_whitebox_test" once all
|
||||
# implementations support core_message.
|
||||
cc_library(
|
||||
name = "license_whitebox_core_message_test",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"license_whitebox_process_license_response_core_message_test.cc",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":license_whitebox",
|
||||
":license_whitebox_test",
|
||||
":test_license_builder",
|
||||
"//chromium_deps/testing",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "license_whitebox_benchmark",
|
||||
testonly = True,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "api/export.h"
|
||||
#include "api/result.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -42,11 +43,11 @@ typedef struct WB_Aead_Whitebox WB_Aead_Whitebox;
|
||||
// |context| was null, if |context_size| was zero, or if |whitebox| was null.
|
||||
//
|
||||
// WB_RESULT_OUT_OF_MEMORY if the necessary memory could not be allocated.
|
||||
WB_Result WB_Aead_Create(const uint8_t* whitebox_init_data,
|
||||
size_t whitebox_init_data_size,
|
||||
const uint8_t* context,
|
||||
size_t context_size,
|
||||
WB_Aead_Whitebox** whitebox);
|
||||
WB_API WB_Result WB_Aead_Create(const uint8_t* whitebox_init_data,
|
||||
size_t whitebox_init_data_size,
|
||||
const uint8_t* context,
|
||||
size_t context_size,
|
||||
WB_Aead_Whitebox** whitebox);
|
||||
|
||||
// Releases all resources used by the white-box instance pointed to by
|
||||
// |whitebox|.
|
||||
@@ -54,7 +55,7 @@ WB_Result WB_Aead_Create(const uint8_t* whitebox_init_data,
|
||||
// Args:
|
||||
// whitebox (in) : A pointer to a white-box instance. Passing in null will
|
||||
// result in a no-op.
|
||||
void WB_Aead_Delete(WB_Aead_Whitebox* whitebox);
|
||||
WB_API void WB_Aead_Delete(WB_Aead_Whitebox* whitebox);
|
||||
|
||||
// Encrypts |input_data| and writes the cipher data, nonce and the data
|
||||
// verification tag to |output_data|. The implementation should generate and use
|
||||
@@ -85,11 +86,11 @@ void WB_Aead_Delete(WB_Aead_Whitebox* whitebox);
|
||||
//
|
||||
// WB_RESULT_BUFFER_TOO_SMALL if |output_data_size| (as input) was less than
|
||||
// the required size.
|
||||
WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
|
||||
const uint8_t* input_data,
|
||||
size_t input_data_size,
|
||||
uint8_t* output_data,
|
||||
size_t* output_data_size);
|
||||
WB_API WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
|
||||
const uint8_t* input_data,
|
||||
size_t input_data_size,
|
||||
uint8_t* output_data,
|
||||
size_t* output_data_size);
|
||||
|
||||
// Decrypts |input_data| and writes the plaintext to |output_data|. |input_data|
|
||||
// must have been encrypted using WB_Aead_Encrypt() with the same |whitebox|.
|
||||
@@ -119,11 +120,11 @@ WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
|
||||
//
|
||||
// WB_RESULT_DATA_VERIFICATION_ERROR if |input_data| failed data verification.
|
||||
// The state of |output_data| is undefined.
|
||||
WB_Result WB_Aead_Decrypt(const WB_Aead_Whitebox* whitebox,
|
||||
const uint8_t* input_data,
|
||||
size_t input_data_size,
|
||||
uint8_t* output_data,
|
||||
size_t* output_data_size);
|
||||
WB_API WB_Result WB_Aead_Decrypt(const WB_Aead_Whitebox* whitebox,
|
||||
const uint8_t* input_data,
|
||||
size_t input_data_size,
|
||||
uint8_t* output_data,
|
||||
size_t* output_data_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
12
api/export.h
Normal file
12
api/export.h
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved.
|
||||
|
||||
#ifndef WHITEBOX_API_EXPORT_H_
|
||||
#define WHITEBOX_API_EXPORT_H_
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define WB_API _declspec(dllexport)
|
||||
#else
|
||||
#define WB_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#endif // WHITEBOX_API_EXPORT_H_
|
||||
@@ -1,345 +0,0 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved.
|
||||
|
||||
#include "api/license_test_helper.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "cdm/keys/certs.h"
|
||||
#include "cdm/protos/license_protocol.pb.h"
|
||||
#include "crypto_utils/aes_cbc_encryptor.h"
|
||||
#include "crypto_utils/crypto_util.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
namespace {
|
||||
|
||||
struct KeyData {
|
||||
video_widevine::License_KeyContainer_SecurityLevel level;
|
||||
std::vector<uint8_t> key_id;
|
||||
std::vector<uint8_t> iv;
|
||||
std::vector<uint8_t> content_key;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
KeyData SoftwareCryptoKey() {
|
||||
return {
|
||||
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO,
|
||||
{ // key_id:
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '0', '1', '2', '3', '4', '5',
|
||||
},
|
||||
{ // iv:
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
},
|
||||
{ // content_key:
|
||||
0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
|
||||
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
KeyData SoftwareDecodeKey() {
|
||||
return {
|
||||
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_DECODE,
|
||||
{ // key_id:
|
||||
'9', '8', '7', '6', '5', '4', '3', '2',
|
||||
'1', '0', '9', '8', '7', '6', '5', '4',
|
||||
},
|
||||
{ // iv:
|
||||
0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24,
|
||||
0x25, 0x26, 0x27, 0x28, 0x29, 0x30, 0x31, 0x32,
|
||||
},
|
||||
{ // content_key:
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
KeyData HardwareCryptoKey() {
|
||||
return {
|
||||
video_widevine::License_KeyContainer_SecurityLevel_HW_SECURE_CRYPTO,
|
||||
{ // key_id:
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
|
||||
},
|
||||
{ // iv:
|
||||
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40,
|
||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
||||
},
|
||||
{ // content_key:
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
||||
}
|
||||
};
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
// Returns |buffer| converted into a string.
|
||||
std::string AsString(const uint8_t* buffer, size_t buffer_size) {
|
||||
return std::string(reinterpret_cast<const char*>(buffer), buffer_size);
|
||||
}
|
||||
|
||||
// Returns the encryption key based on |license_request| and |session_key|.
|
||||
std::string GetEncryptionKey(const std::string& license_request,
|
||||
const std::string& session_key) {
|
||||
return widevine::crypto_util::DeriveKey(
|
||||
session_key, widevine::crypto_util::kWrappingKeyLabel, license_request,
|
||||
widevine::crypto_util::kWrappingKeySizeBits);
|
||||
}
|
||||
|
||||
std::string AesEncrypt(const std::string& key,
|
||||
const uint8_t* iv,
|
||||
size_t iv_size,
|
||||
const uint8_t* plain_text,
|
||||
size_t plain_text_size) {
|
||||
widevine::AesCbcEncryptor encryptor;
|
||||
encryptor.SetKey(reinterpret_cast<const uint8_t*>(key.data()), key.size());
|
||||
std::vector<uint8_t> cipher_text(plain_text_size);
|
||||
CHECK(encryptor.Encrypt(iv, iv_size, plain_text, plain_text_size,
|
||||
cipher_text.data()));
|
||||
return AsString(cipher_text.data(), cipher_text.size());
|
||||
}
|
||||
|
||||
video_widevine::License::KeyContainer CreateContentKeyContainer(
|
||||
const KeyData& key_data,
|
||||
const std::string& key_container_encryption_key) {
|
||||
video_widevine::License::KeyContainer key;
|
||||
key.set_id(key_data.key_id.data(), key_data.key_id.size());
|
||||
key.set_iv(key_data.iv.data(), key_data.iv.size());
|
||||
key.set_type(video_widevine::License_KeyContainer_KeyType_CONTENT);
|
||||
key.set_level(key_data.level);
|
||||
key.set_key(AesEncrypt(key_container_encryption_key, key_data.iv.data(),
|
||||
key_data.iv.size(), key_data.content_key.data(),
|
||||
key_data.content_key.size()));
|
||||
return key;
|
||||
}
|
||||
|
||||
video_widevine::License::KeyContainer CreateSigningKeyContainer(
|
||||
const std::string& key_container_encryption_key) {
|
||||
const std::vector<uint8_t> signing_iv = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '0', '1', '2', '3', '4', '5',
|
||||
};
|
||||
// 512 bits of key material for dual server/client signing key.
|
||||
const std::vector<uint8_t> signing_key = {
|
||||
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,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
};
|
||||
|
||||
video_widevine::License::KeyContainer key;
|
||||
key.set_iv(signing_iv.data(), signing_iv.size());
|
||||
key.set_type(video_widevine::License_KeyContainer_KeyType_SIGNING);
|
||||
key.set_key(AesEncrypt(key_container_encryption_key, signing_iv.data(),
|
||||
signing_iv.size(), signing_key.data(),
|
||||
signing_key.size()));
|
||||
return key;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::vector<uint8_t> GetSoftwareCryptoKeyId() {
|
||||
const auto key = SoftwareCryptoKey();
|
||||
return key.key_id;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> GetSoftwareDecodeKeyId() {
|
||||
const auto key = SoftwareDecodeKey();
|
||||
return key.key_id;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> GetHardwareCryptoKeyId() {
|
||||
const auto key = HardwareCryptoKey();
|
||||
return key.key_id;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> GetUnusedKeyId() {
|
||||
return {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
}
|
||||
|
||||
// Returns a serialized license request with the following data:
|
||||
// {
|
||||
// "requestTime": <current time>,
|
||||
// "clientId": {
|
||||
// "clientCapabilities": {
|
||||
// "videoResolutionConstraints": true,
|
||||
// "clientToken": true,
|
||||
// "sessionToken": false,
|
||||
// "maxHdcpVersion": "HDCP_V1"
|
||||
// },
|
||||
// "clientInfo": [{
|
||||
// "name": "architecture_name",
|
||||
// "value": "x86-64"
|
||||
// },{
|
||||
// "name": "company_name",
|
||||
// "value": "Google"
|
||||
// },{
|
||||
// "name": "model_name",
|
||||
// "value": "ChromeCDM"
|
||||
// },{
|
||||
// "name": "platform_name",
|
||||
// "value": "Windows"
|
||||
// },{
|
||||
// "name": "widevine_cdm_version",
|
||||
// "value": "4.10.1686.29"
|
||||
// }],
|
||||
// "type": "DRM_DEVICE_CERTIFICATE",
|
||||
// "token": {
|
||||
// <test device certificate>
|
||||
// }"
|
||||
// }",
|
||||
// "contentId": {
|
||||
// "webmKeyId": {
|
||||
// "licenseType": "STREAMING",
|
||||
// "requestId": "REQUEST_ID",
|
||||
// "header": "01234567890123456"
|
||||
// }
|
||||
// },
|
||||
// "protocolVersion": "VERSION_2_1",
|
||||
// "type": "NEW"
|
||||
// }
|
||||
std::string CreateLicenseRequest() {
|
||||
video_widevine::LicenseRequest license_request;
|
||||
|
||||
// Request time is now.
|
||||
license_request.set_request_time(std::time(nullptr));
|
||||
|
||||
auto* client_id = license_request.mutable_client_id();
|
||||
auto* capabilities = client_id->mutable_client_capabilities();
|
||||
capabilities->set_video_resolution_constraints(true);
|
||||
capabilities->set_client_token(true);
|
||||
capabilities->set_session_token(false);
|
||||
capabilities->set_max_hdcp_version(
|
||||
video_widevine::ClientIdentification::ClientCapabilities::HDCP_V1);
|
||||
|
||||
auto* client_info = client_id->add_client_info();
|
||||
client_info->set_name("architecture_name");
|
||||
client_info->set_value("x86-64");
|
||||
client_info = client_id->add_client_info();
|
||||
client_info->set_name("company_name");
|
||||
client_info->set_value("Google");
|
||||
client_info = client_id->add_client_info();
|
||||
client_info->set_name("model_name");
|
||||
client_info->set_value("ChromeCDM");
|
||||
client_info = client_id->add_client_info();
|
||||
client_info->set_name("platform_name");
|
||||
client_info->set_value("Windows");
|
||||
client_info = client_id->add_client_info();
|
||||
client_info->set_name("widevine_cdm_version");
|
||||
client_info->set_value("4.10.1686.29");
|
||||
|
||||
client_id->set_type(
|
||||
video_widevine::ClientIdentification_TokenType_DRM_DEVICE_CERTIFICATE);
|
||||
client_id->set_token(wvcdm::kRsaDrmCertificate,
|
||||
wvcdm::kRsaDrmCertificateSize);
|
||||
|
||||
auto* content_id = license_request.mutable_content_id();
|
||||
auto* webm_key_id = content_id->mutable_webm_key_id();
|
||||
webm_key_id->set_license_type(video_widevine::STREAMING);
|
||||
webm_key_id->set_request_id("REQUEST_ID");
|
||||
webm_key_id->set_header("01234567890123456");
|
||||
|
||||
license_request.set_protocol_version(video_widevine::VERSION_2_1);
|
||||
license_request.set_type(video_widevine::LicenseRequest::NEW);
|
||||
return license_request.SerializeAsString();
|
||||
}
|
||||
|
||||
// Returns a serialized license using values from |serialized_license_request|
|
||||
// as well as |session_key|. Some of the values match what is in the license
|
||||
// request, but as they are not checked it really doesn't matter. The license
|
||||
// will contain all 3 keys |kKeyId1|, |kKeyId2|, and |kKeyId3| with different
|
||||
// security levels. The license is of the form:
|
||||
// {
|
||||
// "id": {
|
||||
// "requestId": "REQUEST_ID",
|
||||
// "sessionId": "SESSION_ID",
|
||||
// "type": "STREAMING",
|
||||
// "version": 0
|
||||
// },
|
||||
// "policy": {
|
||||
// "canPlay": true,
|
||||
// "canPersist": false,
|
||||
// "canRenew": true,
|
||||
// "licenseDurationSeconds": "600",
|
||||
// "renewalDelaySeconds": "30",
|
||||
// "renewalRetryIntervalSeconds": "10",
|
||||
// "renewWithUsage": false
|
||||
// },
|
||||
// "key": [{
|
||||
// "iv": <|kInitializationVector|>,
|
||||
// "type": "SIGNING",
|
||||
// "key": <computed>
|
||||
// },{
|
||||
// "id": <|kKeyId1|>,
|
||||
// "iv": <|kInitializationVector|>,
|
||||
// "type": "CONTENT",
|
||||
// "level": "SW_SECURE_CRYPTO",
|
||||
// "key": <|kContentKey1|>
|
||||
// },{
|
||||
// "id": <|kKeyId2|>,
|
||||
// "iv": <|kInitializationVector|>,
|
||||
// "type": "CONTENT",
|
||||
// "level": "SW_SECURE_DECODE",
|
||||
// "key": <|kContentKey2|>
|
||||
// },{
|
||||
// "id": <|kKeyId3|>,
|
||||
// "iv": <|kInitializationVector|>,
|
||||
// "type": "CONTENT",
|
||||
// "level": "HW_SECURE_CRYPTO",
|
||||
// "key": <|kContentKey3|>
|
||||
// }],
|
||||
// "licenseStartTime": <from license_request.requestTime>,
|
||||
// "remoteAttestationVerified": false,
|
||||
// "platformVerificationStatus": "PLATFORM_UNVERIFIED"
|
||||
// }
|
||||
std::string CreateLicense(const std::string& serialized_license_request,
|
||||
const std::string& session_key) {
|
||||
DCHECK_EQ(session_key.size(), 16u);
|
||||
|
||||
// Extract values needed for the license.
|
||||
video_widevine::LicenseRequest license_request;
|
||||
CHECK(license_request.ParseFromString(serialized_license_request));
|
||||
const auto request_time = license_request.request_time();
|
||||
|
||||
const std::string key_container_encryption_key =
|
||||
GetEncryptionKey(serialized_license_request, session_key);
|
||||
|
||||
// Now create the license.
|
||||
video_widevine::License license;
|
||||
auto* license_id = license.mutable_id();
|
||||
license_id->set_request_id("REQUEST_ID");
|
||||
license_id->set_session_id("SESSION_ID");
|
||||
license_id->set_type(video_widevine::STREAMING);
|
||||
license_id->set_version(0);
|
||||
|
||||
auto* policy = license.mutable_policy();
|
||||
policy->set_can_play(true);
|
||||
policy->set_can_persist(false);
|
||||
policy->set_can_renew(true);
|
||||
policy->set_license_duration_seconds(600);
|
||||
policy->set_renewal_delay_seconds(30);
|
||||
policy->set_renewal_retry_interval_seconds(10);
|
||||
policy->set_renew_with_usage(false);
|
||||
|
||||
license.add_key()->CopyFrom(
|
||||
CreateSigningKeyContainer(key_container_encryption_key));
|
||||
license.add_key()->CopyFrom(CreateContentKeyContainer(
|
||||
SoftwareCryptoKey(), key_container_encryption_key));
|
||||
license.add_key()->CopyFrom(CreateContentKeyContainer(
|
||||
SoftwareDecodeKey(), key_container_encryption_key));
|
||||
license.add_key()->CopyFrom(CreateContentKeyContainer(
|
||||
HardwareCryptoKey(), key_container_encryption_key));
|
||||
|
||||
license.set_license_start_time(request_time);
|
||||
license.set_remote_attestation_verified(false);
|
||||
license.set_platform_verification_status(
|
||||
video_widevine::PlatformVerificationStatus::PLATFORM_UNVERIFIED);
|
||||
|
||||
return license.SerializeAsString();
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved.
|
||||
|
||||
#ifndef WHITEBOX_API_LICENSE_TEST_HELPER_H_
|
||||
#define WHITEBOX_API_LICENSE_TEST_HELPER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace widevine {
|
||||
|
||||
// Returns a serialized LicenseRequest.
|
||||
std::string CreateLicenseRequest();
|
||||
|
||||
// Returns a serialized License based on |serialized_license_request| and
|
||||
// |session_key|. The license contains 3 content keys (key1, key2, key3)
|
||||
// with levels SW_SECURE_CRYPTO, SW_SECURE_DECODE, and HW_SECURE_CRYPTO,
|
||||
// respectively.
|
||||
std::string CreateLicense(const std::string& serialized_license_request,
|
||||
const std::string& session_key);
|
||||
|
||||
// Returns the key ID for each key.
|
||||
std::vector<uint8_t> GetSoftwareCryptoKeyId();
|
||||
std::vector<uint8_t> GetSoftwareDecodeKeyId();
|
||||
std::vector<uint8_t> GetHardwareCryptoKeyId();
|
||||
|
||||
// Returns a key ID which is not included in the license.
|
||||
std::vector<uint8_t> GetUnusedKeyId();
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
#endif // WHITEBOX_API_LICENSE_TEST_HELPER_H_
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "api/export.h"
|
||||
#include "api/result.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -38,9 +39,9 @@ typedef enum {
|
||||
// WB_RESULT_INVALID_PARAMETER if |whitebox_init_data| was null or invalid.
|
||||
//
|
||||
// WB_RESULT_OUT_OF_MEMORY if the necessary memory could not be allocated.
|
||||
WB_Result WB_License_Create(const uint8_t* whitebox_init_data,
|
||||
size_t whitebox_init_data_size,
|
||||
WB_License_Whitebox** whitebox);
|
||||
WB_API WB_Result WB_License_Create(const uint8_t* whitebox_init_data,
|
||||
size_t whitebox_init_data_size,
|
||||
WB_License_Whitebox** whitebox);
|
||||
|
||||
// Releases all resources used by the white-box instance pointed to by
|
||||
// |whitebox|.
|
||||
@@ -48,7 +49,7 @@ WB_Result WB_License_Create(const uint8_t* whitebox_init_data,
|
||||
// Args:
|
||||
// whitebox (in) : A pointer to a white-box instance. Passing in null will
|
||||
// result in a no-op.
|
||||
void WB_License_Delete(WB_License_Whitebox* whitebox);
|
||||
WB_API void WB_License_Delete(WB_License_Whitebox* whitebox);
|
||||
|
||||
// Signs a license request using the CDM's private signing key.
|
||||
//
|
||||
@@ -74,11 +75,12 @@ void WB_License_Delete(WB_License_Whitebox* whitebox);
|
||||
//
|
||||
// WB_RESULT_BUFFER_TOO_SMALL if |signature_size| (as input) was less than the
|
||||
// required size.
|
||||
WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox,
|
||||
const uint8_t* license_request,
|
||||
size_t license_request_size,
|
||||
uint8_t* signature,
|
||||
size_t* signature_size);
|
||||
WB_API WB_Result
|
||||
WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox,
|
||||
const uint8_t* license_request,
|
||||
size_t license_request_size,
|
||||
uint8_t* signature,
|
||||
size_t* signature_size);
|
||||
|
||||
// Verifies a license response using HMAC and the server signing key.
|
||||
//
|
||||
@@ -93,6 +95,13 @@ WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox,
|
||||
// Args:
|
||||
// whitebox (in/out) : The white-box instance that will load the keys.
|
||||
//
|
||||
// core_message (in) : Serialized information communicating the structure of
|
||||
// |message|. Signature verification should be done on |core_message| +
|
||||
// |message|.
|
||||
//
|
||||
// core_message_size (in) : The number of bytes in |core_message|. If this is
|
||||
// zero, it means that there was no meta message provided for the message.
|
||||
//
|
||||
// message (in) : The message field of the license response.
|
||||
//
|
||||
// message_size (in) : The number of bytes in |message|.
|
||||
@@ -114,26 +123,30 @@ WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox,
|
||||
// WB_RESULT_OK if the response was verified and the keys were loaded into
|
||||
// |whitebox|.
|
||||
//
|
||||
// WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |message| was null,
|
||||
// if |message_size| was zero, if |message| did not conform to the expected
|
||||
// format, if |signature| was null, if |signature_size| was incorrect, if
|
||||
// |session_key| was null, if |session_key_size| was incorrect, if
|
||||
// |session_key| could not be unwrapped correctly, if |license_request| was
|
||||
// null, or if |license_request_size| was zero.
|
||||
// WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |core_message| was
|
||||
// null, if |message| was null, if |message_size| was zero, if |message| did
|
||||
// not conform to the expected format, if |signature| was null, if
|
||||
// |signature_size| was incorrect, if |session_key| was null, if
|
||||
// |session_key_size| was incorrect, if |session_key| could not be unwrapped
|
||||
// correctly, if |license_request| was null, or if |license_request_size| was
|
||||
// zero.
|
||||
//
|
||||
// WB_RESULT_INVALID_SIGNATURE if |message|'s signature does not match
|
||||
// |signature|.
|
||||
//
|
||||
// WB_RESULT_INVALID_STATE if a license has already been loaded.
|
||||
WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
|
||||
const uint8_t* message,
|
||||
size_t message_size,
|
||||
const uint8_t* signature,
|
||||
size_t signature_size,
|
||||
const uint8_t* session_key,
|
||||
size_t session_key_size,
|
||||
const uint8_t* license_request,
|
||||
size_t license_request_size);
|
||||
WB_API WB_Result
|
||||
WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
|
||||
const uint8_t* core_message,
|
||||
size_t core_message_size,
|
||||
const uint8_t* message,
|
||||
size_t message_size,
|
||||
const uint8_t* signature,
|
||||
size_t signature_size,
|
||||
const uint8_t* session_key,
|
||||
size_t session_key_size,
|
||||
const uint8_t* license_request,
|
||||
size_t license_request_size);
|
||||
|
||||
// Signs |message| and return the signature via |signature| using HMAC and the
|
||||
// client renewal signing key
|
||||
@@ -162,11 +175,12 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
|
||||
// required size.
|
||||
//
|
||||
// WB_RESULT_INVALID_STATE if |whitebox| had no signing keys.
|
||||
WB_Result WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox,
|
||||
const uint8_t* message,
|
||||
size_t message_size,
|
||||
uint8_t* signature,
|
||||
size_t* signature_size);
|
||||
WB_API WB_Result
|
||||
WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox,
|
||||
const uint8_t* message,
|
||||
size_t message_size,
|
||||
uint8_t* signature,
|
||||
size_t* signature_size);
|
||||
|
||||
// Verifies the renewal response using HMAC and the server signing key.
|
||||
//
|
||||
@@ -192,11 +206,12 @@ WB_Result WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox,
|
||||
// |signature|.
|
||||
//
|
||||
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
|
||||
WB_Result WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox,
|
||||
const uint8_t* message,
|
||||
size_t message_size,
|
||||
const uint8_t* signature,
|
||||
size_t signature_size);
|
||||
WB_API WB_Result
|
||||
WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox,
|
||||
const uint8_t* message,
|
||||
size_t message_size,
|
||||
const uint8_t* signature,
|
||||
size_t signature_size);
|
||||
|
||||
// Gets the secret string needed by WB_License_Unmask() in order to unmask the
|
||||
// masked decrypted content returned by WB_License_MaskedDecrypt().
|
||||
@@ -240,12 +255,12 @@ WB_Result WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox,
|
||||
// the required size.
|
||||
//
|
||||
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
|
||||
WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox,
|
||||
WB_CipherMode mode,
|
||||
const uint8_t* key_id,
|
||||
size_t key_id_size,
|
||||
uint8_t* secret_string,
|
||||
size_t* secret_string_size);
|
||||
WB_API WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox,
|
||||
WB_CipherMode mode,
|
||||
const uint8_t* key_id,
|
||||
size_t key_id_size,
|
||||
uint8_t* secret_string,
|
||||
size_t* secret_string_size);
|
||||
|
||||
// Decrypts |input_data| and writes the plaintext to |output_data|.
|
||||
//
|
||||
@@ -295,16 +310,16 @@ WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox,
|
||||
// the required size.
|
||||
//
|
||||
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
|
||||
WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox,
|
||||
WB_CipherMode mode,
|
||||
const uint8_t* key_id,
|
||||
size_t key_id_size,
|
||||
const uint8_t* input_data,
|
||||
size_t input_data_size,
|
||||
const uint8_t* iv,
|
||||
size_t iv_size,
|
||||
uint8_t* output_data,
|
||||
size_t* output_data_size);
|
||||
WB_API WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox,
|
||||
WB_CipherMode mode,
|
||||
const uint8_t* key_id,
|
||||
size_t key_id_size,
|
||||
const uint8_t* input_data,
|
||||
size_t input_data_size,
|
||||
const uint8_t* iv,
|
||||
size_t iv_size,
|
||||
uint8_t* output_data,
|
||||
size_t* output_data_size);
|
||||
|
||||
// Decrypts |input_data| and write the obfuscated plaintext to
|
||||
// |masked_output_data|. The obfuscated plaintext can be deobfuscated using
|
||||
@@ -359,16 +374,16 @@ WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox,
|
||||
// than the required size.
|
||||
//
|
||||
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
|
||||
WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox,
|
||||
WB_CipherMode mode,
|
||||
const uint8_t* key_id,
|
||||
size_t key_id_size,
|
||||
const uint8_t* input_data,
|
||||
size_t input_data_size,
|
||||
const uint8_t* iv,
|
||||
size_t iv_size,
|
||||
uint8_t* masked_output_data,
|
||||
size_t* masked_output_data_size);
|
||||
WB_API WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox,
|
||||
WB_CipherMode mode,
|
||||
const uint8_t* key_id,
|
||||
size_t key_id_size,
|
||||
const uint8_t* input_data,
|
||||
size_t input_data_size,
|
||||
const uint8_t* iv,
|
||||
size_t iv_size,
|
||||
uint8_t* masked_output_data,
|
||||
size_t* masked_output_data_size);
|
||||
|
||||
// Unmasks a subset of the data in |masked_data| using |secret_string| and
|
||||
// writes it to |unmasked_data|.
|
||||
@@ -380,6 +395,9 @@ WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox,
|
||||
// It is assumed that indexes between 0 and |size - 1| (inclusive) are all valid
|
||||
// indexes into |unmasked_data|.
|
||||
//
|
||||
// The memory range used for |masked_data| must not overlap with
|
||||
// |unmasked_data|.
|
||||
//
|
||||
// Args:
|
||||
// masked_data (in) : The masked data to read from.
|
||||
//
|
||||
@@ -393,12 +411,12 @@ WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox,
|
||||
// secret_string_size (in) : The number of bytes in |secret_string|.
|
||||
//
|
||||
// unmasked_data (out) : The output buffer to write the unmasked data to.
|
||||
void WB_License_Unmask(const uint8_t* masked_data,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
const uint8_t* secret_string,
|
||||
size_t secret_string_size,
|
||||
uint8_t* unmasked_data);
|
||||
WB_API void WB_License_Unmask(const uint8_t* masked_data,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
const uint8_t* secret_string,
|
||||
size_t secret_string_size,
|
||||
uint8_t* unmasked_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -72,12 +72,14 @@ class LicenseWhiteboxChromeOSTest
|
||||
License license;
|
||||
builder.Build(*public_key_, &license);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
// This is the strictest level of enforcement. It will be the last one
|
||||
|
||||
@@ -50,12 +50,14 @@ class LicenseWhiteboxDecryptBenchmark
|
||||
WB_RESULT_OK);
|
||||
|
||||
const auto license = CreateLicense();
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
void TearDown() override { WB_License_Delete(whitebox_); }
|
||||
|
||||
@@ -54,12 +54,14 @@ class LicenseWhiteboxDecryptTest : public LicenseWhiteboxTestBase {
|
||||
License license;
|
||||
builder.Build(*public_key_, &license);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
// We need two special keys for this test, one that will be used for a
|
||||
|
||||
@@ -48,12 +48,14 @@ class LicenseWhiteboxGetSecretStringTest : public LicenseWhiteboxTestBase {
|
||||
License license;
|
||||
builder.Build(*public_key_, &license);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
// We need two special keys for this test, one that will be used for a
|
||||
|
||||
@@ -66,12 +66,14 @@ class LicenseWhiteboxMaskedDecryptTest : public LicenseWhiteboxTestBase {
|
||||
License license;
|
||||
builder.Build(*public_key_, &license);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
// We need two special keys for this test, one that will be used for a
|
||||
|
||||
@@ -50,10 +50,12 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseBenchmark,
|
||||
WB_RESULT_OK);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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()),
|
||||
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);
|
||||
|
||||
WB_License_Delete(whitebox_);
|
||||
@@ -84,10 +86,12 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseBenchmark,
|
||||
WB_RESULT_OK);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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()),
|
||||
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);
|
||||
|
||||
sampler.Push(timer.Get());
|
||||
@@ -115,10 +119,12 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseBenchmark, ProcessLicenseResponse) {
|
||||
timer.Reset();
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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()),
|
||||
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);
|
||||
|
||||
sampler.Push(timer.Get());
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved.
|
||||
|
||||
#include "api/license_whitebox.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "api/license_whitebox_test_base.h"
|
||||
#include "api/test_license_builder.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace widevine {
|
||||
class LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest
|
||||
: public LicenseWhiteboxTestBase {
|
||||
protected:
|
||||
void UseLicenseWithoutSigningKey(bool use_odk) {
|
||||
TestLicenseBuilder builder;
|
||||
builder.AddStubbedContentKey();
|
||||
builder.SetUseODK(use_odk);
|
||||
builder.Build(*public_key_, &license_);
|
||||
}
|
||||
|
||||
void UseLicenseWithSigningKey(const std::vector<uint8_t>& padding,
|
||||
bool use_odk) {
|
||||
TestLicenseBuilder builder;
|
||||
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey(), padding);
|
||||
builder.AddStubbedContentKey();
|
||||
builder.SetUseODK(use_odk);
|
||||
builder.Build(*public_key_, &license_);
|
||||
}
|
||||
|
||||
License license_;
|
||||
};
|
||||
|
||||
// Success tests below test with and without the ODK.
|
||||
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
|
||||
SuccessWithoutOdkAndWithoutSigningKey) {
|
||||
UseLicenseWithoutSigningKey(/* use_odk = */ false);
|
||||
|
||||
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,
|
||||
SuccessWithOdkAndWithoutSigningKey) {
|
||||
UseLicenseWithoutSigningKey(/* use_odk = */ true);
|
||||
|
||||
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,
|
||||
SuccessWithoutOdkAndWithSigningKeyNoPadding) {
|
||||
UseLicenseWithSigningKey(TestLicenseBuilder::NoPadding(),
|
||||
/* use_odk = */ false);
|
||||
|
||||
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,
|
||||
SuccessWithOdkAndWithSigningKeyNoPadding) {
|
||||
UseLicenseWithSigningKey(TestLicenseBuilder::NoPadding(),
|
||||
/* use_odk = */ true);
|
||||
|
||||
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,
|
||||
SuccessWithoutOdkAndWithSigningKeyPKSC8Padding) {
|
||||
UseLicenseWithSigningKey(TestLicenseBuilder::PKSC8Padding(),
|
||||
/* use_odk = */ false);
|
||||
|
||||
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,
|
||||
SuccessWithOdkAndWithSigningKeyPKSC8Padding) {
|
||||
UseLicenseWithSigningKey(TestLicenseBuilder::PKSC8Padding(),
|
||||
/* use_odk = */ true);
|
||||
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseWithCoreMessageTest,
|
||||
InvalidSignatureWithZeroCoreMessageSize) {
|
||||
UseLicenseWithoutSigningKey(/* use_odk = */ true);
|
||||
|
||||
// |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);
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
class LicenseWhiteboxProcessLicenseResponseTest
|
||||
: public LicenseWhiteboxTestBase {
|
||||
protected:
|
||||
@@ -37,36 +36,42 @@ class LicenseWhiteboxProcessLicenseResponseTest
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseTest, SuccessWithoutSigningKey) {
|
||||
UseLicenseWithoutSigningKey();
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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(LicenseWhiteboxProcessLicenseResponseTest,
|
||||
SuccessWithSigningKeyNoPadding) {
|
||||
UseLicenseWithSigningKey(TestLicenseBuilder::NoPadding());
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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(LicenseWhiteboxProcessLicenseResponseTest,
|
||||
SuccessWithSigningKeyPKSC8Padding) {
|
||||
UseLicenseWithSigningKey(TestLicenseBuilder::PKSC8Padding());
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
class LicenseWhiteboxProcessLicenseResponseErrorTest
|
||||
@@ -85,24 +90,28 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidSignatureForModifedMessage) {
|
||||
Modify(&license_.message);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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(), 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_SIGNATURE);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidSignatureForModifedSignature) {
|
||||
Modify(&license_.signature);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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(), 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_SIGNATURE);
|
||||
}
|
||||
|
||||
// The license request is used to derive the signing key. If the request was
|
||||
@@ -111,28 +120,33 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidSignatureForModifedLicenseRequest) {
|
||||
Modify(&license_.request);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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(), 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_SIGNATURE);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidParameterForNullWhitebox) {
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
nullptr, 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);
|
||||
ASSERT_EQ(
|
||||
WB_License_ProcessLicenseResponse(
|
||||
nullptr, 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_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidParameterForNullMessage) {
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, nullptr, license_.message.size(),
|
||||
whitebox_, license_.core_message.data(),
|
||||
license_.core_message.size(), nullptr, license_.message.size(),
|
||||
license_.signature.data(), license_.signature.size(),
|
||||
license_.session_key.data(), license_.session_key.size(),
|
||||
license_.request.data(), license_.request.size()),
|
||||
@@ -142,7 +156,8 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidParameterForZeroMessageSize) {
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, license_.message.data(), 0,
|
||||
whitebox_, license_.core_message.data(),
|
||||
license_.core_message.size(), license_.message.data(), 0,
|
||||
license_.signature.data(), license_.signature.size(),
|
||||
license_.session_key.data(), license_.session_key.size(),
|
||||
license_.request.data(), license_.request.size()),
|
||||
@@ -152,40 +167,44 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidParameterForNullSignature) {
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, license_.message.data(), license_.message.size(),
|
||||
nullptr, license_.signature.size(), license_.session_key.data(),
|
||||
license_.session_key.size(), license_.request.data(),
|
||||
license_.request.size()),
|
||||
whitebox_, license_.core_message.data(),
|
||||
license_.core_message.size(), license_.message.data(),
|
||||
license_.message.size(), nullptr, license_.signature.size(),
|
||||
license_.session_key.data(), license_.session_key.size(),
|
||||
license_.request.data(), license_.request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidParameterForInvalidSignatureSize) {
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, license_.message.data(), license_.message.size(),
|
||||
license_.signature.data(), 5, license_.session_key.data(),
|
||||
license_.session_key.size(), license_.request.data(),
|
||||
license_.request.size()),
|
||||
whitebox_, license_.core_message.data(),
|
||||
license_.core_message.size(), license_.message.data(),
|
||||
license_.message.size(), license_.signature.data(), 5,
|
||||
license_.session_key.data(), license_.session_key.size(),
|
||||
license_.request.data(), license_.request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidParameterForNullSessionKey) {
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, license_.message.data(), license_.message.size(),
|
||||
license_.signature.data(), license_.signature.size(), nullptr,
|
||||
license_.session_key.size(), license_.request.data(),
|
||||
license_.request.size()),
|
||||
whitebox_, license_.core_message.data(),
|
||||
license_.core_message.size(), license_.message.data(),
|
||||
license_.message.size(), license_.signature.data(),
|
||||
license_.signature.size(), nullptr, license_.session_key.size(),
|
||||
license_.request.data(), license_.request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidParameterForInvalidSessionKeySize) {
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, license_.message.data(), license_.message.size(),
|
||||
license_.signature.data(), license_.signature.size(),
|
||||
license_.session_key.data(), 5, license_.request.data(),
|
||||
license_.request.size()),
|
||||
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(), 5,
|
||||
license_.request.data(), license_.request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
@@ -195,31 +214,35 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidParameterForModifedSessionKey) {
|
||||
Modify(&license_.session_key);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidParameterForNullLicenseRequest) {
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, license_.message.data(), license_.message.size(),
|
||||
license_.signature.data(), license_.signature.size(),
|
||||
license_.session_key.data(), license_.session_key.size(),
|
||||
nullptr, license_.request.size()),
|
||||
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(), nullptr, license_.request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
||||
InvalidParameterForZeroLienseRequestSize) {
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, license_.message.data(), license_.message.size(),
|
||||
license_.signature.data(), license_.signature.size(),
|
||||
license_.session_key.data(), license_.session_key.size(),
|
||||
license_.request.data(), 0),
|
||||
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(), 0),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
@@ -240,21 +263,25 @@ class LicenseWhiteboxMultiLicenseTest
|
||||
TEST_F(LicenseWhiteboxMultiLicenseTest, InvalidState) {
|
||||
// Load the first license. This one is expected to succeed as the whitebox has
|
||||
// not loaded a license yet.
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
|
||||
// Attempt to load the same license again. This should fail as it already has
|
||||
// a license (even though it is the same license).
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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_STATE);
|
||||
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_INVALID_STATE);
|
||||
}
|
||||
|
||||
// Even though a whitebox can only load a license once, if it fails to load a
|
||||
@@ -264,21 +291,25 @@ TEST_F(LicenseWhiteboxMultiLicenseTest, SuccessAfterFailure) {
|
||||
// in key derivation which is a later step of license parsing.
|
||||
std::vector<uint8_t> bad_request = license_.request;
|
||||
Modify(&bad_request);
|
||||
ASSERT_NE(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, license_.message.data(), license_.message.size(),
|
||||
license_.signature.data(), license_.signature.size(),
|
||||
license_.session_key.data(), license_.session_key.size(),
|
||||
bad_request.data(), bad_request.size()),
|
||||
WB_RESULT_OK);
|
||||
ASSERT_NE(
|
||||
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(),
|
||||
bad_request.data(), bad_request.size()),
|
||||
WB_RESULT_OK);
|
||||
|
||||
// Attempt to load the license again, but use the correct (unmodified)
|
||||
// request.
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
@@ -38,12 +38,14 @@ class LicenseWhiteboxSignBenchmark : public LicenseWhiteboxBenchmark {
|
||||
WB_RESULT_OK);
|
||||
|
||||
const auto license = CreateLicense();
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
void TearDown() override { WB_License_Delete(whitebox_); }
|
||||
|
||||
@@ -36,12 +36,14 @@ class LicenseWhiteboxSignRenewalRequestTest : public LicenseWhiteboxTestBase {
|
||||
License license;
|
||||
builder.Build(*public_key_, &license);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
// Get the expected signature for |message|. By returning the message, this
|
||||
@@ -186,12 +188,14 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest, InvalidStateForNoSigningKey) {
|
||||
License license;
|
||||
builder.Build(*public_key_, &license);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
|
||||
ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(),
|
||||
garbage_request_.size(),
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved.
|
||||
|
||||
#include "api/license_whitebox.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "api/license_test_helper.h"
|
||||
#include "api/test_data.h"
|
||||
#include "crypto_utils/rsa_key.h"
|
||||
#include "testing/include/gtest/gtest.h"
|
||||
|
||||
using RsaPublicKey = widevine::RsaPublicKey;
|
||||
|
||||
namespace {
|
||||
|
||||
const uint8_t kDummyMessage[] = {
|
||||
0x1e, 0x70, 0xbd, 0xeb, 0x24, 0xf2, 0x9d, 0x05, 0xc5, 0xb5,
|
||||
0xf4, 0xca, 0xe6, 0x1d, 0x01, 0x97, 0x29, 0xf4, 0xe0, 0x7c,
|
||||
0xfd, 0xcc, 0x97, 0x8d, 0xc2, 0xbb, 0x2d, 0x9b, 0x6b, 0x45,
|
||||
0x06, 0xbd, 0x2c, 0x66, 0x10, 0x42, 0x73, 0x8d, 0x88, 0x9b,
|
||||
0x18, 0xcc, 0xcb, 0x7e, 0x43, 0x23, 0x06, 0xe9, 0x8f, 0x8f,
|
||||
};
|
||||
const size_t kDummyMessageSize = sizeof(kDummyMessage);
|
||||
|
||||
// Size of a license signature. This must be big enough to hold the signature
|
||||
// returned by WB_License_SignLicenseRequest().
|
||||
constexpr size_t kSignatureSize = 256;
|
||||
|
||||
std::string AsString(const uint8_t* buffer, size_t buffer_size) {
|
||||
return std::string(reinterpret_cast<const char*>(buffer), buffer_size);
|
||||
}
|
||||
|
||||
// Used to test the rest of the whitebox API as this class creates |whitebox_|
|
||||
// during setup, so it is available for all tests. It also creates |public_key_|
|
||||
// which is the matching RSA public key that can be used to verify signing
|
||||
// operations inside the whitebox.
|
||||
class LicenseWhiteboxTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
const std::vector<uint8_t> init_data = GetLicenseInitData();
|
||||
ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_),
|
||||
WB_RESULT_OK);
|
||||
|
||||
std::vector<uint8_t> public_key = GetMatchingLicensePublicKey();
|
||||
public_key_.reset(
|
||||
RsaPublicKey::Create(AsString(public_key.data(), public_key.size())));
|
||||
ASSERT_TRUE(public_key_);
|
||||
}
|
||||
|
||||
void TearDown() override { WB_License_Delete(whitebox_); }
|
||||
|
||||
// Public key as an usable object.
|
||||
std::unique_ptr<RsaPublicKey> public_key_;
|
||||
|
||||
WB_License_Whitebox* whitebox_;
|
||||
};
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, SignAndVerifySucceedsWithRandomData) {
|
||||
uint8_t signature[kSignatureSize];
|
||||
size_t signature_size = kSignatureSize;
|
||||
ASSERT_EQ(
|
||||
WB_License_SignLicenseRequest(whitebox_, kDummyMessage, kDummyMessageSize,
|
||||
signature, &signature_size),
|
||||
WB_RESULT_OK);
|
||||
|
||||
// Verify the signature.
|
||||
ASSERT_TRUE(
|
||||
public_key_->VerifySignature(AsString(kDummyMessage, kDummyMessageSize),
|
||||
AsString(signature, signature_size)));
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, SignAndVerifySucceedsWithLicenseRequest) {
|
||||
const std::string license_request = widevine::CreateLicenseRequest();
|
||||
|
||||
uint8_t signature[kSignatureSize];
|
||||
size_t signature_size = kSignatureSize;
|
||||
ASSERT_EQ(
|
||||
WB_License_SignLicenseRequest(
|
||||
whitebox_, reinterpret_cast<const uint8_t*>(license_request.data()),
|
||||
license_request.size(), signature, &signature_size),
|
||||
WB_RESULT_OK);
|
||||
|
||||
ASSERT_TRUE(public_key_->VerifySignature(
|
||||
license_request, AsString(signature, signature_size)));
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, SignLicenseRequestFailsWithWhiteboxNull) {
|
||||
uint8_t signature[kSignatureSize];
|
||||
size_t signature_size = kSignatureSize;
|
||||
ASSERT_EQ(
|
||||
WB_License_SignLicenseRequest(nullptr, kDummyMessage, kDummyMessageSize,
|
||||
signature, &signature_size),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, SignLicenseRequestFailsWithMessageNull) {
|
||||
uint8_t signature[kSignatureSize];
|
||||
size_t signature_size = kSignatureSize;
|
||||
ASSERT_EQ(WB_License_SignLicenseRequest(whitebox_, nullptr, kDummyMessageSize,
|
||||
signature, &signature_size),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, SignLicenseRequestFailsWithMessageSizeZero) {
|
||||
uint8_t signature[kSignatureSize];
|
||||
size_t signature_size = kSignatureSize;
|
||||
ASSERT_EQ(WB_License_SignLicenseRequest(whitebox_, kDummyMessage, 0,
|
||||
signature, &signature_size),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, SignLicenseRequestFailsWithSignatureNull) {
|
||||
size_t signature_size = kSignatureSize;
|
||||
ASSERT_EQ(
|
||||
WB_License_SignLicenseRequest(whitebox_, kDummyMessage, kDummyMessageSize,
|
||||
nullptr, &signature_size),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, SignLicenseRequestFailsWithSignatureSizeNull) {
|
||||
uint8_t signature[kSignatureSize];
|
||||
ASSERT_EQ(
|
||||
WB_License_SignLicenseRequest(whitebox_, kDummyMessage, kDummyMessageSize,
|
||||
signature, nullptr),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, SignLicenseRequestFailsWithSignatureSizeZero) {
|
||||
uint8_t signature[kSignatureSize];
|
||||
size_t signature_size = 0;
|
||||
ASSERT_EQ(
|
||||
WB_License_SignLicenseRequest(whitebox_, kDummyMessage, kDummyMessageSize,
|
||||
signature, &signature_size),
|
||||
WB_RESULT_BUFFER_TOO_SMALL);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, SignLicenseRequestFailsWithSignatureTooSmall) {
|
||||
uint8_t signature[10];
|
||||
size_t signature_size = sizeof(signature);
|
||||
ASSERT_EQ(
|
||||
WB_License_SignLicenseRequest(whitebox_, kDummyMessage, kDummyMessageSize,
|
||||
signature, &signature_size),
|
||||
WB_RESULT_BUFFER_TOO_SMALL);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, ProcessLicenseResponseFailsWithWhiteboxNull) {
|
||||
std::vector<uint8_t> message{1, 2, 3};
|
||||
std::vector<uint8_t> signature{4, 5, 6, 7};
|
||||
std::vector<uint8_t> session_key{1, 2, 3, 4, 5, 6, 7, 8};
|
||||
std::vector<uint8_t> license_request{10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
nullptr, message.data(), message.size(), signature.data(),
|
||||
signature.size(), session_key.data(), session_key.size(),
|
||||
license_request.data(), license_request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, ProcessLicenseResponseFailsWithMessageNull) {
|
||||
std::vector<uint8_t> message{1, 2, 3};
|
||||
std::vector<uint8_t> signature{4, 5, 6, 7};
|
||||
std::vector<uint8_t> session_key{1, 2, 3, 4, 5, 6, 7, 8};
|
||||
std::vector<uint8_t> license_request{10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, nullptr, message.size(), signature.data(),
|
||||
signature.size(), session_key.data(), session_key.size(),
|
||||
license_request.data(), license_request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, ProcessLicenseResponseFailsWithMessageSizeZero) {
|
||||
std::vector<uint8_t> message{/* empty */};
|
||||
std::vector<uint8_t> signature{4, 5, 6, 7};
|
||||
std::vector<uint8_t> session_key{1, 2, 3, 4, 5, 6, 7, 8};
|
||||
std::vector<uint8_t> license_request{10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, message.data(), message.size(), signature.data(),
|
||||
signature.size(), session_key.data(), session_key.size(),
|
||||
license_request.data(), license_request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, ProcessLicenseResponseFailsWithSignatureNull) {
|
||||
std::vector<uint8_t> message{1, 2, 3};
|
||||
std::vector<uint8_t> signature{4, 5, 6, 7};
|
||||
std::vector<uint8_t> session_key{1, 2, 3, 4, 5, 6, 7, 8};
|
||||
std::vector<uint8_t> license_request{10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, nullptr, message.size(), nullptr, signature.size(),
|
||||
session_key.data(), session_key.size(), license_request.data(),
|
||||
license_request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, ProcessLicenseResponseFailsWithSignatureSizeZero) {
|
||||
std::vector<uint8_t> message{1, 2, 3};
|
||||
std::vector<uint8_t> signature{/* empty */};
|
||||
std::vector<uint8_t> session_key{1, 2, 3, 4, 5, 6, 7, 8};
|
||||
std::vector<uint8_t> license_request{10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, message.data(), message.size(), signature.data(),
|
||||
signature.size(), session_key.data(), session_key.size(),
|
||||
license_request.data(), license_request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, ProcessLicenseResponseFailsWithSessionKeyNull) {
|
||||
std::vector<uint8_t> message{1, 2, 3};
|
||||
std::vector<uint8_t> signature{4, 5, 6, 7};
|
||||
std::vector<uint8_t> session_key{1, 2, 3, 4, 5, 6, 7, 8};
|
||||
std::vector<uint8_t> license_request{10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, message.data(), message.size(), signature.data(),
|
||||
signature.size(), nullptr, session_key.size(),
|
||||
license_request.data(), license_request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, ProcessLicenseResponseFailsWithSessionKeySizeZero) {
|
||||
std::vector<uint8_t> message{1, 2, 3};
|
||||
std::vector<uint8_t> signature{4, 5, 6, 7};
|
||||
std::vector<uint8_t> session_key{/* empty */};
|
||||
std::vector<uint8_t> license_request{10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, message.data(), message.size(), signature.data(),
|
||||
signature.size(), session_key.data(), session_key.size(),
|
||||
license_request.data(), license_request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, ProcessLicenseResponseFailsWithRequestNull) {
|
||||
std::vector<uint8_t> message{1, 2, 3};
|
||||
std::vector<uint8_t> signature{4, 5, 6, 7};
|
||||
std::vector<uint8_t> session_key{1, 2, 3, 4, 5, 6, 7, 8};
|
||||
std::vector<uint8_t> license_request{10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, message.data(), message.size(), signature.data(),
|
||||
signature.size(), session_key.data(), session_key.size(),
|
||||
nullptr, license_request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxTest, ProcessLicenseResponseFailsWithRequestSizeZero) {
|
||||
std::vector<uint8_t> message{1, 2, 3};
|
||||
std::vector<uint8_t> signature{4, 5, 6, 7};
|
||||
std::vector<uint8_t> session_key{1, 2, 3, 4, 5, 6, 7, 8};
|
||||
std::vector<uint8_t> license_request{/* empty */};
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, message.data(), message.size(), signature.data(),
|
||||
signature.size(), session_key.data(), session_key.size(),
|
||||
license_request.data(), license_request.size()),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -34,12 +34,14 @@ class LicenseWhiteboxVerifyBenchmark : public LicenseWhiteboxBenchmark {
|
||||
WB_RESULT_OK);
|
||||
|
||||
const auto license = CreateLicense();
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
void TearDown() override { WB_License_Delete(whitebox_); }
|
||||
|
||||
@@ -36,12 +36,14 @@ class LicenseWhiteboxVerifyRenewalResponseTest
|
||||
License license;
|
||||
builder.Build(*public_key_, &license);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Sign(const std::vector<uint8_t>& message) {
|
||||
@@ -210,12 +212,14 @@ TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, InvalidStateForNoSigningKey) {
|
||||
License license;
|
||||
builder.Build(*public_key_, &license);
|
||||
|
||||
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
||||
whitebox_, 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);
|
||||
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);
|
||||
|
||||
ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_,
|
||||
garbage_renewal_message_.data(),
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "crypto_utils/aes_cbc_encryptor.h"
|
||||
#include "crypto_utils/crypto_util.h"
|
||||
#include "crypto_utils/sha_util.h"
|
||||
#include "oemcrypto/odk/include/core_message_deserialize.h"
|
||||
#include "oemcrypto/odk/include/core_message_serialize_proto.h"
|
||||
#include "oemcrypto/odk/include/odk.h"
|
||||
#include "oemcrypto/odk/include/odk_structs.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
@@ -98,6 +102,95 @@ std::string DeriveIV(const std::vector<uint8_t>& context) {
|
||||
return crypto_util::DeriveIv(context_str);
|
||||
}
|
||||
|
||||
void UpdateKeyControlBlock(
|
||||
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
|
||||
// fields. The fields are defined to be in big-endian byte order.
|
||||
//
|
||||
// Bytes 0..3: Verification.
|
||||
// Constant bytes “kctl”, “kc09”, “kc10”, “kc11”, ... “kc15”.
|
||||
// Bytes 4..7: Obsolete.
|
||||
// Bytes 8..11: Nonce.
|
||||
// Bytes 12..15: Control Bits
|
||||
// Bits 27..26: Security_Level (Only for L3 white-box implementations)
|
||||
// 0 = SW_SECURE_CRYPTO
|
||||
// 1 = SW_SECURE_DECODE
|
||||
// 2 = HW_SECURE_CRYPTO
|
||||
// 3 = HW_SECURE_DECODE or HW_SECURE_ALL
|
||||
std::vector<uint8_t> key_control_block = {
|
||||
'k', 'c', 't', 'l', 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
switch (level) {
|
||||
case video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO:
|
||||
key_control_block[12] = 0x00 << 2;
|
||||
break;
|
||||
case video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_DECODE:
|
||||
key_control_block[12] = 0x01 << 2;
|
||||
break;
|
||||
case video_widevine::License_KeyContainer_SecurityLevel_HW_SECURE_CRYPTO:
|
||||
key_control_block[12] = 0x02 << 2;
|
||||
break;
|
||||
default:
|
||||
key_control_block[12] = 0x03 << 2;
|
||||
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());
|
||||
}
|
||||
|
||||
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.");
|
||||
constexpr uint32_t session_id = 0xcafebabe;
|
||||
constexpr uint32_t nonce = 0xdeadbeef;
|
||||
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce,
|
||||
session_id};
|
||||
|
||||
// Start by making a call to determine how big the core_message for the
|
||||
// request needs to be.
|
||||
size_t core_message_length = 0;
|
||||
auto odk_result = ODK_PrepareCoreLicenseRequest(
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(serialized_request.data())),
|
||||
serialized_request.size(), &core_message_length, &nonce_values);
|
||||
CHECK_EQ(odk_result, OEMCrypto_ERROR_SHORT_BUFFER);
|
||||
|
||||
// Now that we know the size, create |combined_request_message| with room
|
||||
// for the core message and append |serialized_request_|, as the combined
|
||||
// buffer is needed by ODK_PrepareCoreLicenseRequest().
|
||||
std::string combined_request_message;
|
||||
combined_request_message.resize(core_message_length);
|
||||
combined_request_message.append(serialized_request);
|
||||
odk_result = ODK_PrepareCoreLicenseRequest(
|
||||
reinterpret_cast<uint8_t*>(
|
||||
const_cast<char*>(combined_request_message.data())),
|
||||
combined_request_message.size(), &core_message_length, &nonce_values);
|
||||
CHECK_EQ(odk_result, OEMCrypto_SUCCESS);
|
||||
|
||||
// As the core_message is the first part of |combined_request_message|,
|
||||
// extract it.
|
||||
const std::string request_core_message =
|
||||
combined_request_message.substr(0, core_message_length);
|
||||
std::string core_message_hash = widevine::Sha256_Hash(request_core_message);
|
||||
|
||||
oemcrypto_core_message::ODK_LicenseRequest core_request{};
|
||||
CHECK(oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage(
|
||||
request_core_message, &core_request));
|
||||
|
||||
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));
|
||||
return oemcrypto_core_message;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
@@ -132,6 +225,7 @@ TestLicenseBuilder::TestLicenseBuilder() {
|
||||
InitializeResponse(request_, &response_);
|
||||
|
||||
serialized_request_ = request_.SerializeAsString();
|
||||
|
||||
container_key_ = crypto_util::DeriveKey(
|
||||
session_key_, crypto_util::kWrappingKeyLabel, serialized_request_,
|
||||
crypto_util::kWrappingKeySizeBits);
|
||||
@@ -156,17 +250,20 @@ void TestLicenseBuilder::AddSigningKey(const std::vector<uint8_t>& key,
|
||||
}
|
||||
|
||||
void TestLicenseBuilder::AddStubbedContentKey() {
|
||||
const video_widevine::License_KeyContainer_SecurityLevel kLevel =
|
||||
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(
|
||||
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO);
|
||||
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.
|
||||
container->set_key("0000000000000000");
|
||||
// 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());
|
||||
}
|
||||
|
||||
void TestLicenseBuilder::AddContentKey(
|
||||
@@ -192,6 +289,7 @@ void TestLicenseBuilder::AddContentKey(
|
||||
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());
|
||||
}
|
||||
|
||||
void TestLicenseBuilder::AddOperatorSessionKey(
|
||||
@@ -235,6 +333,10 @@ void TestLicenseBuilder::SetVerificationStatus(VerificationStatus setting) {
|
||||
}
|
||||
}
|
||||
|
||||
void TestLicenseBuilder::SetUseODK(bool setting) {
|
||||
use_odk_ = setting;
|
||||
}
|
||||
|
||||
void TestLicenseBuilder::Build(const RsaPublicKey& public_key,
|
||||
License* license) const {
|
||||
DCHECK(license);
|
||||
@@ -246,19 +348,26 @@ void TestLicenseBuilder::Build(const RsaPublicKey& public_key,
|
||||
crypto_util::kSigningKeySizeBits * 2);
|
||||
signing_key.resize(crypto_util::kSigningKeySizeBytes);
|
||||
|
||||
const std::string signature_str =
|
||||
crypto_util::CreateSignatureHmacSha256(signing_key, message_str);
|
||||
|
||||
std::string session_key_str;
|
||||
CHECK(public_key.Encrypt(session_key_, &session_key_str));
|
||||
|
||||
license->request = std::vector<uint8_t>(serialized_request_.begin(),
|
||||
serialized_request_.end());
|
||||
license->message =
|
||||
std::vector<uint8_t>(message_str.begin(), message_str.end());
|
||||
license->signature =
|
||||
std::vector<uint8_t>(signature_str.begin(), signature_str.end());
|
||||
license->session_key =
|
||||
std::vector<uint8_t>(session_key_str.begin(), session_key_str.end());
|
||||
const std::string oemcrypto_core_message =
|
||||
use_odk_ ? GenerateCoreMessage(serialized_request_, message_str)
|
||||
: std::string();
|
||||
|
||||
// If |use_odk_| is false, |oemcrypto_core_message| will be empty.
|
||||
const std::string signature_str = crypto_util::CreateSignatureHmacSha256(
|
||||
signing_key, oemcrypto_core_message + message_str);
|
||||
|
||||
license->request.assign(serialized_request_.begin(),
|
||||
serialized_request_.end());
|
||||
if (!oemcrypto_core_message.empty()) {
|
||||
license->core_message.assign(oemcrypto_core_message.begin(),
|
||||
oemcrypto_core_message.end());
|
||||
}
|
||||
license->message.assign(message_str.begin(), message_str.end());
|
||||
license->signature.assign(signature_str.begin(), signature_str.end());
|
||||
license->session_key.assign(session_key_str.begin(), session_key_str.end());
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace widevine {
|
||||
|
||||
struct License {
|
||||
std::vector<uint8_t> request;
|
||||
|
||||
std::vector<uint8_t> core_message;
|
||||
std::vector<uint8_t> message;
|
||||
std::vector<uint8_t> signature;
|
||||
|
||||
@@ -68,6 +70,10 @@ class TestLicenseBuilder {
|
||||
|
||||
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);
|
||||
|
||||
// Gets the serialized license request and response (in components) that would
|
||||
// have been used in the license exchange.
|
||||
void Build(const RsaPublicKey& public_key, License* license) const;
|
||||
@@ -79,6 +85,7 @@ class TestLicenseBuilder {
|
||||
video_widevine::License response_;
|
||||
std::string serialized_request_;
|
||||
std::string container_key_;
|
||||
bool use_odk_ = false;
|
||||
};
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
Reference in New Issue
Block a user