Remove old test license holder
[ Merged from http://go/wvgerrit/143750 ] The old test license holder would generate a minimal license response, but could not correctly mimic important server logic introduced in the v16 server. Since all integration tests now have policies on the UAT server, we do not need these minimalist license responses anymore. Bug: 192700112 Test: GtsMediaTestCases on sunfish Change-Id: I78c1b6085a6d0239840a11f2b904902210e5e61c
This commit is contained in:
@@ -576,266 +576,6 @@ bool WvCdmTestBase::Initialize(int argc, const char* const argv[],
|
||||
return true;
|
||||
}
|
||||
|
||||
TestLicenseHolder::TestLicenseHolder(CdmEngine* cdm_engine)
|
||||
: cdm_engine_(cdm_engine),
|
||||
oemcrypto_api_(0),
|
||||
session_opened_(false),
|
||||
// Keys are initialized with simple values, and the correct size:
|
||||
derived_mac_key_server_(MAC_KEY_SIZE, 'a'),
|
||||
derived_mac_key_client_(MAC_KEY_SIZE, 'b'),
|
||||
mac_key_server_(MAC_KEY_SIZE, 'c'),
|
||||
mac_key_client_(MAC_KEY_SIZE, 'd'),
|
||||
enc_key_(CONTENT_KEY_SIZE, 'e'),
|
||||
session_key_(CONTENT_KEY_SIZE, 'f') {}
|
||||
|
||||
TestLicenseHolder::~TestLicenseHolder() { CloseSession(); }
|
||||
|
||||
void TestLicenseHolder::OpenSession(const std::string& key_system) {
|
||||
CdmResponseType status =
|
||||
cdm_engine_->OpenSession(key_system, nullptr, nullptr, &session_id_);
|
||||
ASSERT_EQ(status, NO_ERROR);
|
||||
ASSERT_NE("", session_id_) << "Could not open CDM session.";
|
||||
ASSERT_TRUE(cdm_engine_->IsOpenSession(session_id_));
|
||||
session_opened_ = true;
|
||||
}
|
||||
|
||||
void TestLicenseHolder::CloseSession() {
|
||||
if (session_opened_) {
|
||||
cdm_engine_->CloseSession(session_id_);
|
||||
session_opened_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void TestLicenseHolder::GenerateKeyRequest(
|
||||
const std::string& key_id, const std::string& init_data_type_string) {
|
||||
ASSERT_TRUE(session_opened_);
|
||||
CdmAppParameterMap app_parameters;
|
||||
CdmKeySetId key_set_id;
|
||||
InitializationData init_data(init_data_type_string, key_id);
|
||||
if (wvutil::g_cutoff >= wvutil::CDM_LOG_DEBUG) init_data.DumpToLogs();
|
||||
CdmKeyRequest key_request;
|
||||
CdmResponseType result = cdm_engine_->GenerateKeyRequest(
|
||||
session_id_, key_set_id, init_data, kLicenseTypeStreaming, app_parameters,
|
||||
&key_request);
|
||||
EXPECT_EQ(KEY_MESSAGE, result);
|
||||
signed_license_request_data_ = key_request.message;
|
||||
EXPECT_EQ(kKeyRequestTypeInitial, key_request.type);
|
||||
}
|
||||
|
||||
void TestLicenseHolder::CreateDefaultLicense() {
|
||||
video_widevine::SignedMessage signed_message;
|
||||
EXPECT_TRUE(signed_message.ParseFromString(signed_license_request_data_));
|
||||
license_request_data_ = signed_message.msg();
|
||||
video_widevine::LicenseRequest license_request;
|
||||
EXPECT_TRUE(license_request.ParseFromString(license_request_data_));
|
||||
video_widevine::ClientIdentification client_id = license_request.client_id();
|
||||
|
||||
EXPECT_EQ(
|
||||
video_widevine::ClientIdentification_TokenType_DRM_DEVICE_CERTIFICATE,
|
||||
client_id.type());
|
||||
|
||||
oemcrypto_api_ =
|
||||
(client_id.has_client_capabilities() &&
|
||||
client_id.client_capabilities().has_oem_crypto_api_version())
|
||||
? client_id.client_capabilities().oem_crypto_api_version()
|
||||
: 0;
|
||||
|
||||
std::string signed_buffer = license_request_data_;
|
||||
std::string core_message = signed_message.has_oemcrypto_core_message()
|
||||
? signed_message.oemcrypto_core_message()
|
||||
: "";
|
||||
if (oemcrypto_api_ >= 17) {
|
||||
signed_buffer = signed_message.oemcrypto_core_message() + signed_buffer;
|
||||
}
|
||||
|
||||
// Extract the RSA key from the DRM certificate.
|
||||
std::string token = client_id.token();
|
||||
video_widevine::SignedDrmCertificate signed_drm_cert;
|
||||
EXPECT_TRUE(signed_drm_cert.ParseFromString(token));
|
||||
video_widevine::DrmCertificate drm_cert;
|
||||
EXPECT_TRUE(drm_cert.ParseFromString(signed_drm_cert.drm_certificate()));
|
||||
EXPECT_TRUE(rsa_key_.Init(drm_cert.public_key()));
|
||||
EXPECT_TRUE(
|
||||
rsa_key_.VerifySignature(signed_buffer, signed_message.signature()));
|
||||
|
||||
DeriveKeysFromSessionKey();
|
||||
|
||||
video_widevine::LicenseIdentification* license_id = license()->mutable_id();
|
||||
license_id->set_request_id("TestCase");
|
||||
license_id->set_session_id(session_id_);
|
||||
license_id->set_type(video_widevine::STREAMING);
|
||||
license_id->set_version(0);
|
||||
|
||||
::video_widevine::License_Policy* policy = license()->mutable_policy();
|
||||
policy->set_can_play(true);
|
||||
policy->set_can_persist(false);
|
||||
policy->set_can_renew(false);
|
||||
policy->set_playback_duration_seconds(0);
|
||||
policy->set_license_duration_seconds(0);
|
||||
|
||||
AddMacKey();
|
||||
}
|
||||
|
||||
void TestLicenseHolder::AddMacKey() {
|
||||
video_widevine::License_KeyContainer* key_container = license()->add_key();
|
||||
std::vector<uint8_t> iv(KEY_IV_SIZE, 'v');
|
||||
std::string iv_s(iv.begin(), iv.end());
|
||||
key_container->set_iv(iv_s);
|
||||
key_container->set_type(video_widevine::License_KeyContainer_KeyType_SIGNING);
|
||||
|
||||
// Combine server and client mac keys.
|
||||
std::vector<uint8_t> keys(mac_key_server_);
|
||||
keys.insert(keys.end(), mac_key_client_.begin(), mac_key_client_.end());
|
||||
std::string encrypted_keys =
|
||||
WvCdmTestBase::Aes128CbcEncrypt(enc_key_, keys, iv);
|
||||
key_container->set_key(encrypted_keys);
|
||||
}
|
||||
|
||||
video_widevine::License_KeyContainer* TestLicenseHolder::AddKey(
|
||||
const KeyId& key_id, const std::vector<uint8_t>& key_data,
|
||||
const wvoec::KeyControlBlock& block_in) {
|
||||
video_widevine::License_KeyContainer* key_container = license()->add_key();
|
||||
wvoec::KeyControlBlock block = block_in;
|
||||
if (block.verification[0] == 0) {
|
||||
block.verification[0] = 'k';
|
||||
block.verification[1] = 'c';
|
||||
block.verification[2] = '1';
|
||||
// This will work until oemcrypto api 20.
|
||||
block.verification[3] = '0' + wvoec::global_features.api_version - 10;
|
||||
}
|
||||
key_container->set_id(key_id);
|
||||
key_container->set_type(video_widevine::License_KeyContainer_KeyType_CONTENT);
|
||||
key_container->set_level(
|
||||
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO);
|
||||
|
||||
std::vector<uint8_t> iv(KEY_IV_SIZE, 'v');
|
||||
std::string iv_s(iv.begin(), iv.end());
|
||||
key_container->set_iv(iv_s);
|
||||
|
||||
std::string encrypted_key_data =
|
||||
WvCdmTestBase::Aes128CbcEncrypt(enc_key_, key_data, iv);
|
||||
// TODO(b/111069024): remove this!
|
||||
std::string padding(CONTENT_KEY_SIZE, '-');
|
||||
key_container->set_key(encrypted_key_data + padding);
|
||||
|
||||
// TODO(b/192700112): This mock license server should parse the core message
|
||||
// request, and only encrypt the key control block if the API is greater than
|
||||
// or equal to 16.5. For now, we can pass tests on the v17 branch by checking
|
||||
// against v17.0.
|
||||
if (oemcrypto_api_ >= 17) {
|
||||
std::string block_s(reinterpret_cast<const char*>(&block),
|
||||
reinterpret_cast<const char*>(&block) + sizeof(block));
|
||||
key_container->mutable_key_control()->set_key_control_block(block_s);
|
||||
} else {
|
||||
std::vector<uint8_t> block_v(
|
||||
reinterpret_cast<const uint8_t*>(&block),
|
||||
reinterpret_cast<const uint8_t*>(&block) + sizeof(block));
|
||||
std::vector<uint8_t> block_iv(KEY_IV_SIZE, 'w');
|
||||
std::string block_iv_s(block_iv.begin(), block_iv.end());
|
||||
std::string encrypted_block =
|
||||
WvCdmTestBase::Aes128CbcEncrypt(key_data, block_v, block_iv);
|
||||
key_container->mutable_key_control()->set_iv(block_iv_s);
|
||||
key_container->mutable_key_control()->set_key_control_block(
|
||||
encrypted_block);
|
||||
}
|
||||
return key_container;
|
||||
}
|
||||
|
||||
void TestLicenseHolder::SignAndLoadLicense() {
|
||||
#if 0 // Need to turn off protobuf_lite to use this.
|
||||
LOGV("License = %s\n", license_.DebugString().c_str());
|
||||
#endif
|
||||
std::string license_data;
|
||||
license_.SerializeToString(&license_data);
|
||||
|
||||
std::string signature =
|
||||
WvCdmTestBase::SignHMAC(license_data, derived_mac_key_server_);
|
||||
|
||||
std::string session_key_s(session_key_.begin(), session_key_.end());
|
||||
std::string encrypted_session_key;
|
||||
EXPECT_TRUE(rsa_key_.Encrypt(session_key_s, &encrypted_session_key));
|
||||
video_widevine::SignedMessage signed_response;
|
||||
signed_response.set_msg(license_data);
|
||||
signed_response.set_type(video_widevine::SignedMessage_MessageType_LICENSE);
|
||||
signed_response.set_session_key(encrypted_session_key);
|
||||
signed_response.set_signature(signature);
|
||||
|
||||
std::string response_data;
|
||||
signed_response.SerializeToString(&response_data);
|
||||
|
||||
CdmKeySetId key_set_id;
|
||||
CdmLicenseType license_type; // Required for AddKey. Result value ignored.
|
||||
EXPECT_EQ(KEY_ADDED, cdm_engine_->AddKey(session_id_, response_data,
|
||||
&license_type, &key_set_id));
|
||||
}
|
||||
|
||||
void TestLicenseHolder::DeriveKeysFromSessionKey() {
|
||||
std::string context;
|
||||
GenerateMacContext(license_request_data_, &context);
|
||||
std::vector<uint8_t> mac_key_context(context.begin(), context.end());
|
||||
GenerateEncryptContext(license_request_data_, &context);
|
||||
std::vector<uint8_t> enc_key_context(context.begin(), context.end());
|
||||
|
||||
ASSERT_TRUE(
|
||||
DeriveKey(session_key_, mac_key_context, 1, &derived_mac_key_server_));
|
||||
std::vector<uint8_t> mac_key_part2;
|
||||
ASSERT_TRUE(DeriveKey(session_key_, mac_key_context, 2, &mac_key_part2));
|
||||
derived_mac_key_server_.insert(derived_mac_key_server_.end(),
|
||||
mac_key_part2.begin(), mac_key_part2.end());
|
||||
|
||||
ASSERT_TRUE(
|
||||
DeriveKey(session_key_, mac_key_context, 3, &derived_mac_key_client_));
|
||||
ASSERT_TRUE(DeriveKey(session_key_, mac_key_context, 4, &mac_key_part2));
|
||||
derived_mac_key_client_.insert(derived_mac_key_client_.end(),
|
||||
mac_key_part2.begin(), mac_key_part2.end());
|
||||
|
||||
std::vector<uint8_t> enc_key;
|
||||
ASSERT_TRUE(DeriveKey(session_key_, enc_key_context, 1, &enc_key_));
|
||||
}
|
||||
|
||||
bool TestLicenseHolder::DeriveKey(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& context,
|
||||
int counter, std::vector<uint8_t>* out) {
|
||||
if (key.empty() || counter > 4 || context.empty() || out == nullptr) {
|
||||
LOGE("DeriveKey(): bad context");
|
||||
return false;
|
||||
}
|
||||
const EVP_CIPHER* cipher = EVP_aes_128_cbc();
|
||||
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
|
||||
|
||||
if (!cmac_ctx) {
|
||||
LOGE("DeriveKey(): cmac failure");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMAC_Init(cmac_ctx, &key[0], key.size(), cipher, nullptr)) {
|
||||
LOGE("DeriveKey(): CMAC_Init");
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> message;
|
||||
message.push_back(counter);
|
||||
message.insert(message.end(), context.begin(), context.end());
|
||||
|
||||
if (!CMAC_Update(cmac_ctx, &message[0], message.size())) {
|
||||
LOGE("DeriveKey(): CMAC_Update");
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t reslen;
|
||||
uint8_t res[128];
|
||||
if (!CMAC_Final(cmac_ctx, res, &reslen)) {
|
||||
LOGE("DeriveKey(): CMAC_Final");
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
return false;
|
||||
}
|
||||
out->assign(res, res + reslen);
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string MakePSSH(const video_widevine::WidevinePsshData& header) {
|
||||
std::string data;
|
||||
header.SerializeToString(&data);
|
||||
|
||||
@@ -108,69 +108,6 @@ class TestCryptoSession : public CryptoSession {
|
||||
CdmResponseType GenerateNonce(uint32_t* nonce) override;
|
||||
};
|
||||
|
||||
// A holder for a license. Users of this class will first open a session with
|
||||
// OpenSession, then generate a key request with GenerateKeyRequest, and then
|
||||
// call CreateDefaultLicense to create a bare-bones license with no keys in it.
|
||||
// The user may then access the license to adjust the policy, or use AddKey to
|
||||
// add keys to the license. The license is then loaded via SignAndLoadLicense.
|
||||
class TestLicenseHolder {
|
||||
public:
|
||||
// cdm_engine must exist and outlive the TestLicenseHolder.
|
||||
TestLicenseHolder(CdmEngine* cdm_engine);
|
||||
~TestLicenseHolder();
|
||||
// Caller must ensure device already provisioned.
|
||||
void OpenSession(const std::string& key_system);
|
||||
void CloseSession();
|
||||
// Use the cdm_engine to generate a key request in the session. This should
|
||||
// be called after OpenSession. This saves the signed license request, so
|
||||
// that the DRM certificate can be extracted in CreateDefaultLicense.
|
||||
void GenerateKeyRequest(const std::string& key_id,
|
||||
const std::string& init_data_type_string);
|
||||
// Create a bare-bones license from the license request. After this, the user
|
||||
// may access and modify the license using license() below.
|
||||
void CreateDefaultLicense();
|
||||
// Sign the license using the DRM certificate's RSA key. Then the license is
|
||||
// passed to the cdm_engine using AddKey. After this, the license is loaded
|
||||
// and the keys may be used.
|
||||
void SignAndLoadLicense();
|
||||
|
||||
// The session id. This is only valid after a call to OpenSession.
|
||||
const std::string& session_id() { return session_id_; }
|
||||
// The license protobuf. This is only valid after CreateDefaultLicense.
|
||||
video_widevine::License* license() { return &license_; };
|
||||
// Add a key with the given key control block and key data.
|
||||
// If the block's verification is empty, it will be set to a valid value.
|
||||
// The key data is encrypted correctly.
|
||||
video_widevine::License_KeyContainer* AddKey(
|
||||
const KeyId& key_id, const std::vector<uint8_t>& key_data,
|
||||
const wvoec::KeyControlBlock& block);
|
||||
|
||||
private:
|
||||
// Helper method to generate mac keys and encryption keys for the license.
|
||||
void DeriveKeysFromSessionKey();
|
||||
// Derive a single mac key or encryption key using CMAC.
|
||||
bool DeriveKey(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& context, int counter,
|
||||
std::vector<uint8_t>* out);
|
||||
// Add the mac keys to the license.
|
||||
void AddMacKey();
|
||||
|
||||
CdmEngine* cdm_engine_;
|
||||
uint32_t oemcrypto_api_;
|
||||
std::string signed_license_request_data_;
|
||||
std::string license_request_data_;
|
||||
std::string session_id_;
|
||||
bool session_opened_;
|
||||
RsaPublicKey rsa_key_; // From the DRM Certificate.
|
||||
video_widevine::License license_;
|
||||
std::vector<uint8_t> derived_mac_key_server_;
|
||||
std::vector<uint8_t> derived_mac_key_client_;
|
||||
std::vector<uint8_t> mac_key_server_;
|
||||
std::vector<uint8_t> mac_key_client_;
|
||||
std::vector<uint8_t> enc_key_;
|
||||
std::vector<uint8_t> session_key_;
|
||||
};
|
||||
|
||||
// Given a PSSH data structure, this makes a PSSH string for use in
|
||||
// generating a license request.
|
||||
std::string MakePSSH(const video_widevine::WidevinePsshData& header);
|
||||
|
||||
Reference in New Issue
Block a user