Save and retrieve key information from licenses and usage records am: e538c96131
Original change: https://googleplex-android-review.googlesource.com/c/platform/vendor/widevine/+/13947818 Change-Id: I069e5654eba3be908815406d38e270f6188f86e5
This commit is contained in:
@@ -219,6 +219,19 @@ class CdmSession {
|
||||
private:
|
||||
friend class CdmSessionTest;
|
||||
|
||||
// Both these methods will attempt to load wrapped key material and
|
||||
// cache values in |drm_certificate_| and |wrapped_private_key_|
|
||||
// if successful.
|
||||
// This methods will load the key from persistent storage.
|
||||
CdmResponseType LoadPrivateKey();
|
||||
// This method will load the specified key if valid or otherwise load
|
||||
// the information from the legacy certificate.
|
||||
CdmResponseType LoadPrivateOrLegacyKey(
|
||||
const std::string& certificate,
|
||||
const CryptoWrappedKey& wrapped_private_key);
|
||||
|
||||
CdmResponseType LoadPrivateKey(const CryptoWrappedKey& wrapped_private_key);
|
||||
|
||||
bool GenerateKeySetId(bool atsc_mode_enabled, CdmKeySetId* key_set_id);
|
||||
|
||||
CdmResponseType StoreLicense();
|
||||
@@ -273,6 +286,9 @@ class CdmSession {
|
||||
CdmSecurityLevel security_level_;
|
||||
SecurityLevel requested_security_level_;
|
||||
CdmAppParameterMap app_parameters_;
|
||||
bool atsc_mode_enabled_ = false;
|
||||
std::string drm_certificate_;
|
||||
CryptoWrappedKey wrapped_private_key_;
|
||||
|
||||
// decryption flags
|
||||
bool is_initial_decryption_;
|
||||
|
||||
@@ -38,8 +38,7 @@ class CdmLicense {
|
||||
CdmLicense(const CdmSessionId& session_id);
|
||||
virtual ~CdmLicense();
|
||||
|
||||
virtual bool Init(const std::string& client_token,
|
||||
CdmClientTokenType client_token_type, bool use_privacy_mode,
|
||||
virtual bool Init(bool use_privacy_mode,
|
||||
const std::string& signed_service_certificate,
|
||||
CryptoSession* session, PolicyEngine* policy_engine);
|
||||
|
||||
@@ -49,9 +48,9 @@ class CdmLicense {
|
||||
const std::string& signed_service_certificate);
|
||||
|
||||
virtual CdmResponseType PrepareKeyRequest(
|
||||
const InitializationData& init_data, CdmLicenseType license_type,
|
||||
const CdmAppParameterMap& app_parameters, CdmKeyMessage* signed_request,
|
||||
std::string* server_url);
|
||||
const InitializationData& init_data, const std::string& client_token,
|
||||
CdmLicenseType license_type, const CdmAppParameterMap& app_parameters,
|
||||
CdmKeyMessage* signed_request, std::string* server_url);
|
||||
virtual CdmResponseType PrepareKeyUpdateRequest(
|
||||
bool is_renewal, const CdmAppParameterMap& app_parameters,
|
||||
CdmSession* cdm_session, CdmKeyMessage* signed_request,
|
||||
@@ -64,13 +63,13 @@ class CdmLicense {
|
||||
const InitializationData& init_data);
|
||||
|
||||
virtual CdmResponseType RestoreOfflineLicense(
|
||||
const CdmKeyMessage& license_request,
|
||||
const std::string& client_token, const CdmKeyMessage& license_request,
|
||||
const CdmKeyResponse& license_response,
|
||||
const CdmKeyResponse& license_renewal_response,
|
||||
int64_t playback_start_time, int64_t last_playback_time,
|
||||
int64_t grace_period_end_time, CdmSession* cdm_session);
|
||||
virtual CdmResponseType RestoreLicenseForRelease(
|
||||
const CdmKeyMessage& license_request,
|
||||
const std::string& client_token, const CdmKeyMessage& license_request,
|
||||
const CdmKeyResponse& license_response);
|
||||
virtual bool HasInitData() { return static_cast<bool>(stored_init_data_); }
|
||||
virtual bool IsKeyLoaded(const KeyId& key_id);
|
||||
@@ -138,7 +137,6 @@ class CdmLicense {
|
||||
PolicyEngine* policy_engine_;
|
||||
std::string server_url_;
|
||||
std::string client_token_;
|
||||
CdmClientTokenType client_token_type_;
|
||||
const CdmSessionId session_id_;
|
||||
std::unique_ptr<InitializationData> stored_init_data_;
|
||||
bool initialized_;
|
||||
|
||||
@@ -977,7 +977,7 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
const CdmProvisioningResponse& response,
|
||||
SecurityLevel requested_security_level, std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
LOGI("Handling provision request");
|
||||
LOGI("Handling provision response");
|
||||
if (response.empty()) {
|
||||
LOGE("Empty provisioning response");
|
||||
cert_provisioning_.reset();
|
||||
|
||||
@@ -169,56 +169,16 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
|
||||
usage_support_type_ = kNonSecureUsageSupport;
|
||||
}
|
||||
|
||||
// Device Provisioning state is not yet known.
|
||||
// If not using certificates, then Keybox is client token for license
|
||||
// requests.
|
||||
// Otherwise, try to fetch device certificate. If not successful and
|
||||
// provisioning is supported, return NEED_PROVISIONING. Otherwise, return
|
||||
// an error.
|
||||
// client_token and client_token_type are determined here; they are needed
|
||||
// to initialize the license parser.
|
||||
std::string client_token;
|
||||
std::string serial_number;
|
||||
CdmClientTokenType client_token_type =
|
||||
crypto_session_->GetPreProvisionTokenType();
|
||||
|
||||
// License server client ID token is a stored certificate. Stage it or
|
||||
// indicate that provisioning is needed. Get token from stored certificate
|
||||
CryptoWrappedKey private_key;
|
||||
bool atsc_mode_enabled = false;
|
||||
if (cdm_client_property_set != nullptr)
|
||||
atsc_mode_enabled = cdm_client_property_set->use_atsc_mode();
|
||||
if (file_handle_->RetrieveCertificate(
|
||||
atsc_mode_enabled, &client_token, &private_key, &serial_number,
|
||||
nullptr) != DeviceFiles::kCertificateValid) {
|
||||
atsc_mode_enabled_ = cdm_client_property_set->use_atsc_mode();
|
||||
|
||||
if (!file_handle_->HasCertificate(atsc_mode_enabled_))
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
CdmResponseType load_cert_sts;
|
||||
M_TIME(
|
||||
load_cert_sts = crypto_session_->LoadCertificatePrivateKey(private_key),
|
||||
crypto_metrics_, crypto_session_load_certificate_private_key_,
|
||||
load_cert_sts);
|
||||
switch (load_cert_sts) {
|
||||
case NO_ERROR:
|
||||
metrics_->drm_certificate_key_type_.Record(
|
||||
DrmKeyTypeToMetricValue(private_key.type()));
|
||||
break;
|
||||
case SESSION_LOST_STATE_ERROR:
|
||||
case SYSTEM_INVALIDATED_ERROR:
|
||||
return load_cert_sts;
|
||||
default:
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
|
||||
client_token_type = kClientTokenDrmCert;
|
||||
|
||||
// Session is provisioned with certificate needed to construct
|
||||
// license request (or with keybox).
|
||||
|
||||
if (forced_session_id) {
|
||||
key_set_id_ = *forced_session_id;
|
||||
} else {
|
||||
const bool ok = GenerateKeySetId(atsc_mode_enabled, &key_set_id_);
|
||||
const bool ok = GenerateKeySetId(atsc_mode_enabled_, &key_set_id_);
|
||||
assert(ok);
|
||||
if (!ok) {
|
||||
// Assertions may be disabled
|
||||
@@ -247,8 +207,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
|
||||
if (!Properties::GetServiceCertificate(session_id_, &service_certificate))
|
||||
service_certificate.clear();
|
||||
|
||||
if (!license_parser_->Init(client_token, client_token_type,
|
||||
Properties::UsePrivacyMode(session_id_),
|
||||
if (!license_parser_->Init(Properties::UsePrivacyMode(session_id_),
|
||||
service_certificate, crypto_session_.get(),
|
||||
policy_engine_.get()))
|
||||
return LICENSE_PARSER_INIT_ERROR;
|
||||
@@ -337,6 +296,10 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
|
||||
usage_entry_ = std::move(license_data.usage_entry);
|
||||
usage_entry_number_ = license_data.usage_entry_number;
|
||||
|
||||
CdmResponseType status = LoadPrivateOrLegacyKey(
|
||||
license_data.drm_certificate, license_data.wrapped_private_key);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
// Attempts to restore a released offline license are treated as a release
|
||||
// retry.
|
||||
if (Properties::allow_restore_of_offline_licenses_with_release()) {
|
||||
@@ -396,8 +359,8 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
|
||||
|
||||
CdmResponseType result;
|
||||
if (license_type == kLicenseTypeRelease) {
|
||||
result =
|
||||
license_parser_->RestoreLicenseForRelease(key_request_, key_response_);
|
||||
result = license_parser_->RestoreLicenseForRelease(
|
||||
license_data.drm_certificate, key_request_, key_response_);
|
||||
|
||||
if (result != NO_ERROR) {
|
||||
SetErrorDetail(error_detail, result);
|
||||
@@ -405,9 +368,10 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
|
||||
}
|
||||
} else {
|
||||
result = license_parser_->RestoreOfflineLicense(
|
||||
key_request_, key_response_, offline_key_renewal_response_,
|
||||
license_data.playback_start_time, license_data.last_playback_time,
|
||||
license_data.grace_period_end_time, this);
|
||||
license_data.drm_certificate, key_request_, key_response_,
|
||||
offline_key_renewal_response_, license_data.playback_start_time,
|
||||
license_data.last_playback_time, license_data.grace_period_end_time,
|
||||
this);
|
||||
if (result != NO_ERROR) {
|
||||
SetErrorDetail(error_detail, result);
|
||||
return RESTORE_OFFLINE_LICENSE_ERROR_2;
|
||||
@@ -449,6 +413,10 @@ CdmResponseType CdmSession::RestoreUsageSession(
|
||||
usage_entry_number_ = usage_data.usage_entry_number;
|
||||
usage_provider_session_token_ = usage_data.provider_session_token;
|
||||
|
||||
CdmResponseType status = LoadPrivateOrLegacyKey(
|
||||
usage_data.drm_certificate, usage_data.wrapped_private_key);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
CdmResponseType sts = NO_ERROR;
|
||||
if (usage_support_type_ == kUsageEntrySupport &&
|
||||
usage_table_header_ != nullptr) {
|
||||
@@ -461,7 +429,8 @@ CdmResponseType CdmSession::RestoreUsageSession(
|
||||
}
|
||||
}
|
||||
|
||||
sts = license_parser_->RestoreLicenseForRelease(key_request_, key_response_);
|
||||
sts = license_parser_->RestoreLicenseForRelease(usage_data.drm_certificate,
|
||||
key_request_, key_response_);
|
||||
|
||||
if (sts != NO_ERROR) {
|
||||
SetErrorDetail(error_detail, sts);
|
||||
@@ -568,10 +537,13 @@ CdmResponseType CdmSession::GenerateKeyRequestInternal(
|
||||
return KEY_REQUEST_ERROR_1;
|
||||
}
|
||||
|
||||
CdmResponseType status = LoadPrivateKey();
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
app_parameters_ = app_parameters;
|
||||
CdmResponseType status = license_parser_->PrepareKeyRequest(
|
||||
init_data, license_type, app_parameters, &key_request->message,
|
||||
&key_request->url);
|
||||
status = license_parser_->PrepareKeyRequest(
|
||||
init_data, drm_certificate_, license_type, app_parameters,
|
||||
&key_request->message, &key_request->url);
|
||||
if (status != KEY_MESSAGE) return status;
|
||||
|
||||
key_request_ = key_request->message;
|
||||
@@ -1018,12 +990,10 @@ CdmResponseType CdmSession::StoreLicense() {
|
||||
|
||||
std::string app_id;
|
||||
GetApplicationId(&app_id);
|
||||
std::string drm_certificate;
|
||||
CryptoWrappedKey wrapped_private_key;
|
||||
if (!file_handle_->StoreUsageInfo(
|
||||
provider_session_token, key_request_, key_response_,
|
||||
DeviceFiles::GetUsageInfoFileName(app_id), key_set_id_, usage_entry_,
|
||||
usage_entry_number_, drm_certificate, wrapped_private_key)) {
|
||||
usage_entry_number_, drm_certificate_, wrapped_private_key_)) {
|
||||
LOGE("Unable to store usage info");
|
||||
// Usage info file is corrupt. Delete current usage entry and file.
|
||||
if (usage_support_type_ == kUsageEntrySupport) {
|
||||
@@ -1044,7 +1014,6 @@ CdmResponseType CdmSession::StoreLicense() {
|
||||
bool CdmSession::StoreLicense(DeviceFiles::LicenseState state,
|
||||
int* error_detail) {
|
||||
DeviceFiles::ResponseType error_detail_alt = DeviceFiles::kNoError;
|
||||
std::string drm_certificate;
|
||||
DeviceFiles::CdmLicenseData license_data{
|
||||
key_set_id_,
|
||||
state,
|
||||
@@ -1060,8 +1029,8 @@ bool CdmSession::StoreLicense(DeviceFiles::LicenseState state,
|
||||
app_parameters_,
|
||||
usage_entry_,
|
||||
usage_entry_number_,
|
||||
drm_certificate,
|
||||
CryptoWrappedKey()};
|
||||
drm_certificate_,
|
||||
wrapped_private_key_};
|
||||
|
||||
bool result = file_handle_->StoreLicense(license_data, &error_detail_alt);
|
||||
if (error_detail != nullptr) {
|
||||
@@ -1271,6 +1240,83 @@ bool CdmSession::VerifyOfflineUsageEntry() {
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::LoadPrivateKey() {
|
||||
std::string drm_certificate;
|
||||
CryptoWrappedKey private_key;
|
||||
uint32_t system_id;
|
||||
|
||||
if (file_handle_->RetrieveCertificate(atsc_mode_enabled_, &drm_certificate,
|
||||
&private_key, nullptr, &system_id) !=
|
||||
DeviceFiles::kCertificateValid) {
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
|
||||
CdmResponseType status = LoadPrivateKey(private_key);
|
||||
|
||||
if (status == NO_ERROR) {
|
||||
drm_certificate_ = drm_certificate;
|
||||
wrapped_private_key_.set_type(private_key.type());
|
||||
wrapped_private_key_.set_key(private_key.key());
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::LoadPrivateOrLegacyKey(
|
||||
const std::string& certificate, const CryptoWrappedKey& private_key) {
|
||||
// Use provided key if valid
|
||||
if (!certificate.empty() && private_key.IsValid()) {
|
||||
CdmResponseType status = LoadPrivateKey(private_key);
|
||||
|
||||
if (status == NO_ERROR) {
|
||||
drm_certificate_ = certificate;
|
||||
wrapped_private_key_.set_type(private_key.type());
|
||||
wrapped_private_key_.set_key(private_key.key());
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Otherwise use key from legacy certificate
|
||||
std::string drm_certificate;
|
||||
CryptoWrappedKey wrapped_private_key;
|
||||
if (file_handle_->RetrieveLegacyCertificate(
|
||||
&drm_certificate, &wrapped_private_key, nullptr, nullptr) !=
|
||||
DeviceFiles::kCertificateValid)
|
||||
return NEED_PROVISIONING;
|
||||
|
||||
CdmResponseType status = LoadPrivateKey(wrapped_private_key);
|
||||
|
||||
if (status == NO_ERROR) {
|
||||
drm_certificate_ = drm_certificate;
|
||||
wrapped_private_key_.set_type(wrapped_private_key.type());
|
||||
wrapped_private_key_.set_key(wrapped_private_key.key());
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::LoadPrivateKey(
|
||||
const CryptoWrappedKey& private_key) {
|
||||
CdmResponseType load_cert_sts;
|
||||
M_TIME(
|
||||
load_cert_sts = crypto_session_->LoadCertificatePrivateKey(private_key),
|
||||
crypto_metrics_, crypto_session_load_certificate_private_key_,
|
||||
load_cert_sts);
|
||||
|
||||
switch (load_cert_sts) {
|
||||
case NO_ERROR:
|
||||
metrics_->drm_certificate_key_type_.Record(
|
||||
DrmKeyTypeToMetricValue(private_key.type()));
|
||||
return NO_ERROR;
|
||||
case SESSION_LOST_STATE_ERROR:
|
||||
case SYSTEM_INVALIDATED_ERROR:
|
||||
return load_cert_sts;
|
||||
default:
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
}
|
||||
|
||||
// For testing only - takes ownership of pointers
|
||||
|
||||
void CdmSession::set_license_parser(CdmLicense* license_parser) {
|
||||
|
||||
@@ -200,9 +200,7 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id, Clock* clock)
|
||||
|
||||
CdmLicense::~CdmLicense() {}
|
||||
|
||||
bool CdmLicense::Init(const std::string& client_token,
|
||||
CdmClientTokenType client_token_type,
|
||||
bool use_privacy_mode,
|
||||
bool CdmLicense::Init(bool use_privacy_mode,
|
||||
const std::string& signed_service_certificate,
|
||||
CryptoSession* session, PolicyEngine* policy_engine) {
|
||||
if (!clock_) {
|
||||
@@ -213,10 +211,6 @@ bool CdmLicense::Init(const std::string& client_token,
|
||||
LOGE("Session ID not provided");
|
||||
return false;
|
||||
}
|
||||
if (client_token.size() == 0) {
|
||||
LOGE("Client token not provided");
|
||||
return false;
|
||||
}
|
||||
if (session == nullptr || !session->IsOpen()) {
|
||||
LOGE("Crypto session not provided or not open");
|
||||
return false;
|
||||
@@ -231,8 +225,6 @@ bool CdmLicense::Init(const std::string& client_token,
|
||||
return false;
|
||||
}
|
||||
|
||||
client_token_ = client_token;
|
||||
client_token_type_ = client_token_type;
|
||||
crypto_session_ = session;
|
||||
policy_engine_ = policy_engine;
|
||||
use_privacy_mode_ = use_privacy_mode;
|
||||
@@ -247,18 +239,19 @@ CdmResponseType CdmLicense::SetServiceCertificate(
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
const InitializationData& init_data, CdmLicenseType license_type,
|
||||
const CdmAppParameterMap& app_parameters, CdmKeyMessage* signed_request,
|
||||
std::string* server_url) {
|
||||
const InitializationData& init_data, const std::string& client_token,
|
||||
CdmLicenseType license_type, const CdmAppParameterMap& app_parameters,
|
||||
CdmKeyMessage* signed_request, std::string* server_url) {
|
||||
if (!initialized_) {
|
||||
LOGE("CdmLicense not initialized");
|
||||
return LICENSE_PARSER_NOT_INITIALIZED_4;
|
||||
}
|
||||
client_token_ = client_token;
|
||||
if (init_data.IsEmpty() && stored_init_data_) {
|
||||
InitializationData restored_init_data = *stored_init_data_;
|
||||
stored_init_data_.reset();
|
||||
return PrepareKeyRequest(restored_init_data, license_type, app_parameters,
|
||||
signed_request, server_url);
|
||||
return PrepareKeyRequest(restored_init_data, client_token, license_type,
|
||||
app_parameters, signed_request, server_url);
|
||||
}
|
||||
wrapped_keys_ = init_data.ExtractWrappedKeys();
|
||||
if (!init_data.is_supported()) {
|
||||
@@ -793,7 +786,7 @@ CdmResponseType CdmLicense::HandleEmbeddedKeyData(
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::RestoreOfflineLicense(
|
||||
const CdmKeyMessage& license_request,
|
||||
const std::string& client_token, const CdmKeyMessage& license_request,
|
||||
const CdmKeyResponse& license_response,
|
||||
const CdmKeyResponse& license_renewal_response, int64_t playback_start_time,
|
||||
int64_t last_playback_time, int64_t grace_period_end_time,
|
||||
@@ -808,6 +801,8 @@ CdmResponseType CdmLicense::RestoreOfflineLicense(
|
||||
return EMPTY_LICENSE_RESPONSE_3;
|
||||
}
|
||||
|
||||
client_token_ = client_token;
|
||||
|
||||
SignedMessage signed_request;
|
||||
if (!signed_request.ParseFromString(license_request)) {
|
||||
LOGE("Failed to parse license request");
|
||||
@@ -889,7 +884,7 @@ CdmResponseType CdmLicense::RestoreOfflineLicense(
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::RestoreLicenseForRelease(
|
||||
const CdmKeyMessage& license_request,
|
||||
const std::string& client_token, const CdmKeyMessage& license_request,
|
||||
const CdmKeyResponse& license_response) {
|
||||
if (license_request.empty()) {
|
||||
LOGE("License request is empty");
|
||||
@@ -901,6 +896,8 @@ CdmResponseType CdmLicense::RestoreLicenseForRelease(
|
||||
return EMPTY_LICENSE_RESPONSE_4;
|
||||
}
|
||||
|
||||
client_token_ = client_token;
|
||||
|
||||
SignedMessage signed_request;
|
||||
if (!signed_request.ParseFromString(license_request)) {
|
||||
LOGE("Failed to parse signed license request");
|
||||
@@ -1046,6 +1043,11 @@ CdmResponseType CdmLicense::PrepareClientId(
|
||||
const CdmAppParameterMap& app_parameters,
|
||||
const std::string& provider_client_token, LicenseRequest* license_request) {
|
||||
wvcdm::ClientIdentification id;
|
||||
if (client_token_.empty()) {
|
||||
LOGE("Client token not set when preparing client ID");
|
||||
return CLIENT_TOKEN_NOT_SET;
|
||||
}
|
||||
|
||||
CdmResponseType status = id.Init(client_token_, crypto_session_);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ class MockDeviceFiles : public DeviceFiles {
|
||||
DeviceFiles::CertificateState(bool, std::string*,
|
||||
CryptoWrappedKey*, std::string*,
|
||||
uint32_t*));
|
||||
MOCK_METHOD1(HasCertificate, bool(bool));
|
||||
};
|
||||
|
||||
class MockUsageTableHeader : public UsageTableHeader {
|
||||
@@ -169,8 +170,8 @@ class MockCdmLicense : public CdmLicense {
|
||||
public:
|
||||
MockCdmLicense(const CdmSessionId& session_id) : CdmLicense(session_id) {}
|
||||
|
||||
MOCK_METHOD6(Init, bool(const std::string&, CdmClientTokenType, bool,
|
||||
const std::string&, CryptoSession*, PolicyEngine*));
|
||||
MOCK_METHOD4(Init,
|
||||
bool(bool, const std::string&, CryptoSession*, PolicyEngine*));
|
||||
MOCK_METHOD0(provider_session_token, std::string());
|
||||
};
|
||||
|
||||
@@ -218,19 +219,10 @@ TEST_F(CdmSessionTest, InitWithBuiltInCertificate) {
|
||||
EXPECT_CALL(*crypto_session_, GetSecurityLevel())
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(level));
|
||||
EXPECT_CALL(*crypto_session_, GetPreProvisionTokenType())
|
||||
.WillOnce(Return(kClientTokenDrmCert));
|
||||
EXPECT_CALL(*file_handle_,
|
||||
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
|
||||
Return(DeviceFiles::kCertificateValid)));
|
||||
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey))
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*license_parser_,
|
||||
Init(Eq(kToken), Eq(kClientTokenDrmCert), false, Eq(kEmptyString),
|
||||
Eq(crypto_session_), Eq(policy_engine_)))
|
||||
EXPECT_CALL(*file_handle_, HasCertificate(false)).WillOnce(Return(true));
|
||||
EXPECT_CALL(*license_parser_, Init(false, Eq(kEmptyString),
|
||||
Eq(crypto_session_), Eq(policy_engine_)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
ASSERT_EQ(NO_ERROR, cdm_session_->Init(nullptr));
|
||||
@@ -245,19 +237,10 @@ TEST_F(CdmSessionTest, InitWithCertificate) {
|
||||
EXPECT_CALL(*crypto_session_, GetSecurityLevel())
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(level));
|
||||
EXPECT_CALL(*crypto_session_, GetPreProvisionTokenType())
|
||||
.WillOnce(Return(kClientTokenKeybox));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*file_handle_,
|
||||
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
|
||||
Return(DeviceFiles::kCertificateValid)));
|
||||
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey))
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*license_parser_,
|
||||
Init(Eq(kToken), Eq(kClientTokenDrmCert), false, Eq(kEmptyString),
|
||||
Eq(crypto_session_), Eq(policy_engine_)))
|
||||
EXPECT_CALL(*file_handle_, HasCertificate(false)).WillOnce(Return(true));
|
||||
EXPECT_CALL(*license_parser_, Init(false, Eq(kEmptyString),
|
||||
Eq(crypto_session_), Eq(policy_engine_)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
ASSERT_EQ(NO_ERROR, cdm_session_->Init(nullptr));
|
||||
@@ -272,19 +255,10 @@ TEST_F(CdmSessionTest, ReInitFail) {
|
||||
EXPECT_CALL(*crypto_session_, GetSecurityLevel())
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(level));
|
||||
EXPECT_CALL(*crypto_session_, GetPreProvisionTokenType())
|
||||
.WillOnce(Return(kClientTokenKeybox));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*file_handle_,
|
||||
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
|
||||
Return(DeviceFiles::kCertificateValid)));
|
||||
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey))
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*license_parser_,
|
||||
Init(Eq(kToken), Eq(kClientTokenDrmCert), false, Eq(kEmptyString),
|
||||
Eq(crypto_session_), Eq(policy_engine_)))
|
||||
EXPECT_CALL(*file_handle_, HasCertificate(false)).WillOnce(Return(true));
|
||||
EXPECT_CALL(*license_parser_, Init(false, Eq(kEmptyString),
|
||||
Eq(crypto_session_), Eq(policy_engine_)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
ASSERT_EQ(NO_ERROR, cdm_session_->Init(nullptr));
|
||||
@@ -298,25 +272,6 @@ TEST_F(CdmSessionTest, InitFailCryptoError) {
|
||||
ASSERT_EQ(UNKNOWN_ERROR, cdm_session_->Init(nullptr));
|
||||
}
|
||||
|
||||
TEST_F(CdmSessionTest, InitNeedsProvisioning) {
|
||||
Sequence crypto_session_seq;
|
||||
CdmSecurityLevel level = kSecurityLevelL1;
|
||||
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_, GetSecurityLevel())
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(level));
|
||||
EXPECT_CALL(*crypto_session_, GetPreProvisionTokenType())
|
||||
.WillOnce(Return(kClientTokenKeybox));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*file_handle_,
|
||||
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
|
||||
.WillOnce(Return(DeviceFiles::kCertificateInvalid));
|
||||
|
||||
ASSERT_EQ(NEED_PROVISIONING, cdm_session_->Init(nullptr));
|
||||
}
|
||||
|
||||
TEST_F(CdmSessionTest, UpdateUsageEntry) {
|
||||
// Setup common expectations for initializing the CdmSession object.
|
||||
Sequence crypto_session_seq;
|
||||
@@ -327,21 +282,12 @@ TEST_F(CdmSessionTest, UpdateUsageEntry) {
|
||||
EXPECT_CALL(*crypto_session_, GetSecurityLevel())
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(level));
|
||||
EXPECT_CALL(*crypto_session_, GetPreProvisionTokenType())
|
||||
.WillOnce(Return(kClientTokenKeybox));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*file_handle_,
|
||||
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
|
||||
Return(DeviceFiles::kCertificateValid)));
|
||||
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey))
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*file_handle_, HasCertificate(false)).WillOnce(Return(true));
|
||||
EXPECT_CALL(*crypto_session_, GetUsageTableHeader())
|
||||
.WillOnce(Return(&usage_table_header_));
|
||||
EXPECT_CALL(*license_parser_,
|
||||
Init(Eq(kToken), Eq(kClientTokenDrmCert), false, Eq(kEmptyString),
|
||||
Eq(crypto_session_), Eq(policy_engine_)))
|
||||
EXPECT_CALL(*license_parser_, Init(false, Eq(kEmptyString),
|
||||
Eq(crypto_session_), Eq(policy_engine_)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Set up mocks and expectations for the UpdateUsageEntryInformation call.
|
||||
|
||||
@@ -250,22 +250,13 @@ TEST_F(CdmLicenseTest, InitSuccess) {
|
||||
EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true));
|
||||
|
||||
CreateCdmLicense();
|
||||
EXPECT_TRUE(cdm_license_->Init(kToken, kClientTokenDrmCert, false,
|
||||
kEmptyServiceCertificate, crypto_session_,
|
||||
policy_engine_));
|
||||
}
|
||||
|
||||
TEST_F(CdmLicenseTest, InitFail_EmptyToken) {
|
||||
CreateCdmLicense();
|
||||
EXPECT_FALSE(cdm_license_->Init("", kClientTokenDrmCert, false,
|
||||
kEmptyServiceCertificate, crypto_session_,
|
||||
policy_engine_));
|
||||
EXPECT_TRUE(cdm_license_->Init(false, kEmptyServiceCertificate,
|
||||
crypto_session_, policy_engine_));
|
||||
}
|
||||
|
||||
TEST_F(CdmLicenseTest, InitFail_CryptoSessionNull) {
|
||||
CreateCdmLicense();
|
||||
EXPECT_FALSE(cdm_license_->Init(kToken, kClientTokenDrmCert, false,
|
||||
kEmptyServiceCertificate, nullptr,
|
||||
EXPECT_FALSE(cdm_license_->Init(false, kEmptyServiceCertificate, nullptr,
|
||||
policy_engine_));
|
||||
}
|
||||
|
||||
@@ -273,36 +264,32 @@ TEST_F(CdmLicenseTest, InitFail_PolicyEngineNull) {
|
||||
EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true));
|
||||
|
||||
CreateCdmLicense();
|
||||
EXPECT_FALSE(cdm_license_->Init(kToken, kClientTokenDrmCert, false,
|
||||
kEmptyServiceCertificate, crypto_session_,
|
||||
nullptr));
|
||||
EXPECT_FALSE(cdm_license_->Init(false, kEmptyServiceCertificate,
|
||||
crypto_session_, nullptr));
|
||||
}
|
||||
|
||||
TEST_F(CdmLicenseTest, InitWithEmptyServiceCert) {
|
||||
EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true));
|
||||
|
||||
CreateCdmLicense();
|
||||
EXPECT_TRUE(cdm_license_->Init(kToken, kClientTokenDrmCert, true,
|
||||
kEmptyServiceCertificate, crypto_session_,
|
||||
policy_engine_));
|
||||
EXPECT_TRUE(cdm_license_->Init(true, kEmptyServiceCertificate,
|
||||
crypto_session_, policy_engine_));
|
||||
}
|
||||
|
||||
TEST_F(CdmLicenseTest, InitWithInvalidServiceCert) {
|
||||
EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true));
|
||||
|
||||
CreateCdmLicense();
|
||||
EXPECT_FALSE(cdm_license_->Init(kToken, kClientTokenDrmCert, true,
|
||||
kInvalidServiceCertificate, crypto_session_,
|
||||
policy_engine_));
|
||||
EXPECT_FALSE(cdm_license_->Init(true, kInvalidServiceCertificate,
|
||||
crypto_session_, policy_engine_));
|
||||
}
|
||||
|
||||
TEST_F(CdmLicenseTest, InitWithServiceCert) {
|
||||
EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true));
|
||||
|
||||
CreateCdmLicense();
|
||||
EXPECT_TRUE(cdm_license_->Init(kToken, kClientTokenDrmCert, true,
|
||||
kDefaultServiceCertificate, crypto_session_,
|
||||
policy_engine_));
|
||||
EXPECT_TRUE(cdm_license_->Init(true, kDefaultServiceCertificate,
|
||||
crypto_session_, policy_engine_));
|
||||
}
|
||||
|
||||
TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
|
||||
@@ -335,16 +322,15 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
|
||||
Return(NO_ERROR)));
|
||||
|
||||
CreateCdmLicense();
|
||||
EXPECT_TRUE(cdm_license_->Init(kToken, kClientTokenDrmCert, true,
|
||||
kDefaultServiceCertificate, crypto_session_,
|
||||
policy_engine_));
|
||||
EXPECT_TRUE(cdm_license_->Init(true, kDefaultServiceCertificate,
|
||||
crypto_session_, policy_engine_));
|
||||
|
||||
CdmAppParameterMap app_parameters;
|
||||
CdmKeyMessage signed_request;
|
||||
std::string server_url;
|
||||
EXPECT_EQ(cdm_license_->PrepareKeyRequest(*init_data_, kLicenseTypeStreaming,
|
||||
app_parameters, &signed_request,
|
||||
&server_url),
|
||||
EXPECT_EQ(cdm_license_->PrepareKeyRequest(
|
||||
*init_data_, kToken, kLicenseTypeStreaming, app_parameters,
|
||||
&signed_request, &server_url),
|
||||
KEY_MESSAGE);
|
||||
|
||||
EXPECT_TRUE(!signed_request.empty());
|
||||
@@ -460,16 +446,15 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) {
|
||||
Return(NO_ERROR)));
|
||||
|
||||
CreateCdmLicense();
|
||||
EXPECT_TRUE(cdm_license_->Init(kToken, kClientTokenDrmCert, true,
|
||||
kDefaultServiceCertificate, crypto_session_,
|
||||
policy_engine_));
|
||||
EXPECT_TRUE(cdm_license_->Init(true, kDefaultServiceCertificate,
|
||||
crypto_session_, policy_engine_));
|
||||
|
||||
CdmAppParameterMap app_parameters;
|
||||
CdmKeyMessage signed_request;
|
||||
std::string server_url;
|
||||
EXPECT_EQ(cdm_license_->PrepareKeyRequest(*init_data_, kLicenseTypeStreaming,
|
||||
app_parameters, &signed_request,
|
||||
&server_url),
|
||||
EXPECT_EQ(cdm_license_->PrepareKeyRequest(
|
||||
*init_data_, kToken, kLicenseTypeStreaming, app_parameters,
|
||||
&signed_request, &server_url),
|
||||
KEY_MESSAGE);
|
||||
|
||||
EXPECT_TRUE(!signed_request.empty());
|
||||
@@ -601,9 +586,8 @@ TEST_P(CdmLicenseEntitledKeyTest, LoadsEntitledKeys) {
|
||||
|
||||
// Set up the CdmLicense with the mocks and fake entitlement key
|
||||
CreateCdmLicense();
|
||||
EXPECT_TRUE(cdm_license_->Init(kToken, kClientTokenDrmCert, true,
|
||||
kDefaultServiceCertificate, crypto_session_,
|
||||
policy_engine_));
|
||||
EXPECT_TRUE(cdm_license_->Init(true, kDefaultServiceCertificate,
|
||||
crypto_session_, policy_engine_));
|
||||
cdm_license_->set_entitlement_keys(entitlement_license);
|
||||
|
||||
// Call the function under test and check its return value
|
||||
|
||||
@@ -51,6 +51,8 @@ namespace {
|
||||
|
||||
// HTTP response codes.
|
||||
const int kHttpOk = 200;
|
||||
const int kDrmCertificateExpiryPeriod = 150;
|
||||
const std::string kCencMimeType = "video/mp4";
|
||||
|
||||
const wvcdm::CdmIdentifier kExampleIdentifier = {
|
||||
wvcdm::EMPTY_SPOID, "com.example", "com.example", 7, 9};
|
||||
@@ -1747,6 +1749,13 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
|
||||
client_auth->assign(config.client_auth());
|
||||
}
|
||||
|
||||
CdmResponseType GenerateKeyRequest() {
|
||||
CdmAppParameterMap app_parameters;
|
||||
return GenerateKeyRequest(kCencMimeType, binary_key_id(), app_parameters,
|
||||
kLicenseTypeStreaming, kDefaultCdmIdentifier,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void GenerateKeyRequest(const std::string& init_data,
|
||||
CdmLicenseType license_type) {
|
||||
GenerateKeyRequest(init_data, license_type, nullptr);
|
||||
@@ -1794,6 +1803,24 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
|
||||
CdmLicenseType license_type,
|
||||
const CdmIdentifier& cdm_identifier,
|
||||
CdmClientPropertySet* property_set) {
|
||||
CdmResponseType status =
|
||||
GenerateKeyRequest(init_data_type, init_data, app_parameters,
|
||||
license_type, cdm_identifier, property_set);
|
||||
EXPECT_EQ(expected_response, status)
|
||||
<< "session_id_ " << session_id_ << std::endl
|
||||
<< "init_data (hex) " << wvcdm::b2a_hex(init_data) << std::endl
|
||||
<< "cdm_identifier.origin " << cdm_identifier.origin << std::endl
|
||||
<< "cdm_identifier.app_package_name " << cdm_identifier.app_package_name
|
||||
<< std::endl
|
||||
<< "cdm_identifier.unique_id " << cdm_identifier.unique_id << std::endl;
|
||||
}
|
||||
|
||||
CdmResponseType GenerateKeyRequest(const std::string& init_data_type,
|
||||
const std::string& init_data,
|
||||
CdmAppParameterMap& app_parameters,
|
||||
CdmLicenseType license_type,
|
||||
const CdmIdentifier& cdm_identifier,
|
||||
CdmClientPropertySet* property_set) {
|
||||
CdmKeyRequest key_request;
|
||||
std::string key_set_id;
|
||||
license_type_ = license_type;
|
||||
@@ -1801,20 +1828,13 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
|
||||
InitializationData parsed_init_data(init_data_type, init_data);
|
||||
parsed_init_data.DumpToLogs();
|
||||
}
|
||||
EXPECT_EQ(
|
||||
expected_response,
|
||||
decryptor_->GenerateKeyRequest(
|
||||
session_id_, key_set_id, init_data_type, init_data, license_type,
|
||||
app_parameters, property_set, cdm_identifier, &key_request))
|
||||
<< "session_id_ " << session_id_ << std::endl
|
||||
<< "init_data (hex) " << wvcdm::b2a_hex(init_data) << std::endl
|
||||
<< "key_set_id " << key_set_id << std::endl
|
||||
<< "cdm_identifier.origin " << cdm_identifier.origin << std::endl
|
||||
<< "cdm_identifier.app_package_name " << cdm_identifier.app_package_name
|
||||
<< std::endl
|
||||
<< "cdm_identifier.unique_id " << cdm_identifier.unique_id << std::endl;
|
||||
|
||||
CdmResponseType status = decryptor_->GenerateKeyRequest(
|
||||
session_id_, key_set_id, init_data_type, init_data, license_type,
|
||||
app_parameters, property_set, cdm_identifier, &key_request);
|
||||
key_msg_ = key_request.message;
|
||||
EXPECT_EQ(0u, key_request.url.size());
|
||||
return status;
|
||||
}
|
||||
|
||||
void GenerateRenewalRequest(CdmLicenseType license_type,
|
||||
@@ -2027,6 +2047,40 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
|
||||
decryptor_->Unprovision(kSecurityLevelL3, kDefaultCdmIdentifier));
|
||||
}
|
||||
|
||||
bool IsProvisioned(const CdmIdentifier& identifier,
|
||||
SecurityLevel requested_security_level) {
|
||||
TestWvCdmClientPropertySet property_set_L3;
|
||||
TestWvCdmClientPropertySet* property_set = nullptr;
|
||||
|
||||
if (kLevel3 == requested_security_level) {
|
||||
property_set_L3.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
||||
property_set = &property_set_L3;
|
||||
}
|
||||
|
||||
CdmResponseType status = decryptor_->OpenSession(
|
||||
config_.key_system(), property_set, identifier, nullptr, &session_id_);
|
||||
|
||||
if (status == NO_ERROR) {
|
||||
wvcdm::CdmAppParameterMap app_parameters;
|
||||
status =
|
||||
GenerateKeyRequest(kCencMimeType, binary_key_id(), app_parameters,
|
||||
kLicenseTypeStreaming, identifier, nullptr);
|
||||
}
|
||||
|
||||
decryptor_->CloseSession(session_id_);
|
||||
|
||||
switch (status) {
|
||||
case NO_ERROR:
|
||||
case KEY_MESSAGE:
|
||||
return true;
|
||||
case NEED_PROVISIONING:
|
||||
return false;
|
||||
default:
|
||||
EXPECT_EQ(NO_ERROR, status);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Provision() { Provision(kDefaultCdmIdentifier, kLevelDefault); }
|
||||
|
||||
void Provision(const CdmIdentifier& identifier,
|
||||
@@ -2040,24 +2094,13 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
|
||||
property_set = &property_set_L3;
|
||||
}
|
||||
|
||||
CdmResponseType status = decryptor_->OpenSession(
|
||||
config_.key_system(), property_set, identifier, nullptr, &session_id_);
|
||||
switch (status) {
|
||||
case NO_ERROR:
|
||||
decryptor_->CloseSession(session_id_);
|
||||
return;
|
||||
case NEED_PROVISIONING:
|
||||
break;
|
||||
default:
|
||||
EXPECT_EQ(NO_ERROR, status);
|
||||
return;
|
||||
}
|
||||
if (IsProvisioned(identifier, requested_security_level)) return;
|
||||
|
||||
std::string provisioning_server;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
|
||||
status = decryptor_->GetProvisioningRequest(
|
||||
CdmResponseType status = decryptor_->GetProvisioningRequest(
|
||||
cert_type, cert_authority, identifier, kEmptyServiceCertificate,
|
||||
requested_security_level, &key_msg_, &provisioning_server);
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, status);
|
||||
@@ -2169,10 +2212,8 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
||||
Unprovision();
|
||||
EXPECT_EQ(
|
||||
NEED_PROVISIONING,
|
||||
decryptor_->OpenSession(config_.key_system(), nullptr,
|
||||
kDefaultCdmIdentifier, nullptr, &session_id_));
|
||||
EXPECT_FALSE(IsProvisioned(kDefaultCdmIdentifier, kLevelDefault));
|
||||
|
||||
std::string provisioning_server;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
@@ -2195,11 +2236,9 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, ProvisioningTestWithServiceCertificate) {
|
||||
CdmResponseType status =
|
||||
decryptor_->OpenSession(config_.key_system(), nullptr,
|
||||
kDefaultCdmIdentifier, nullptr, &session_id_);
|
||||
EXPECT_TRUE(status == NEED_PROVISIONING || status == NO_ERROR)
|
||||
<< "Failure to open session. error: " << status;
|
||||
Unprovision();
|
||||
EXPECT_FALSE(IsProvisioned(kDefaultCdmIdentifier, kLevelDefault));
|
||||
|
||||
std::string provisioning_server;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
@@ -2222,6 +2261,7 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTestWithServiceCertificate) {
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, L3ProvisioningTest) {
|
||||
Unprovision();
|
||||
TestWvCdmClientPropertySet property_set_L3;
|
||||
property_set_L3.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
||||
std::string provisioning_server;
|
||||
@@ -2246,19 +2286,28 @@ TEST_F(WvCdmRequestLicenseTest, L3ProvisioningTest) {
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, PerOriginProvisioningTest) {
|
||||
Unprovision();
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_->Unprovision(kSecurityLevelL3, kExampleIdentifier));
|
||||
Provision();
|
||||
|
||||
// Verify the global identifier is provisioned.
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->OpenSession(
|
||||
config_.key_system(), nullptr,
|
||||
kDefaultCdmIdentifier, nullptr, &session_id_));
|
||||
|
||||
CdmAppParameterMap app_parameters;
|
||||
EXPECT_EQ(KEY_MESSAGE,
|
||||
GenerateKeyRequest(kCencMimeType, binary_key_id(), app_parameters,
|
||||
kLicenseTypeStreaming, kDefaultCdmIdentifier,
|
||||
nullptr));
|
||||
decryptor_->CloseSession(session_id_);
|
||||
|
||||
// The other identifier should not be provisioned.
|
||||
EXPECT_EQ(wvcdm::NEED_PROVISIONING,
|
||||
decryptor_->OpenSession(config_.key_system(), nullptr,
|
||||
kExampleIdentifier, nullptr, &session_id_));
|
||||
EXPECT_FALSE(IsProvisioned(kExampleIdentifier, kLevelDefault));
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, PerOriginProvisioningSupportsOldPaths) {
|
||||
@@ -2588,6 +2637,42 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningRevocationTest) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, ProvisioningWithExpiringCertTest) {
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_->Unprovision(kSecurityLevelL1, kExampleIdentifier));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_->Unprovision(kSecurityLevelL3, kExampleIdentifier));
|
||||
|
||||
EXPECT_FALSE(IsProvisioned(kExampleIdentifier, kLevelDefault));
|
||||
ConfigTestEnv config(kContentProtectionStagingServer, true);
|
||||
|
||||
// Provision
|
||||
std::string provisioning_server;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->GetProvisioningRequest(
|
||||
cert_type, cert_authority, kExampleIdentifier,
|
||||
kEmptyServiceCertificate, kLevelDefault,
|
||||
&key_msg_, &provisioning_server));
|
||||
|
||||
std::string response = GetCertRequestResponse(config.provisioning_server());
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->HandleProvisioningResponse(
|
||||
kExampleIdentifier, response, kLevelDefault,
|
||||
&cert, &wrapped_key));
|
||||
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||
decryptor_->CloseSession(session_id_);
|
||||
|
||||
// Make sure it is provisioned, then wait for certificate expiry period
|
||||
EXPECT_TRUE(IsProvisioned(kExampleIdentifier, kLevelDefault));
|
||||
sleep(kDrmCertificateExpiryPeriod);
|
||||
|
||||
// Verify that it is no longer provisioned after the certificate expires
|
||||
EXPECT_FALSE(IsProvisioned(kExampleIdentifier, kLevelDefault));
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, PropertySetTest) {
|
||||
TestWvCdmClientPropertySet property_set_L1;
|
||||
TestWvCdmClientPropertySet property_set_L3;
|
||||
@@ -2760,6 +2845,48 @@ TEST_F(WvCdmRequestLicenseTest, AddStreamingKeyTest) {
|
||||
decryptor_->CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, StreamingWithExpiringCertTest) {
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_->Unprovision(kSecurityLevelL1, kExampleIdentifier));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_->Unprovision(kSecurityLevelL3, kExampleIdentifier));
|
||||
|
||||
EXPECT_FALSE(IsProvisioned(kExampleIdentifier, kLevelDefault));
|
||||
ConfigTestEnv config(kContentProtectionStagingServer, true);
|
||||
|
||||
// Provision
|
||||
std::string provisioning_server;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->GetProvisioningRequest(
|
||||
cert_type, cert_authority, kExampleIdentifier,
|
||||
kEmptyServiceCertificate, kLevelDefault,
|
||||
&key_msg_, &provisioning_server));
|
||||
|
||||
std::string response = GetCertRequestResponse(config.provisioning_server());
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->HandleProvisioningResponse(
|
||||
kExampleIdentifier, response, kLevelDefault,
|
||||
&cert, &wrapped_key));
|
||||
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||
|
||||
EXPECT_TRUE(IsProvisioned(kExampleIdentifier, kLevelDefault));
|
||||
|
||||
// Fetch a streaming license
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_->OpenSession(config_.key_system(), nullptr,
|
||||
kExampleIdentifier, nullptr, &session_id_));
|
||||
|
||||
CdmAppParameterMap app_parameters;
|
||||
GenerateKeyRequest(KEY_MESSAGE, kCencMimeType, binary_key_id(),
|
||||
app_parameters, kLicenseTypeStreaming, kExampleIdentifier,
|
||||
nullptr);
|
||||
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth());
|
||||
decryptor_->CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, AddKeyOfflineTest) {
|
||||
Unprovision();
|
||||
Provision();
|
||||
@@ -2801,6 +2928,68 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) {
|
||||
decryptor_->CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeysWithExpiringCertTest) {
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_->Unprovision(kSecurityLevelL1, kExampleIdentifier));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_->Unprovision(kSecurityLevelL3, kExampleIdentifier));
|
||||
|
||||
EXPECT_FALSE(IsProvisioned(kExampleIdentifier, kLevelDefault));
|
||||
ConfigTestEnv config(kContentProtectionStagingServer, true);
|
||||
|
||||
// Provision
|
||||
std::string provisioning_server;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->GetProvisioningRequest(
|
||||
cert_type, cert_authority, kExampleIdentifier,
|
||||
kEmptyServiceCertificate, kLevelDefault,
|
||||
&key_msg_, &provisioning_server));
|
||||
|
||||
std::string response = GetCertRequestResponse(config.provisioning_server());
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->HandleProvisioningResponse(
|
||||
kExampleIdentifier, response, kLevelDefault,
|
||||
&cert, &wrapped_key));
|
||||
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||
|
||||
EXPECT_TRUE(IsProvisioned(kExampleIdentifier, kLevelDefault));
|
||||
|
||||
std::string key_id;
|
||||
std::string client_auth;
|
||||
GetOfflineConfiguration(&key_id, &client_auth);
|
||||
|
||||
// Fetch offline license
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_->OpenSession(config_.key_system(), nullptr,
|
||||
kExampleIdentifier, nullptr, &session_id_));
|
||||
|
||||
CdmAppParameterMap app_parameters;
|
||||
GenerateKeyRequest(KEY_MESSAGE, kCencMimeType, key_id, app_parameters,
|
||||
kLicenseTypeOffline, kExampleIdentifier, nullptr);
|
||||
VerifyKeyRequestResponse(config_.license_server(), client_auth);
|
||||
|
||||
CdmKeySetId key_set_id = key_set_id_;
|
||||
EXPECT_FALSE(key_set_id_.empty());
|
||||
decryptor_->CloseSession(session_id_);
|
||||
|
||||
session_id_.clear();
|
||||
|
||||
// Wait till certificate expires
|
||||
sleep(kDrmCertificateExpiryPeriod);
|
||||
|
||||
// Make sure the certificate has expired and the device is not provisioned
|
||||
EXPECT_FALSE(IsProvisioned(kExampleIdentifier, kLevelDefault));
|
||||
|
||||
// Restore offline license
|
||||
decryptor_->OpenSession(config_.key_system(), nullptr, kExampleIdentifier,
|
||||
nullptr, &session_id_);
|
||||
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_->RestoreKey(session_id_, key_set_id));
|
||||
decryptor_->CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, DisallowMultipleRestoreOfflineKeyTest) {
|
||||
Unprovision();
|
||||
Provision();
|
||||
@@ -2987,11 +3176,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
|
||||
std::string client_auth;
|
||||
GetOfflineConfiguration(&key_id, &client_auth);
|
||||
|
||||
CdmResponseType sts =
|
||||
decryptor_->OpenSession(config_.key_system(), &property_set,
|
||||
kDefaultCdmIdentifier, nullptr, &session_id_);
|
||||
|
||||
if (NEED_PROVISIONING == sts) {
|
||||
if (!IsProvisioned(kDefaultCdmIdentifier, kLevel3)) {
|
||||
std::string provisioning_server;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
@@ -3009,8 +3194,6 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
|
||||
EXPECT_EQ(NO_ERROR, decryptor_->OpenSession(
|
||||
config_.key_system(), &property_set,
|
||||
kDefaultCdmIdentifier, nullptr, &session_id_));
|
||||
} else {
|
||||
EXPECT_EQ(NO_ERROR, sts);
|
||||
}
|
||||
|
||||
decryptor_->OpenSession(config_.key_system(), &property_set,
|
||||
@@ -3063,11 +3246,7 @@ TEST_F(WvCdmRequestLicenseTest,
|
||||
GetOfflineConfiguration(&key_id, &client_auth);
|
||||
key_id[key_id.size() - 1] = '1';
|
||||
|
||||
CdmResponseType sts =
|
||||
decryptor_->OpenSession(config_.key_system(), &property_set,
|
||||
kDefaultCdmIdentifier, nullptr, &session_id_);
|
||||
|
||||
if (NEED_PROVISIONING == sts) {
|
||||
if (!IsProvisioned(kDefaultCdmIdentifier, kLevel3)) {
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
@@ -3085,8 +3264,6 @@ TEST_F(WvCdmRequestLicenseTest,
|
||||
EXPECT_EQ(NO_ERROR, decryptor_->OpenSession(
|
||||
config_.key_system(), &property_set,
|
||||
kDefaultCdmIdentifier, nullptr, &session_id_));
|
||||
} else {
|
||||
EXPECT_EQ(NO_ERROR, sts);
|
||||
}
|
||||
|
||||
decryptor_->OpenSession(config_.key_system(), &property_set,
|
||||
|
||||
@@ -103,7 +103,7 @@ TEST_F(WvContentDecryptionModuleMetricsTest, EngineAndSessionMetrics) {
|
||||
wvcdm::CdmKeySystem key_system("com.widevine");
|
||||
Unprovision(kDefaultCdmIdentifier);
|
||||
|
||||
// Openning the session will fail with NEEDS_PROVISIONING error. But it will
|
||||
// Opening the session will fail with NEEDS_PROVISIONING error. But it will
|
||||
// still create some session-level stats.
|
||||
EXPECT_EQ(CdmResponseType::NEED_PROVISIONING,
|
||||
decryptor_.OpenSession(key_system, nullptr, kDefaultCdmIdentifier,
|
||||
@@ -133,11 +133,6 @@ TEST_F(WvContentDecryptionModuleMetricsTest, EngineAndSessionMetrics) {
|
||||
|
||||
// Validate a session-level metric.
|
||||
ASSERT_THAT(metrics.session_metrics().size(), Eq(1));
|
||||
EXPECT_THAT(
|
||||
metrics.session_metrics(0).cdm_session_life_span_ms().double_value(),
|
||||
Gt(0.0))
|
||||
<< "Unexpected failure with session_metrics: "
|
||||
<< wvcdm::b2a_hex(serialized_metrics);
|
||||
}
|
||||
|
||||
TEST_F(WvContentDecryptionModuleMetricsTest,
|
||||
@@ -190,11 +185,6 @@ TEST_F(WvContentDecryptionModuleMetricsTest,
|
||||
ASSERT_THAT(metrics.session_metrics().size(), Eq(i + 1))
|
||||
<< "Unexpected failure with session_metrics: "
|
||||
<< wvcdm::b2a_hex(serialized_metrics);
|
||||
EXPECT_THAT(
|
||||
metrics.session_metrics(0).cdm_session_life_span_ms().double_value(),
|
||||
Gt(0.0))
|
||||
<< "Unexpected failure with session_metrics: "
|
||||
<< wvcdm::b2a_hex(serialized_metrics);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user