Source release v2.1.6-0-824 + third_party libs

Change-Id: If190f81154326aa7dc22d66009687f389146ddfd
This commit is contained in:
Joey Parrish
2014-07-14 13:25:39 -07:00
parent fa64436e4f
commit 97b453dd71
11 changed files with 522 additions and 173 deletions

View File

@@ -1,14 +1,29 @@
README.upgrading for Widevine CDM Partner Kit v2.1
Date: 7/07/2014
Date: 7/10/2014
This document provides details on important changes between versions of the
Widevine CDM. Some upgrades may require you to make changes to your
application, so please read carefully.
Widevine CDM. Some upgrades require you to make changes to your application,
so please read carefully.
NOTE: All gyp variables have default values in platforms/global_config.gypi.
You may override these defaults in your platform-specific gypi.
New in v2.1.6:
=====
The following methods have been removed from the CDM interface (class
ContentDecryptionModule):
* CancelKeyRequest
The following methods have been added to the CDM interface (class
ContentDecryptionModule):
* CloseSession
Previous versions of the CDM did not dispatch key errors (Host::SendKeyError)
on failure. This has been fixed. If you added workarounds to your Host,
please remove them to avoid duplicate key errors.
New in v2.1.5:
=====
New gyp variables have been introduced to make the build more configurable:
@@ -27,7 +42,7 @@ New gyp variables have been introduced to make the build more configurable:
The CDM interface (class ContentDecryptionModule) has been simplified.
The following methods have been removed:
* InitializeAudioDecoder()
* InitializeAudioDecoder
* InitializeVideoDecoder
* DeinitializeDecoder
* ResetDecoder

View File

@@ -272,13 +272,13 @@ class ContentDecryptionModule_1 {
// Tests whether |key_id| is known to any current session.
virtual bool IsKeyValid(const uint8_t* key_id, int key_id_size) = 0;
// Cancels any pending key request made to the CDM for |session_id|.
// Closes the session identified by |session_id| and releases all crypto
// resources related to that session. After calling this, it is invalid to
// refer to this session any more, because the session has been destroyed.
//
// Returns kSuccess if all pending key requests for |session_id| were
// successfully canceled or there was no key request to be canceled,
// kSessionError otherwise.
virtual Status CancelKeyRequest(
const char* session_id, int session_id_size) = 0;
// Returns kSuccess if the session |session_id| was successfully closed and
// all resources released, kSessionError otherwise.
virtual Status CloseSession(const char* session_id, int session_id_size) = 0;
// Performs scheduled operation with |context| when the timer fires.
virtual void TimerExpired(void* context) = 0;

View File

@@ -1,3 +1,3 @@
// Widevine CDM Kit Version
#define WV_CDM_VERSION "v2.1.5-0-811"
#define WV_CDM_VERSION "v2.1.6-0-824"

View File

@@ -95,8 +95,8 @@ class WvContentDecryptionModule : public cdm::ContentDecryptionModule,
virtual bool IsKeyValid(const uint8_t* key_id, int key_id_size) OVERRIDE;
virtual cdm::Status CancelKeyRequest(const char* session_id,
int session_id_size) OVERRIDE;
virtual cdm::Status CloseSession(const char* session_id,
int session_id_size) OVERRIDE;
virtual void TimerExpired(void* context) OVERRIDE;

View File

@@ -14,6 +14,18 @@
#include "wv_cdm_types.h"
#include "wv_cdm_version.h"
namespace {
enum {
// individual error codes
kAttachEventListenerError = 0x0001,
// error classes to be OR'd with cdm engine result values
kOpenSessionErrorBase = 0x0100,
kGenerateKeyRequestErrorBase = 0x0200,
kAddKeyErrorBase = 0x0300,
};
} // namespace
void INITIALIZE_CDM_MODULE() {}
void DeinitializeCdmModule() {}
@@ -115,15 +127,20 @@ cdm::Status WvContentDecryptionModule::GenerateKeyRequest(
CdmResponseType result =
cdm_engine_.OpenSession("com.widevine.alpha", &property_set_, &session_id);
if (NEED_PROVISIONING == result) {
if (result == NEED_PROVISIONING) {
LOGI("Need to aquire a Device Certificate from the Provisioning Server");
return cdm::kNeedsDeviceCertificate;
}
if (NO_ERROR != result) return cdm::kSessionError;
if (result != NO_ERROR) {
host_->SendKeyError("", 0, cdm::kClientError,
kOpenSessionErrorBase | result);
return cdm::kSessionError;
}
if (!cdm_engine_.AttachEventListener(session_id, &host_event_listener_)) {
cdm_engine_.CloseSession(session_id);
host_->SendKeyError("", 0, cdm::kClientError, kAttachEventListenerError);
return cdm::kSessionError;
}
@@ -136,13 +153,14 @@ cdm::Status WvContentDecryptionModule::GenerateKeyRequest(
app_parameters, &key_request, &server_url);
if (KEY_MESSAGE != result) {
cdm_engine_.CloseSession(session_id);
host_->SendKeyError("", 0, cdm::kClientError,
kGenerateKeyRequestErrorBase | result);
return cdm::kSessionError;
}
host_->SendKeyMessage(session_id.data(), session_id.length(),
key_request.data(), key_request.length(),
server_url.data(), server_url.length());
return cdm::kSuccess;
}
@@ -162,9 +180,11 @@ cdm::Status WvContentDecryptionModule::AddKey(const char* session_id,
if (response == KEY_ADDED) {
EnablePolicyTimer();
return cdm::kSuccess;
} else {
return cdm::kSessionError;
}
host_->SendKeyError(session_id, session_id_size, cdm::kClientError,
kAddKeyErrorBase | response);
return cdm::kSessionError;
}
bool WvContentDecryptionModule::IsKeyValid(const uint8_t* key_id,
@@ -173,11 +193,11 @@ bool WvContentDecryptionModule::IsKeyValid(const uint8_t* key_id,
return cdm_engine_.IsKeyLoaded(key);
}
cdm::Status WvContentDecryptionModule::CancelKeyRequest(const char* session_id,
int session_id_size) {
LOGI("WvContentDecryptionModule::CancelKeyRequest()");
cdm::Status WvContentDecryptionModule::CloseSession(const char* session_id,
int session_id_size) {
LOGI("WvContentDecryptionModule::CloseSession()");
CdmSessionId session_id_internal(session_id, session_id_size);
return cdm_engine_.CancelKeyRequest(session_id_internal) == NO_ERROR
return cdm_engine_.CloseSession(session_id_internal) == NO_ERROR
? cdm::kSuccess
: cdm::kSessionError;
}
@@ -196,6 +216,7 @@ cdm::Status WvContentDecryptionModule::Decrypt(
LOGI("WvContentDecryptionModule::Decrypt()");
if (static_cast<size_t>(encrypted_buffer.iv_size) != KEY_IV_SIZE)
return cdm::kDecryptError;
std::vector < uint8_t > iv(KEY_IV_SIZE);
memcpy(&iv[0], encrypted_buffer.iv, encrypted_buffer.iv_size);
@@ -204,9 +225,9 @@ cdm::Status WvContentDecryptionModule::Decrypt(
CdmSessionId session_id; // it's empty but cdm_engine will locate via key_id?
if (NULL == encrypted_buffer.subsamples
|| encrypted_buffer.num_subsamples <= 0)
return cdm::kDecryptError;
if (!encrypted_buffer.subsamples ||
encrypted_buffer.num_subsamples <= 0)
return cdm::kDecryptError;
CdmDecryptionParameters parameters(&key_id,
encrypted_buffer.data, 0, &iv, 0,
@@ -236,8 +257,8 @@ cdm::Status WvContentDecryptionModule::DecryptDecodeAndRenderFrame(
encrypted_buffer.key_id_size);
CdmSessionId session_id; // it's empty but cdm_engine will locate via key_id.
if (NULL == encrypted_buffer.subsamples
|| encrypted_buffer.num_subsamples <= 0)
if (!encrypted_buffer.subsamples ||
encrypted_buffer.num_subsamples <= 0)
return cdm::kDecryptError;
CdmDecryptionParameters parameters(&key_id, encrypted_buffer.data, 0, &iv, 0,
@@ -262,7 +283,7 @@ cdm::Status WvContentDecryptionModule::DecryptDecodeAndRenderSamples(
encrypted_buffer.key_id_size);
CdmSessionId session_id; // it's empty but cdm_engine will locate via key_id.
if (NULL == encrypted_buffer.subsamples ||
if (!encrypted_buffer.subsamples ||
encrypted_buffer.num_subsamples <= 0)
return cdm::kDecryptError;

View File

@@ -19,6 +19,7 @@
#include "clock.h"
#include "config_test_env.h"
#include "content_decryption_module.h"
#include "device_cert.h"
#include "license_request.h"
#include "log.h"
#include "scoped_ptr.h"
@@ -30,6 +31,7 @@ using wvcdm::scoped_ptr;
static const int kTestPolicyRenewalDelaySeconds = 60;
static const int kDelayWaitToForRenewalMessageSeconds = 2;
static const int kHttpOk = 200;
static double GetCurrentTime() {
struct timeval tv;
@@ -348,7 +350,6 @@ namespace {
const char kKeySystemWidevine[] = "com.widevine.alpha";
std::string g_client_auth;
wvcdm::KeyId g_key_id;
wvcdm::CdmKeySystem g_key_system;
std::string g_license_server;
wvcdm::KeyId g_wrong_key_id;
@@ -375,14 +376,8 @@ class WvCdmApiTest : public testing::Test {
// Set various parameters that the CDM will query.
host_->SetPlatformString("SecurityLevel", "L1");
host_->SetPlatformString("PrivacyOn", "False");
// Put a phony service certificate into persistent storage.
static const size_t kPrivacyCertSize = 256;
std::string cert(kPrivacyCertSize, '\0');
for (size_t i = 0; i < cert.size(); i++) {
cert[i] = i;
}
host_->SetPlatformString("ServiceCertificate", cert);
std::string cert(kDeviceCert, sizeof(kDeviceCert));
host_->SetPlatformString("DeviceCertificate", cert);
// Initialize the CDM module before creating a CDM instance.
INITIALIZE_CDM_MODULE();
@@ -396,62 +391,37 @@ class WvCdmApiTest : public testing::Test {
host_->SetCdmPtr(cdm_);
}
void GenerateKeyRequest(const std::string& key_system,
const std::string& key_id) {
std::string init_data = key_id;
cdm::Status GenerateKeyRequest(const std::string& init_data) {
cdm::Status status = cdm_->GenerateKeyRequest(
NULL, 0, (const uint8_t*)init_data.data(), init_data.length());
// cdm::Host must handle the certificate provisioning request.
if (status == cdm::kNeedsDeviceCertificate) {
std::string provisioning_server_url;
std::string prov_request;
status = cdm_->GetProvisioningRequest(&prov_request,
&provisioning_server_url);
if (status == cdm::kSuccess) {
UrlRequest url_request(provisioning_server_url);
url_request.PostCertRequestInQueryString(prov_request);
std::string message;
bool ok = url_request.GetResponse(&message);
EXPECT_TRUE(ok);
if (ok) {
status = cdm_->HandleProvisioningResponse(message);
if (status == cdm::kSuccess) {
status = cdm_->GenerateKeyRequest(NULL, 0,
(const uint8_t*)init_data.data(), init_data.length());
}
}
}
}
EXPECT_EQ(cdm::kSuccess, status);
return status;
}
// posts a request and extracts the drm message from the response
std::string GetKeyRequestResponse(const std::string& server_url,
const std::string& client_auth,
int expected_response) {
UrlRequest url_request(server_url + client_auth);
std::string GetKeyRequestResponse(const TestHost::KeyMessage& key_msg) {
std::string url;
if (key_msg.default_url.empty()) {
url = g_license_server + g_client_auth;
} else {
// Note that the client auth string is not appended when the CDM tells
// us what URL to use.
url = key_msg.default_url;
}
UrlRequest url_request(url);
EXPECT_TRUE(url_request.is_connected());
if (!url_request.is_connected()) {
return "";
}
url_request.PostRequest(key_msg_);
url_request.PostRequest(key_msg.message);
std::string response;
int resp_bytes = url_request.GetResponse(&response);
// Some license servers return 400 for invalid message, some
// return 500; treat anything other than 200 as an invalid message.
int status_code = url_request.GetStatusCode(response);
int kHttpOk = 200;
if (expected_response == kHttpOk) {
EXPECT_EQ(kHttpOk, status_code);
} else {
EXPECT_NE(kHttpOk, status_code);
}
EXPECT_EQ(kHttpOk, status_code);
if (status_code != kHttpOk) {
return "";
@@ -466,17 +436,32 @@ class WvCdmApiTest : public testing::Test {
}
}
void CancelKeyRequest(std::string session_id) {
void ProcessKeyResponse() {
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
EXPECT_TRUE(key_msg.default_url.empty());
std::string drm_msg = GetKeyRequestResponse(key_msg);
EXPECT_EQ(cdm::kSuccess, AddKey(key_msg.session_id, drm_msg));
}
void ProcessKeyRenewalResponse() {
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
EXPECT_FALSE(key_msg.default_url.empty());
std::string drm_msg = GetKeyRequestResponse(key_msg);
EXPECT_EQ(cdm::kSuccess, AddKey(key_msg.session_id, drm_msg));
}
void CloseSession(const std::string& session_id) {
cdm::Status status =
cdm_->CancelKeyRequest(session_id.data(), session_id.length());
cdm_->CloseSession(session_id.data(), session_id.length());
EXPECT_EQ(cdm::kSuccess, status);
}
void AddKey(std::string& session_id, std::string& drm_msg) {
cdm::Status AddKey(const std::string& session_id,
const std::string& drm_msg) {
cdm::Status status =
cdm_->AddKey(session_id.data(), session_id.size(),
(const uint8_t*)drm_msg.data(), drm_msg.size(), NULL, 0);
EXPECT_EQ(cdm::kSuccess, status);
return status;
}
// Level 1 / Level 2 payload comes back in the cpu memory as cleartext.
@@ -960,10 +945,6 @@ class WvCdmApiTest : public testing::Test {
EXPECT_EQ(cdm::kDecryptError, status);
}
std::string key_msg_;
std::string session_id_;
std::string server_url_;
cdm::ContentDecryptionModule* cdm_; // owned by host_
scoped_ptr<TestHost> host_;
};
@@ -989,7 +970,7 @@ class DummyCDM : public cdm::ContentDecryptionModule {
return false;
}
virtual cdm::Status CancelKeyRequest(const char*, int) OVERRIDE {
virtual cdm::Status CloseSession(const char*, int) OVERRIDE {
return cdm::kSessionError;
}
@@ -1082,116 +1063,115 @@ TEST_F(WvCdmApiTest, TestHostTimer) {
// and works in your test environment.
TEST_F(WvCdmApiTest, DeviceCertificateTest) {
GenerateKeyRequest(g_key_system, g_key_id); // It will have to provision -
// in here.
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
session_id_ = key_msg.session_id;
key_msg_ = key_msg.message;
std::string drm_msg = GetKeyRequestResponse(g_license_server,
g_client_auth, 200);
AddKey(key_msg.session_id, drm_msg);
CancelKeyRequest(session_id_);
// Clear any existing device cert.
host_->SetPlatformString("DeviceCertificate", "");
ASSERT_EQ(cdm::kNeedsDeviceCertificate, GenerateKeyRequest(g_key_id));
// The Host must handle the certificate provisioning request.
std::string server_url;
std::string request;
cdm::Status status = cdm_->GetProvisioningRequest(&request, &server_url);
ASSERT_EQ(cdm::kSuccess, status);
UrlRequest url_request(server_url);
url_request.PostCertRequestInQueryString(request);
std::string message;
bool ok = url_request.GetResponse(&message);
ASSERT_TRUE(ok);
status = cdm_->HandleProvisioningResponse(message);
ASSERT_EQ(cdm::kSuccess, status);
// Now we are provisioned, so GKR should succeed.
EXPECT_EQ(cdm::kSuccess, GenerateKeyRequest(g_key_id));
}
TEST_F(WvCdmApiTest, BaseMessageTest) {
GenerateKeyRequest(g_key_system, g_key_id);
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
session_id_ = key_msg.session_id;
key_msg_ = key_msg.message;
std::string drm_msg = GetKeyRequestResponse(g_license_server,
g_client_auth, 200);
AddKey(key_msg.session_id, drm_msg);
CancelKeyRequest(session_id_);
EXPECT_EQ(cdm::kSuccess, GenerateKeyRequest(g_key_id));
ProcessKeyResponse();
}
TEST_F(WvCdmApiTest, NormalDecryption) {
GenerateKeyRequest(g_key_system, g_key_id);
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
key_msg_ = key_msg.message;
std::string drm_msg = GetKeyRequestResponse(g_license_server,
g_client_auth, 200);
AddKey(key_msg.session_id, drm_msg);
EXPECT_EQ(cdm::kSuccess, GenerateKeyRequest(g_key_id));
ProcessKeyResponse();
DecryptClearPayloadTest();
}
TEST_F(WvCdmApiTest, NormalSubSampleDecryptionWithSubsampleInfo) {
GenerateKeyRequest(g_key_system, g_key_id);
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
key_msg_ = key_msg.message;
std::string drm_msg = GetKeyRequestResponse(g_license_server,
g_client_auth, 200);
AddKey(key_msg.session_id, drm_msg);
EXPECT_EQ(cdm::kSuccess, GenerateKeyRequest(g_key_id));
ProcessKeyResponse();
DecryptClearSubsampleTest();
}
TEST_F(WvCdmApiTest, NormalSubSampleDecryptionWithMissingSubsampleInfo) {
GenerateKeyRequest(g_key_system, g_key_id);
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
key_msg_ = key_msg.message;
std::string drm_msg = GetKeyRequestResponse(g_license_server,
g_client_auth, 200);
AddKey(key_msg.session_id, drm_msg);
EXPECT_EQ(cdm::kSuccess, GenerateKeyRequest(g_key_id));
ProcessKeyResponse();
DecryptClearSubsampleTestWithMissingSubsampleInfo();
}
TEST_F(WvCdmApiTest, TimeTest) {
GenerateKeyRequest(g_key_system, g_key_id);
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
session_id_ = key_msg.session_id;
key_msg_ = key_msg.message;
std::string drm_msg = GetKeyRequestResponse(g_license_server,
g_client_auth, 200);
AddKey(key_msg.session_id, drm_msg);
EXPECT_EQ(cdm::kSuccess, GenerateKeyRequest(g_key_id));
ProcessKeyResponse();
// We expect that by the time we've added a key, the CDM has set a timer.
// Otherwise, it couldn't correctly handle renewal.
EXPECT_NE(0, host_->NumTimers());
host_->FastForwardTime(kTestPolicyRenewalDelaySeconds +
kDelayWaitToForRenewalMessageSeconds);
// When the timer expired, we should have sent a renewal, so we can
// add this renewed key now, assuming things are working as expected.
TestHost::KeyMessage key_msg2 = host_->GetLastKeyMessage();
session_id_ = key_msg2.session_id;
key_msg_ = key_msg2.message;
// Note that the client auth string is not appended when the CDM tells
// us what URL to use.
EXPECT_FALSE(key_msg2.default_url.empty());
drm_msg = GetKeyRequestResponse(key_msg2.default_url, "", 200);
AddKey(key_msg2.session_id, drm_msg);
ProcessKeyRenewalResponse();
}
TEST_F(WvCdmApiTest, SecureDecryptionLevel1) {
GenerateKeyRequest(g_key_system, g_key_id);
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
key_msg_ = key_msg.message;
std::string drm_msg = GetKeyRequestResponse(g_license_server,
g_client_auth, 200);
AddKey(key_msg.session_id, drm_msg);
EXPECT_EQ(cdm::kSuccess, GenerateKeyRequest(g_key_id));
ProcessKeyResponse();
SecureDecryptLevel1Test();
}
TEST_F(WvCdmApiTest, SecureDecryptionLevel1WithSubsampleInfo) {
GenerateKeyRequest(g_key_system, g_key_id);
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
key_msg_ = key_msg.message;
std::string drm_msg = GetKeyRequestResponse(g_license_server,
g_client_auth, 200);
AddKey(key_msg.session_id, drm_msg);
EXPECT_EQ(cdm::kSuccess, GenerateKeyRequest(g_key_id));
ProcessKeyResponse();
SecureDecryptLevel1MultipleSubsamplesTest();
}
TEST_F(WvCdmApiTest, SecureDecryptionLevel1WithMissingSubsampleInfo) {
GenerateKeyRequest(g_key_system, g_key_id);
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
key_msg_ = key_msg.message;
std::string drm_msg = GetKeyRequestResponse(g_license_server,
g_client_auth, 200);
AddKey(key_msg.session_id, drm_msg);
EXPECT_EQ(cdm::kSuccess, GenerateKeyRequest(g_key_id));
ProcessKeyResponse();
WithMissingSubsampleInfoTest();
}
TEST_F(WvCdmApiTest, GenerateKeyRequestFailureSendsKeyError) {
// Pass a bogus key id and expect failure.
EXPECT_EQ(cdm::kSessionError, GenerateKeyRequest(""));
// Expect the CDM to pass a key error back to the host.
EXPECT_EQ(1, host_->KeyErrorsSize());
}
TEST_F(WvCdmApiTest, AddKeyFailureSendsKeyError) {
EXPECT_EQ(cdm::kSuccess, GenerateKeyRequest(g_key_id));
// Get the message and response.
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
EXPECT_TRUE(key_msg.default_url.empty());
std::string drm_msg = GetKeyRequestResponse(key_msg);
// Call AddKey with a bad session id and expect failure.
EXPECT_EQ(cdm::kSessionError, AddKey("BLAH", drm_msg));
// Expect the CDM to pass a key error back to the host.
EXPECT_EQ(1, host_->KeyErrorsSize());
// Call AddKey with a bad license and expect failure.
EXPECT_EQ(cdm::kSessionError, AddKey(key_msg.session_id, "BLAH"));
// Expect the CDM to pass one more key error back to the host.
EXPECT_EQ(2, host_->KeyErrorsSize());
}
} // namespace wvcdm
int main(int argc, char** argv) {
@@ -1200,7 +1180,6 @@ int main(int argc, char** argv) {
wvcdm::ConfigTestEnv config(wvcdm::kGooglePlayServer);
g_client_auth.assign(config.client_auth());
g_key_system.assign(config.key_system());
g_wrong_key_id.assign(config.wrong_key_id());
// The following variables are configurable through command line options.

332
cdm/test/device_cert.h Normal file
View File

@@ -0,0 +1,332 @@
// Copyright 2014 Google Inc. All Rights Reserved.
const char kDeviceCert[] = {
0x0A, 0x9A, 0x14, 0x08, 0x01, 0x10, 0x01, 0x1A,
0x93, 0x14, 0x0A, 0xED, 0x09, 0x0A, 0xAE, 0x02,
0x08, 0x02, 0x12, 0x10, 0x19, 0x77, 0x50, 0x4D,
0x66, 0x1C, 0x28, 0xBE, 0x41, 0xD3, 0xAA, 0x33,
0x98, 0x3D, 0xB5, 0x46, 0x18, 0x8D, 0xA3, 0x81,
0x9E, 0x05, 0x22, 0x8E, 0x02, 0x30, 0x82, 0x01,
0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB2, 0xA8,
0x6A, 0x68, 0x01, 0x84, 0xC2, 0x62, 0x08, 0x8D,
0xFB, 0x5E, 0xA7, 0x5B, 0xC2, 0x70, 0x6E, 0xF0,
0xE1, 0xF7, 0xCE, 0x0D, 0x06, 0x29, 0x8A, 0x8C,
0x11, 0x6C, 0xB8, 0xBD, 0xEC, 0xA5, 0x9F, 0x60,
0x65, 0x9F, 0x89, 0x52, 0xC0, 0x72, 0xF8, 0x2A,
0x30, 0xBD, 0xB8, 0x52, 0xFF, 0x2F, 0x6C, 0xAE,
0x36, 0x1E, 0xED, 0xC2, 0x0E, 0x00, 0x64, 0x57,
0x0F, 0xFD, 0xA9, 0xEE, 0xCE, 0x62, 0xB0, 0x23,
0xB8, 0x68, 0x2B, 0xED, 0xDE, 0x3B, 0xCA, 0xCD,
0x07, 0x55, 0xDB, 0xF7, 0x77, 0xCE, 0x6B, 0x16,
0xE0, 0x17, 0x6C, 0xE6, 0xBE, 0x76, 0xBE, 0x31,
0xC8, 0x62, 0x98, 0xF3, 0x62, 0x3B, 0x24, 0x73,
0x43, 0x19, 0x0A, 0x0A, 0xE9, 0xA4, 0x76, 0xA8,
0x27, 0x12, 0xBD, 0xF5, 0x8A, 0x28, 0x99, 0x54,
0x8A, 0x55, 0x56, 0x6B, 0x92, 0x57, 0xA2, 0x6C,
0x7E, 0xD9, 0xEE, 0xF7, 0xCE, 0xEC, 0xB6, 0xA4,
0xC2, 0xC2, 0x4F, 0x60, 0xF9, 0x6C, 0x96, 0x1E,
0x5A, 0x1C, 0xC6, 0x14, 0x2D, 0x6D, 0xA8, 0x83,
0x8C, 0x80, 0x07, 0x5F, 0x20, 0xFC, 0xAF, 0x08,
0x98, 0xAE, 0x94, 0x10, 0x13, 0x49, 0xD3, 0xDF,
0x94, 0x8A, 0x51, 0xE2, 0x1D, 0xD6, 0x9E, 0xA6,
0xE1, 0x56, 0x23, 0x0D, 0x69, 0x4D, 0x1A, 0x14,
0xEF, 0x5D, 0x33, 0xF8, 0x5D, 0x7A, 0xEF, 0xD8,
0x02, 0x9E, 0xF2, 0xFB, 0xB3, 0x75, 0x04, 0xAF,
0x9C, 0x19, 0x73, 0xEC, 0xA3, 0x01, 0x8F, 0xD7,
0x03, 0xB7, 0x58, 0xD4, 0x2A, 0xD4, 0xA6, 0x21,
0xC8, 0x39, 0x58, 0xCA, 0x2F, 0x40, 0x19, 0x12,
0x35, 0x58, 0x4D, 0xA8, 0x60, 0x06, 0xEE, 0x90,
0x17, 0xE3, 0xB8, 0xA2, 0xE2, 0xDC, 0xEB, 0x74,
0x50, 0x0E, 0xCD, 0x34, 0x44, 0x04, 0x09, 0xC1,
0xC6, 0xE5, 0x55, 0xAF, 0xFD, 0x14, 0xB6, 0x27,
0x4F, 0xA7, 0x2C, 0xB4, 0xE1, 0x3D, 0x02, 0x03,
0x01, 0x00, 0x01, 0x28, 0x99, 0x20, 0x12, 0x80,
0x02, 0x6B, 0x7E, 0x26, 0xBC, 0x2C, 0x1F, 0x19,
0x55, 0x2B, 0xBF, 0x88, 0x3F, 0x48, 0xDE, 0xE2,
0x8E, 0x82, 0xCC, 0x77, 0x72, 0x31, 0x34, 0x2B,
0x4E, 0x2C, 0xDF, 0xFB, 0xF6, 0xA1, 0x6F, 0x94,
0xCA, 0x01, 0x45, 0xAE, 0x42, 0x0A, 0xFF, 0x51,
0xE9, 0xB8, 0x6C, 0xDF, 0xB1, 0x1E, 0x35, 0x81,
0x1D, 0xF9, 0xB7, 0x51, 0x75, 0xE4, 0xF4, 0xD6,
0xEA, 0x7D, 0xBC, 0x96, 0x2F, 0x29, 0x3D, 0xC1,
0x89, 0x1C, 0x5C, 0xF9, 0x08, 0x67, 0x7C, 0x0E,
0xBB, 0xC2, 0x9D, 0x28, 0x6F, 0x38, 0x2E, 0x57,
0x41, 0xA1, 0x96, 0x37, 0xCE, 0x7D, 0xD4, 0x24,
0xFC, 0x26, 0xB2, 0x5E, 0xDF, 0x63, 0x33, 0xBA,
0x3E, 0x3F, 0x92, 0xB6, 0x79, 0xC7, 0xE7, 0x14,
0x86, 0xC5, 0xEE, 0x96, 0xF3, 0x2F, 0xFB, 0x4B,
0xF3, 0xC4, 0xCA, 0xF3, 0x54, 0xDB, 0x56, 0x6C,
0x7F, 0x4E, 0xC7, 0x81, 0x42, 0x87, 0x5D, 0x22,
0xDF, 0x80, 0x9C, 0xE0, 0x9C, 0xE1, 0x9F, 0x0C,
0xBC, 0xB7, 0x58, 0x44, 0x84, 0xE8, 0x3F, 0x97,
0x0C, 0x79, 0x5A, 0x89, 0x09, 0x3D, 0x77, 0xB7,
0xEF, 0xCC, 0x45, 0xB9, 0xC8, 0x20, 0xBE, 0x0A,
0x2F, 0x7A, 0x30, 0x3F, 0x7D, 0x07, 0x33, 0xF9,
0x5D, 0xD0, 0x23, 0x11, 0xD8, 0x21, 0xC9, 0x42,
0xCC, 0x7A, 0x25, 0xD1, 0xEA, 0x22, 0x6B, 0x65,
0x34, 0xF2, 0x66, 0xE7, 0xB9, 0x1B, 0xF7, 0x19,
0xCA, 0xA3, 0x28, 0x8B, 0x06, 0x99, 0x88, 0xFB,
0xD4, 0xA5, 0x24, 0xDC, 0x5D, 0x1F, 0x57, 0xC6,
0xBB, 0xB4, 0x1B, 0x16, 0x31, 0x8E, 0xC2, 0x4E,
0xA1, 0x54, 0xDE, 0x19, 0x77, 0x3A, 0x1B, 0xE6,
0x3F, 0xAF, 0x91, 0x47, 0x0B, 0xED, 0x59, 0xD8,
0xCD, 0x47, 0xF0, 0x62, 0xE0, 0xFA, 0xF3, 0xB1,
0x60, 0xE5, 0xAD, 0x98, 0x12, 0x71, 0x90, 0x58,
0xA9, 0xD7, 0x55, 0x92, 0x62, 0xD3, 0xEA, 0x5B,
0xF8, 0x1A, 0xB6, 0x05, 0x0A, 0xB0, 0x02, 0x08,
0x01, 0x12, 0x10, 0x08, 0x4D, 0x60, 0xBC, 0x65,
0x93, 0x7D, 0xB6, 0xAC, 0x7F, 0x99, 0x2B, 0x41,
0xEC, 0xF5, 0xF2, 0x18, 0xA2, 0xD3, 0x8A, 0x8C,
0x05, 0x22, 0x8E, 0x02, 0x30, 0x82, 0x01, 0x0A,
0x02, 0x82, 0x01, 0x01, 0x00, 0x99, 0x1B, 0x35,
0x7B, 0xB7, 0x14, 0xDE, 0xCA, 0xC1, 0xE7, 0x0E,
0xAA, 0x36, 0xD1, 0xD0, 0x83, 0x4D, 0xF2, 0x4A,
0x3D, 0x10, 0x36, 0x9F, 0x90, 0xA2, 0x27, 0x34,
0xA3, 0xAD, 0x4A, 0xEB, 0xCC, 0xFC, 0x24, 0x32,
0xBD, 0xD6, 0xDC, 0xD1, 0xFF, 0xD7, 0x56, 0x99,
0xBA, 0x56, 0x08, 0xC4, 0x45, 0x79, 0x72, 0xD2,
0x7C, 0x47, 0xAB, 0xCF, 0xF8, 0xC8, 0x8C, 0xD9,
0x90, 0x09, 0x38, 0x26, 0x0B, 0x8C, 0x85, 0x79,
0x53, 0x27, 0xB2, 0xAE, 0xF3, 0xA1, 0xDB, 0x27,
0xE8, 0xB9, 0x62, 0x03, 0x92, 0x84, 0xD6, 0x02,
0xC6, 0xA7, 0x4C, 0x6A, 0x14, 0x3A, 0x67, 0xBE,
0x64, 0xA1, 0x6A, 0x1C, 0x8F, 0x44, 0xFA, 0xFA,
0xDA, 0xC2, 0x42, 0xCE, 0xB6, 0xD8, 0xAD, 0xE9,
0xC4, 0xD4, 0x54, 0x2E, 0xBD, 0x3E, 0xE9, 0xD2,
0xA0, 0xA7, 0x1E, 0xB7, 0xA4, 0xCC, 0xF9, 0x16,
0xE0, 0x2F, 0x26, 0x79, 0x3B, 0x0C, 0x13, 0xA4,
0x92, 0x1C, 0x3E, 0xED, 0x49, 0xC5, 0xC9, 0x6C,
0xD4, 0x55, 0x59, 0x8E, 0xDE, 0x04, 0x0C, 0xE4,
0x72, 0xB0, 0x15, 0xA9, 0xAF, 0x3C, 0xDA, 0x82,
0xC4, 0x97, 0x92, 0xAA, 0x7F, 0x6B, 0xBF, 0xBF,
0x46, 0x67, 0x29, 0x3B, 0x44, 0xEC, 0x74, 0x29,
0xC3, 0x9A, 0x03, 0x89, 0x11, 0xCE, 0x1F, 0xE4,
0x62, 0xC3, 0x5E, 0x95, 0xC2, 0x64, 0xD3, 0x63,
0x34, 0x3C, 0x3A, 0xDB, 0x94, 0x4F, 0xA2, 0xAA,
0xBD, 0xBA, 0x0F, 0xB6, 0x1C, 0x40, 0x27, 0x97,
0x58, 0x5F, 0x3D, 0xFB, 0x79, 0x6F, 0x6C, 0xE1,
0xDC, 0xF3, 0xB7, 0x9C, 0x98, 0x87, 0xBE, 0x98,
0x14, 0x70, 0xEC, 0xBC, 0xB0, 0x48, 0xE5, 0x9E,
0x56, 0x4F, 0xC3, 0xAD, 0x2C, 0x4B, 0x86, 0x0F,
0x70, 0xAA, 0x46, 0x8F, 0xB6, 0x6C, 0x4A, 0x28,
0x47, 0xEE, 0xC7, 0x55, 0xAD, 0xE8, 0x9B, 0xD6,
0x22, 0x57, 0x40, 0xC9, 0xA5, 0x02, 0x03, 0x01,
0x00, 0x01, 0x28, 0x99, 0x20, 0x30, 0x01, 0x12,
0x80, 0x03, 0x21, 0x2D, 0xE1, 0x41, 0xC1, 0x30,
0x57, 0xC1, 0x98, 0x72, 0x18, 0xDD, 0x7F, 0xBC,
0x2D, 0xC9, 0xF8, 0x4C, 0x82, 0xF9, 0x1F, 0x5B,
0x16, 0x3D, 0x03, 0x70, 0xC7, 0x06, 0x93, 0x87,
0xC7, 0x0C, 0x90, 0xC3, 0x06, 0x0F, 0x05, 0x04,
0x57, 0x3C, 0x6E, 0x0B, 0xD3, 0xAC, 0xB9, 0x84,
0xFC, 0x3A, 0xB7, 0xB2, 0x21, 0xA7, 0x7D, 0x37,
0x33, 0x32, 0x4D, 0x67, 0x0A, 0x9A, 0x5E, 0xEA,
0x64, 0x69, 0x1D, 0x56, 0x66, 0xA9, 0xB6, 0x7D,
0xD3, 0x67, 0x80, 0x3C, 0xD5, 0x75, 0x3B, 0xD7,
0x5E, 0xA7, 0x23, 0x9B, 0xEC, 0x0C, 0x00, 0x82,
0x97, 0x69, 0x57, 0x71, 0xCE, 0x20, 0x3C, 0x60,
0x89, 0x8D, 0x4F, 0x26, 0x4A, 0xD5, 0x5D, 0x3D,
0x01, 0xC9, 0x6F, 0x66, 0xD6, 0xFB, 0x6C, 0x53,
0xD1, 0x92, 0x8A, 0x60, 0xAD, 0x04, 0x0D, 0x7D,
0x48, 0xE9, 0xC8, 0x3D, 0x68, 0x49, 0xC2, 0x48,
0xE4, 0x5C, 0x0F, 0x95, 0xBB, 0xB8, 0xCD, 0x0B,
0x1F, 0xEE, 0xE4, 0x45, 0x8C, 0x5C, 0x60, 0xAB,
0x0D, 0x52, 0xE1, 0xFB, 0x0F, 0x8E, 0xE9, 0x87,
0x66, 0xAF, 0x9C, 0xF9, 0x33, 0x07, 0x57, 0x86,
0x57, 0xE8, 0x00, 0xF1, 0xA4, 0xED, 0x3F, 0x6A,
0x00, 0xE8, 0x95, 0x1B, 0x21, 0x58, 0xF4, 0x5C,
0xFC, 0xC2, 0xF7, 0xE5, 0xE5, 0xCC, 0x3D, 0x7F,
0x04, 0xEA, 0x2B, 0xE3, 0x4A, 0xA8, 0xDD, 0x49,
0xEB, 0xD7, 0x8C, 0x61, 0x8C, 0x14, 0x04, 0xE3,
0x08, 0x25, 0x7E, 0x50, 0x2A, 0xAC, 0x8D, 0xF0,
0x0D, 0x52, 0xA8, 0x98, 0x53, 0x01, 0xBF, 0xE5,
0xE6, 0xE7, 0x84, 0xD7, 0x7B, 0x0B, 0xC5, 0x2C,
0x93, 0x5A, 0x8B, 0x18, 0x3F, 0xB5, 0xAF, 0xED,
0x25, 0xA5, 0x85, 0x5A, 0x77, 0xFC, 0xF2, 0x71,
0x5C, 0x90, 0x76, 0x11, 0x62, 0x4A, 0x58, 0xB0,
0x37, 0xD8, 0x19, 0x85, 0x7B, 0xAB, 0x92, 0x6B,
0xEE, 0x4D, 0x56, 0x02, 0x77, 0x08, 0x9E, 0xFB,
0x07, 0x0F, 0xB3, 0xF5, 0x38, 0x5D, 0x1D, 0xDE,
0x1E, 0x48, 0x6D, 0x8F, 0x32, 0xD2, 0x53, 0xDE,
0x86, 0x92, 0xE3, 0x09, 0x8E, 0x35, 0xB3, 0x19,
0x26, 0x47, 0xE7, 0x95, 0x44, 0xCF, 0x0F, 0xB2,
0x8B, 0x36, 0x21, 0x33, 0xE9, 0x42, 0x97, 0x78,
0x1C, 0xF3, 0xF6, 0x89, 0x60, 0x53, 0x16, 0x67,
0xEE, 0x74, 0xE7, 0x02, 0x6B, 0xD7, 0x21, 0x37,
0xEB, 0x1D, 0xDD, 0x05, 0x78, 0x34, 0xCF, 0x1D,
0xAB, 0xE8, 0xD7, 0x06, 0x9F, 0x88, 0xAC, 0xB4,
0xB7, 0xA4, 0x02, 0x47, 0x0F, 0x28, 0x01, 0x26,
0x4B, 0xB4, 0x9C, 0x3B, 0xFE, 0xE2, 0x4F, 0xC6,
0x40, 0xA4, 0x63, 0x74, 0xD6, 0xC1, 0x0B, 0xC7,
0xD2, 0xB9, 0x60, 0x79, 0x2D, 0x11, 0xDA, 0x50,
0x86, 0xAB, 0x8C, 0xCF, 0xF4, 0x61, 0x80, 0xC2,
0x43, 0xC3, 0x95, 0xD2, 0x2F, 0x1A, 0x9E, 0x4F,
0x6B, 0x02, 0x12, 0xA0, 0x0A, 0x2D, 0x2C, 0x09,
0x70, 0xC7, 0xEE, 0xCF, 0x10, 0x8A, 0x67, 0x80,
0x6B, 0xC0, 0x7D, 0x66, 0x49, 0x90, 0x15, 0xFC,
0x96, 0xC1, 0x9E, 0xB9, 0x33, 0x15, 0xAA, 0x16,
0x29, 0x79, 0x3C, 0x79, 0x15, 0x49, 0x8B, 0x6C,
0x1F, 0x76, 0x65, 0xFB, 0xFC, 0x7F, 0xFE, 0x34,
0x1D, 0x97, 0xDB, 0x80, 0xD2, 0x15, 0x20, 0x35,
0x85, 0x45, 0x51, 0x2F, 0x37, 0x87, 0xB0, 0xA6,
0xFC, 0xF4, 0x35, 0x7B, 0x05, 0xB8, 0xC0, 0x1B,
0x30, 0x21, 0x5E, 0xE0, 0x1B, 0x79, 0x66, 0xF8,
0x77, 0x33, 0x11, 0x8D, 0x23, 0xD4, 0x4E, 0xB3,
0x06, 0xAE, 0x09, 0xF6, 0x72, 0x32, 0xDF, 0xA3,
0x99, 0x78, 0x19, 0xD8, 0xFC, 0xB6, 0xB3, 0xAF,
0x46, 0xBB, 0xB2, 0x52, 0x50, 0x4D, 0xDE, 0xF7,
0x9D, 0xD4, 0xB8, 0x7C, 0xEB, 0xD9, 0x94, 0x75,
0x90, 0x4E, 0x83, 0x06, 0x17, 0x0C, 0x33, 0x31,
0x09, 0x73, 0x7B, 0xED, 0x05, 0xFE, 0xE3, 0xC1,
0x4C, 0xA9, 0x25, 0x3F, 0x33, 0x27, 0x17, 0xD0,
0x03, 0x4F, 0x8A, 0x0E, 0x03, 0xBF, 0xE1, 0xD6,
0x5D, 0x0E, 0xBA, 0x51, 0x61, 0x7F, 0x43, 0xA5,
0x46, 0xC7, 0x9E, 0xA3, 0x62, 0xAC, 0xCA, 0xDA,
0x20, 0xE5, 0x4C, 0xB3, 0x3D, 0x9D, 0xF2, 0x0E,
0xF4, 0x08, 0xDF, 0x9C, 0xC0, 0x99, 0xC6, 0xFF,
0xD0, 0x8E, 0x5F, 0x81, 0x72, 0x73, 0x6A, 0xEF,
0xE1, 0xEE, 0x4C, 0x03, 0x77, 0xFF, 0x28, 0xD3,
0x66, 0x19, 0x7D, 0x08, 0xD4, 0x6E, 0x61, 0xC7,
0x59, 0x69, 0x9A, 0xF8, 0xC8, 0xB2, 0xAB, 0xE0,
0xB4, 0x05, 0x45, 0xC2, 0x01, 0xDF, 0x94, 0x7D,
0xC2, 0xA8, 0xC9, 0x9B, 0x30, 0x1A, 0x4E, 0x1B,
0xB2, 0xB2, 0x1C, 0xCE, 0x06, 0x47, 0x9B, 0xCF,
0xA2, 0xF5, 0x56, 0x97, 0x18, 0x96, 0xC0, 0xFE,
0x08, 0x63, 0x75, 0x9C, 0xC0, 0xE6, 0xBC, 0x37,
0x36, 0x13, 0x15, 0x34, 0x60, 0xDB, 0xAF, 0xD1,
0x9F, 0xA7, 0xDD, 0x1D, 0xD2, 0x25, 0x2F, 0xB6,
0x72, 0xC2, 0x13, 0x65, 0x12, 0x08, 0x0F, 0x20,
0x54, 0x2B, 0x7F, 0x33, 0xC2, 0xE6, 0xA9, 0x1D,
0xB6, 0x6C, 0xC5, 0xCA, 0xD6, 0xCC, 0x1B, 0x90,
0xF4, 0x81, 0xD6, 0xDE, 0xB1, 0x87, 0x52, 0xF7,
0x24, 0xD3, 0x46, 0xA2, 0xB4, 0x8F, 0xF9, 0xD3,
0x81, 0xA3, 0x24, 0x79, 0xC0, 0x28, 0xE9, 0xF7,
0x67, 0x2D, 0x8A, 0x6B, 0x05, 0x2D, 0xD9, 0xEE,
0xD2, 0x54, 0x5B, 0x30, 0xA5, 0xC0, 0xC7, 0x85,
0x94, 0x1B, 0xF5, 0xD0, 0xDC, 0x0D, 0x69, 0x10,
0xE7, 0x3A, 0xA3, 0xDB, 0x0F, 0x9B, 0x77, 0x10,
0x75, 0x11, 0x57, 0x64, 0xBB, 0x69, 0x4A, 0x87,
0xC7, 0x3F, 0xD7, 0xB4, 0x74, 0xE4, 0x96, 0xFC,
0xB7, 0x6A, 0xE5, 0x99, 0xBE, 0xD4, 0x36, 0x9D,
0xF4, 0x51, 0xDE, 0xDE, 0xF6, 0x71, 0x72, 0xE4,
0x46, 0x79, 0x4C, 0x04, 0x0F, 0x4D, 0x8C, 0xCB,
0x21, 0xA4, 0x9C, 0xE3, 0xF1, 0x4D, 0x4A, 0xE7,
0xF7, 0x37, 0x1E, 0x91, 0xC5, 0x97, 0x1D, 0xC0,
0x75, 0x21, 0xB0, 0xA1, 0xB5, 0xCF, 0xD5, 0x0A,
0x54, 0x00, 0x81, 0x61, 0x72, 0xC8, 0x1D, 0xBF,
0x0B, 0x16, 0xE7, 0xE0, 0x7D, 0x7E, 0x91, 0xB8,
0x8C, 0x1D, 0xCF, 0x32, 0xB7, 0xCE, 0xB3, 0x4C,
0xE7, 0xD0, 0x53, 0xC5, 0x52, 0x91, 0xDC, 0x04,
0xEC, 0x39, 0xE5, 0x9F, 0x21, 0x0B, 0x36, 0xD7,
0x11, 0x30, 0x89, 0x96, 0x72, 0x3F, 0x9D, 0x3A,
0x7F, 0xC9, 0x9C, 0x51, 0x38, 0x1C, 0xC4, 0x12,
0x9E, 0x8C, 0x59, 0x3D, 0x1F, 0x37, 0x66, 0xF8,
0x42, 0x61, 0xB1, 0xC0, 0x3D, 0xA8, 0xEB, 0xF5,
0xBD, 0x83, 0x31, 0x8F, 0xF9, 0x17, 0x6B, 0xAE,
0xD3, 0x6E, 0x5A, 0x0D, 0x7E, 0x40, 0x82, 0xA1,
0x5B, 0x52, 0xA4, 0x94, 0x76, 0x2E, 0x9D, 0x27,
0x51, 0x0E, 0xEA, 0xD5, 0xC6, 0x65, 0x61, 0x47,
0x8F, 0x67, 0x55, 0x4B, 0x9A, 0x35, 0xBA, 0x40,
0x31, 0x52, 0xFD, 0x7E, 0xE1, 0xE6, 0x7D, 0xFB,
0xBB, 0xCA, 0x33, 0xF3, 0xFA, 0x23, 0xB7, 0x17,
0x5B, 0xE7, 0xD2, 0x93, 0xEB, 0x25, 0x60, 0x73,
0x0B, 0x09, 0x27, 0x48, 0x6C, 0x8E, 0xF6, 0xE7,
0xDF, 0x6D, 0x0D, 0xD7, 0x04, 0xAB, 0x04, 0x64,
0x56, 0x86, 0x79, 0x49, 0x8B, 0xF8, 0xD2, 0xE7,
0x7F, 0x59, 0xAB, 0x90, 0xDE, 0xA1, 0x04, 0x8C,
0x15, 0x24, 0x4C, 0xFA, 0x87, 0x51, 0x1F, 0x12,
0xA2, 0xB3, 0x66, 0x3A, 0x8F, 0x31, 0x9A, 0x08,
0xF4, 0x2C, 0xE2, 0x04, 0x02, 0x12, 0xB3, 0xFF,
0xBF, 0x7E, 0xE0, 0x04, 0x4E, 0x85, 0x51, 0x52,
0xF3, 0x08, 0x09, 0x77, 0x22, 0x54, 0x1E, 0xEC,
0xE8, 0x5B, 0x41, 0x52, 0x43, 0x4D, 0xBF, 0x24,
0x03, 0xAF, 0x4F, 0x3D, 0x58, 0xEE, 0xCD, 0x0E,
0x91, 0x1F, 0x03, 0x55, 0xCA, 0xF5, 0x28, 0x40,
0xB3, 0xA8, 0xAA, 0x7F, 0x5E, 0xD1, 0x67, 0x3D,
0x68, 0xD1, 0xB7, 0x4E, 0xF7, 0x9E, 0xB4, 0x96,
0xED, 0xDF, 0xCA, 0x50, 0x4D, 0x4C, 0xD2, 0xC2,
0xC7, 0x87, 0x5D, 0x1D, 0x85, 0x76, 0xCA, 0x34,
0x1C, 0x47, 0x8B, 0x8F, 0xB2, 0x63, 0x74, 0xDB,
0xB8, 0x99, 0x8B, 0x96, 0x47, 0x87, 0x8A, 0xA7,
0x3A, 0xEB, 0x17, 0x17, 0xEF, 0x59, 0xC1, 0xF6,
0x15, 0x00, 0x78, 0x09, 0x98, 0xB5, 0x52, 0xC1,
0x78, 0x4C, 0xA3, 0x0B, 0xAE, 0xA8, 0xF9, 0xEA,
0xC1, 0xC8, 0x0D, 0x75, 0x91, 0xE5, 0xB4, 0xF7,
0x9D, 0xA8, 0x6B, 0xDA, 0xFA, 0x63, 0xC3, 0xB6,
0x36, 0x9F, 0xB3, 0x78, 0x7D, 0xF0, 0x27, 0xED,
0x45, 0x3F, 0xD9, 0x5D, 0xB3, 0xE7, 0xB3, 0xB7,
0xB0, 0xE6, 0x9E, 0x4F, 0x08, 0xA0, 0xF7, 0x09,
0x22, 0x7D, 0x7D, 0x9F, 0x9C, 0x61, 0xB8, 0xAE,
0x9B, 0x9C, 0xCD, 0x84, 0x9F, 0xBF, 0xEE, 0x8D,
0x40, 0xF4, 0x9A, 0x72, 0x8F, 0xBF, 0xC2, 0xEF,
0xC8, 0x70, 0x8E, 0xAB, 0x10, 0xAC, 0x5B, 0xDA,
0xDC, 0x9F, 0x4E, 0xA0, 0xBA, 0x78, 0xA3, 0x2C,
0x81, 0xF4, 0x2D, 0xCD, 0x35, 0x1E, 0x46, 0xEF,
0x05, 0x24, 0x3A, 0x46, 0xE7, 0x1B, 0xD0, 0xF4,
0x94, 0x5C, 0x58, 0x7B, 0xAC, 0xB4, 0x9E, 0xFF,
0xBD, 0x8D, 0xB0, 0xFB, 0xEB, 0xAC, 0x02, 0x2D,
0xFA, 0x17, 0x6D, 0x92, 0x54, 0x9F, 0x70, 0x4E,
0x7E, 0x30, 0xED, 0x70, 0x42, 0x4B, 0x38, 0x76,
0x82, 0x63, 0x18, 0x77, 0x5F, 0x10, 0x94, 0x6F,
0xD6, 0xA2, 0x3F, 0x27, 0xC0, 0xDC, 0xC9, 0xAA,
0x64, 0xE5, 0x8C, 0x11, 0x31, 0x31, 0x22, 0x40,
0xEB, 0x1D, 0x4E, 0xA6, 0x8D, 0xCF, 0x68, 0x78,
0x8F, 0x84, 0xEF, 0xCB, 0x3D, 0x96, 0x56, 0x9F,
0x1D, 0xFC, 0xF4, 0xFB, 0xBF, 0xB4, 0x9E, 0x39,
0xAB, 0x1B, 0x7F, 0x62, 0xDD, 0x7E, 0x03, 0x8E,
0x3A, 0x16, 0x45, 0xF0, 0x56, 0x9B, 0xAE, 0x9A,
0xFB, 0x3C, 0xC4, 0x81, 0x2B, 0xBA, 0x35, 0xE8,
0x85, 0x20, 0x48, 0x8B, 0xB0, 0x4C, 0x44, 0x85,
0xFA, 0xDB, 0xC2, 0xAE, 0x4E, 0x2D, 0xE5, 0x30,
0x62, 0x6F, 0xC6, 0xEC, 0xD2, 0x1C, 0xE4, 0xF0,
0x1E, 0x71, 0xA3, 0x35, 0x41, 0xF4, 0x3E, 0x2F,
0xDD, 0x36, 0x14, 0x4F, 0x8C, 0xD5, 0x3E, 0x46,
0x81, 0x24, 0x51, 0x93, 0x2B, 0xB0, 0x00, 0x03,
0x93, 0xFE, 0x45, 0x0B, 0x11, 0x6C, 0x36, 0xEA,
0xF3, 0x06, 0xB5, 0xC7, 0xD5, 0x49, 0x1A, 0xB5,
0xD4, 0xBD, 0x97, 0x38, 0x35, 0xE2, 0x84, 0xAC,
0xFC, 0xDE, 0x8C, 0x50, 0xB6, 0x2D, 0x37, 0x21,
0xA8, 0xAE, 0x06, 0x31, 0x70, 0x87, 0x1E, 0xB6,
0x55, 0xB7, 0x5B, 0x28, 0x07, 0x00, 0x00, 0xC7,
0x55, 0xAD, 0xE7, 0xF5, 0xB6, 0xA6, 0x0C, 0xA3,
0x1A, 0x36, 0xAA, 0xC5, 0x37, 0x55, 0x24, 0x9F,
0xD9, 0x1A, 0x75, 0xD3, 0x5C, 0x5E, 0x9A, 0x43,
0xE9, 0x1A, 0xA2, 0x93, 0xAD, 0xD6, 0x3B, 0xD2,
0x2E, 0x82, 0x09, 0xE4, 0x1C, 0x0A, 0x7B, 0x0E,
0x50, 0xCD, 0xAF, 0x00, 0xE6, 0xF4, 0xCF, 0x54,
0xE0, 0xE9, 0xB8, 0x93, 0xF7, 0xD7, 0x64, 0x1A,
0x76, 0x0C, 0x2F, 0x85, 0x67, 0xE6, 0x7C, 0xFA,
0x3C, 0xB8, 0xC7, 0x42, 0xF6, 0x3D, 0x40, 0xDD,
0xBD, 0x2D, 0xC1, 0x0C, 0x2D, 0x17, 0x98, 0xDC,
0x37, 0x7D, 0x02, 0xD7, 0x23, 0x72, 0x09, 0xA5,
0xF2, 0x4C, 0xA3, 0xC8, 0xC9, 0x87, 0x89, 0xE4,
0xCF, 0x88, 0xD8, 0x6F, 0x8F, 0xD7, 0x1E, 0x83,
0x8B, 0x80, 0x11, 0xFE, 0xA8, 0x93, 0xE2, 0xCD,
0x38, 0x8A, 0x88, 0x1E, 0x66, 0x69, 0x3C, 0x98,
0x43, 0xC1, 0x0D, 0x98, 0x8F, 0x34, 0x33, 0x29,
0xC0, 0x33, 0xD0, 0xDD, 0xC1, 0x99, 0x80, 0x47,
0x5B, 0x02, 0xC3, 0x59, 0x04, 0x3F, 0x96, 0xC4,
0x84, 0x8D, 0xE2, 0xF7, 0x04, 0xCD, 0x94, 0xAB,
0x38, 0x82, 0x19, 0x45, 0x69, 0x21, 0x4E, 0x39,
0xB6, 0xF7, 0x78, 0xD5, 0x37, 0x0E, 0x8B, 0x07,
0xD3, 0xFA, 0x60, 0xE7, 0x41, 0x4B, 0xD0, 0x1A,
0xB6, 0x76, 0x61, 0xC0, 0x94, 0x21, 0xD1, 0x47,
0x4D, 0xCC, 0x7E, 0x50, 0x67, 0xA4, 0x2E, 0x93,
0x4D, 0xC5, 0xFE, 0x08, 0x51, 0x60, 0x98, 0x91,
0x65, 0x11, 0x7E, 0x32, 0xA4, 0x15, 0xA0, 0xC6,
0x35, 0xE8, 0xDA, 0xE2, 0xDB, 0x62, 0x8F, 0x9C,
0x5F, 0xF3, 0xF4, 0x27, 0xC0, 0x25, 0x10, 0x74,
0x76, 0x9F, 0x16, 0x13, 0xEC, 0xBF, 0x4A, 0xCE,
0x5D, 0x60, 0xFB, 0xFE, 0x14, 0xF8, 0x18, 0x70,
0xC2, 0x2D, 0xBD, 0x92, 0xAF, 0xEC, 0xAF, 0xE3,
0xAB, 0xA4, 0xBD, 0x7B, 0xDE, 0x47, 0x12, 0x3D,
0x1F, 0x8C, 0x1D, 0x74, 0x66, 0x2B, 0x2E, 0x7B,
0x0C, 0x08, 0xF3, 0x29, 0xCB, 0x89, 0x8D, 0x22,
0x38, 0x70, 0x7A, 0x24, 0xC5, 0x44, 0x28, 0xF7,
0x90, 0x9E, 0xD3, 0xFA, 0x6B, 0x4B, 0xDB, 0x32,
0xE0, 0xBE, 0x65, 0xBF, 0x37, 0x87, 0xF2, 0xA7,
0x6F, 0xB5, 0x48, 0xC4, 0xDE, 0x12, 0x20, 0x2C,
0x88, 0x46, 0x18, 0x74, 0xC2, 0x4A, 0x8A, 0x9F,
0xDF, 0x09, 0x4E, 0xBE, 0x94, 0xB8, 0x94, 0xED,
0xA6, 0x95, 0xCC, 0x54, 0x82, 0xB5, 0x8B, 0xF3,
0xE6, 0xBD, 0xA1, 0xD8, 0xE8, 0x19, 0xB8,
};

View File

@@ -49,7 +49,7 @@ class CdmEngine {
virtual CdmResponseType RestoreKey(const CdmSessionId& session_id,
const CdmKeySetId& key_set_id);
virtual CdmResponseType CancelKeyRequest(const CdmSessionId& session_id);
virtual CdmResponseType RemoveKeys(const CdmSessionId& session_id);
// Construct valid renewal request for the current session keys.
virtual CdmResponseType GenerateRenewalRequest(const CdmSessionId& session_id,

View File

@@ -42,9 +42,6 @@ class CdmSession {
virtual CdmResponseType AddKey(const CdmKeyResponse& key_response,
CdmKeySetId* key_set_id);
// CancelKeyRequest() - Cancel session.
virtual CdmResponseType CancelKeyRequest();
// Query session status
virtual CdmResponseType QueryStatus(CdmQueryMap* key_info);
@@ -94,6 +91,13 @@ class CdmSession {
is_usage_update_needed_ = false;
}
// ReleaseCrypto() - Closes the underlying crypto session but leaves this
// object alive. It is invalid to call any method that requires a crypto
// session after calling this. Since calling this renders this object mostly
// useless, it is preferable to simply delete this object (which will also
// release the underlying crypto session) rather than call this method.
virtual CdmResponseType ReleaseCrypto();
private:
// Internal constructor
void Create(CdmLicense* license_parser, CryptoSession* crypto_session,

View File

@@ -288,18 +288,17 @@ CdmResponseType CdmEngine::RestoreKey(
return sts;
}
CdmResponseType CdmEngine::CancelKeyRequest(const CdmSessionId& session_id) {
LOGI("CdmEngine::CancelKeyRequest");
CdmResponseType CdmEngine::RemoveKeys(const CdmSessionId& session_id) {
LOGI("CdmEngine::RemoveKeys");
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::CancelKeyRequest: session_id not found = %s",
LOGE("CdmEngine::RemoveKeys: session_id not found = %s",
session_id.c_str());
return KEY_ERROR;
}
// Re-initialize to release crypto session/keys without closing session
iter->second->Init();
iter->second->ReleaseCrypto();
return NO_ERROR;
}

View File

@@ -318,12 +318,6 @@ CdmResponseType CdmSession::QueryKeyControlInfo(CdmQueryMap* key_info) {
return NO_ERROR;
}
// CancelKeyRequest() - Cancel session.
CdmResponseType CdmSession::CancelKeyRequest() {
crypto_session_->Close();
return NO_ERROR;
}
// Decrypt() - Accept encrypted buffer and return decrypted data.
CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
if (crypto_session_.get() == NULL || !crypto_session_->IsOpen())
@@ -539,4 +533,9 @@ CdmResponseType CdmSession::UpdateUsageInformation() {
return crypto_session_->UpdateUsageInformation();
}
CdmResponseType CdmSession::ReleaseCrypto() {
crypto_session_->Close();
return NO_ERROR;
}
} // namespace wvcdm