Merge "Allow CE CDM to Create Sessions Without a Service Certificate"

This commit is contained in:
John Bruce
2019-09-17 17:23:45 +00:00
committed by Android (Google) Code Review
12 changed files with 88 additions and 23 deletions

View File

@@ -137,6 +137,10 @@ class CdmEngine {
virtual CdmResponseType RenewKey(const CdmSessionId& session_id, virtual CdmResponseType RenewKey(const CdmSessionId& session_id,
const CdmKeyResponse& key_data); const CdmKeyResponse& key_data);
// Change the service certificate installed in a given session.
virtual CdmResponseType SetSessionServiceCertificate(
const CdmSessionId& session_id, const std::string& service_certificate);
// Query system information // Query system information
virtual CdmResponseType QueryStatus(SecurityLevel security_level, virtual CdmResponseType QueryStatus(SecurityLevel security_level,
const std::string& query_token, const std::string& query_token,

View File

@@ -43,19 +43,23 @@ class CdmSession {
bool IsClosed() { return closed_; } bool IsClosed() { return closed_; }
// Initializes this instance of CdmSession with the given property set. // Initializes this instance of CdmSession with the given property set.
// |cdm_client_property_set| MAY be null, is owned by the caller, //
// and must remain in scope throughout the scope of this session. // |cdm_client_property_set| is caller owned, may be null, but must be in
// scope as long as the session is in scope. The service certificate field is
// cached at the time Init() is called.
virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set); virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set);
// Initializes this instance of CdmSession with the given parmeters. // Initializes this instance of CdmSession with the given parmeters.
// All parameters are owned by the caller. // All parameters are owned by the caller.
// |service_certificate| is caller owned, cannot be null, and must be in //
// scope as long as the session is in scope. // |cdm_client_property_set| is caller owned, may be null, but must be in
// |cdm_client_property_set| is caller owned, may be null, but must be // scope as long as the session is in scope. The service certificate field is
// in scope as long as the session is in scope. // cached at the time Init() is called.
//
// |forced_session_id| is caller owned and may be null. // |forced_session_id| is caller owned and may be null.
// |event_listener| is caller owned, may be null, but must be in scope //
// as long as the session is in scope. // |event_listener| is caller owned, may be null, but must be in scope as long
// as the session is in scope.
virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set, virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set,
const CdmSessionId* forced_session_id, const CdmSessionId* forced_session_id,
WvCdmEventListener* event_listener); WvCdmEventListener* event_listener);
@@ -84,6 +88,11 @@ class CdmSession {
// AddKey() - Accept license response and extract key info. // AddKey() - Accept license response and extract key info.
virtual CdmResponseType AddKey(const CdmKeyResponse& key_response); virtual CdmResponseType AddKey(const CdmKeyResponse& key_response);
// Override the currently-installed service certificate with a new service
// certificate.
virtual CdmResponseType SetServiceCertificate(
const std::string& service_certificate);
// Query session status // Query session status
virtual CdmResponseType QueryStatus(CdmQueryMap* query_response); virtual CdmResponseType QueryStatus(CdmQueryMap* query_response);

View File

@@ -44,6 +44,11 @@ class CdmLicense {
const std::string& signed_service_certificate, const std::string& signed_service_certificate,
CryptoSession* session, PolicyEngine* policy_engine); CryptoSession* session, PolicyEngine* policy_engine);
// Override the currently-installed service certificate with a new service
// certificate.
virtual CdmResponseType SetServiceCertificate(
const std::string& signed_service_certificate);
virtual CdmResponseType PrepareKeyRequest( virtual CdmResponseType PrepareKeyRequest(
const InitializationData& init_data, CdmLicenseType license_type, const InitializationData& init_data, CdmLicenseType license_type,
const CdmAppParameterMap& app_parameters, CdmKeyMessage* signed_request, const CdmAppParameterMap& app_parameters, CdmKeyMessage* signed_request,

View File

@@ -399,7 +399,11 @@ enum CdmResponseType {
REWRAP_DEVICE_RSA_KEY_30_ERROR = 345, REWRAP_DEVICE_RSA_KEY_30_ERROR = 345,
INVALID_SRM_LIST = 346, INVALID_SRM_LIST = 346,
KEYSET_ID_NOT_FOUND_4 = 347, KEYSET_ID_NOT_FOUND_4 = 347,
// Don't forget to add new values to ../test/test_printers.cpp. SESSION_NOT_FOUND_22 = 348,
// Don't forget to add new values to
// * core/test/test_printers.cpp.
// * android/include/mapErrors-inl.h
// * android/include_hidl/mapErrors-inl.h
}; };
enum CdmKeyStatus { enum CdmKeyStatus {

View File

@@ -507,6 +507,19 @@ CdmResponseType CdmEngine::RenewKey(const CdmSessionId& session_id,
return KEY_ADDED; return KEY_ADDED;
} }
CdmResponseType CdmEngine::SetSessionServiceCertificate(
const CdmSessionId& session_id, const std::string& service_certificate) {
LOGI("Setting service certificate: session_id = %s", session_id.c_str());
std::shared_ptr<CdmSession> session;
if (!session_map_.FindSession(session_id, &session)) {
LOGE("Session ID not found: %s", session_id.c_str());
return SESSION_NOT_FOUND_22;
}
return session->SetServiceCertificate(service_certificate);
}
CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level, CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
const std::string& query_token, const std::string& query_token,
std::string* query_response) { std::string* query_response) {

View File

@@ -586,6 +586,11 @@ CdmResponseType CdmSession::QueryStatus(CdmQueryMap* query_response) {
return NO_ERROR; return NO_ERROR;
} }
CdmResponseType CdmSession::SetServiceCertificate(
const std::string& service_certificate) {
return license_parser_->SetServiceCertificate(service_certificate);
}
CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* query_response) { CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* query_response) {
return policy_engine_->Query(query_response); return policy_engine_->Query(query_response);
} }

View File

@@ -226,16 +226,9 @@ bool CdmLicense::Init(const std::string& client_token,
return false; return false;
} }
if (use_privacy_mode) { if (use_privacy_mode && !signed_service_certificate.empty() &&
if (!signed_service_certificate.empty()) { service_certificate_.Init(signed_service_certificate) != NO_ERROR) {
if (service_certificate_.Init(signed_service_certificate) != NO_ERROR) return false;
return false;
}
if (!service_certificate_.has_certificate() &&
!Properties::allow_service_certificate_requests()) {
LOGE("Required service certificate not provided");
return false;
}
} }
client_token_ = client_token; client_token_ = client_token;
@@ -248,6 +241,11 @@ bool CdmLicense::Init(const std::string& client_token,
return true; return true;
} }
CdmResponseType CdmLicense::SetServiceCertificate(
const std::string& signed_service_certificate) {
return service_certificate_.Init(signed_service_certificate);
}
CdmResponseType CdmLicense::PrepareKeyRequest( CdmResponseType CdmLicense::PrepareKeyRequest(
const InitializationData& init_data, CdmLicenseType license_type, const InitializationData& init_data, CdmLicenseType license_type,
const CdmAppParameterMap& app_parameters, CdmKeyMessage* signed_request, const CdmAppParameterMap& app_parameters, CdmKeyMessage* signed_request,

View File

@@ -44,6 +44,8 @@ const std::string kWebmMimeType = "video/webm";
const std::string kEmptyString; const std::string kEmptyString;
const std::string kComma = ","; const std::string kComma = ",";
const std::string kFakeSessionId = "TotallyARealSession123456789";
} // namespace } // namespace
class WvCdmEnginePreProvTest : public WvCdmTestBase { class WvCdmEnginePreProvTest : public WvCdmTestBase {
@@ -317,6 +319,27 @@ TEST_F(WvCdmEnginePreProvTestUat, ProvisioningServiceCertificateInvalidTest) {
ASSERT_NE(cdm_engine_.ValidateServiceCertificate(certificate), NO_ERROR); ASSERT_NE(cdm_engine_.ValidateServiceCertificate(certificate), NO_ERROR);
}; };
TEST_F(WvCdmEngineTest, SetLicensingServiceValidCertificate) {
ASSERT_EQ(cdm_engine_.SetSessionServiceCertificate(
session_id_, config_.license_service_certificate()),
NO_ERROR);
};
TEST_F(WvCdmEngineTest, SetLicensingServiceCertificateUnknownSession) {
ASSERT_EQ(cdm_engine_.SetSessionServiceCertificate(
kFakeSessionId, config_.license_service_certificate()),
SESSION_NOT_FOUND_22);
};
TEST_F(WvCdmEngineTest, SetLicensingServiceInvalidCertificate) {
std::string certificate = config_.license_service_certificate();
// Add four nulls to the beginning of the cert to invalidate it
certificate.insert(0, 4, '\0');
ASSERT_NE(cdm_engine_.SetSessionServiceCertificate(session_id_, certificate),
NO_ERROR);
};
TEST_F(WvCdmEnginePreProvTestStaging, ProvisioningTest) { Provision(); } TEST_F(WvCdmEnginePreProvTestStaging, ProvisioningTest) { Provision(); }
TEST_F(WvCdmEnginePreProvTestUatBinary, ProvisioningTest) { TEST_F(WvCdmEnginePreProvTestUatBinary, ProvisioningTest) {

View File

@@ -282,10 +282,9 @@ TEST_F(CdmLicenseTest, InitWithEmptyServiceCert) {
EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true)); EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true));
CreateCdmLicense(); CreateCdmLicense();
EXPECT_EQ(cdm_license_->Init(kToken, kClientTokenDrmCert, "", true, EXPECT_TRUE(cdm_license_->Init(kToken, kClientTokenDrmCert, "", true,
kEmptyServiceCertificate, crypto_session_, kEmptyServiceCertificate, crypto_session_,
policy_engine_), policy_engine_));
Properties::allow_service_certificate_requests());
} }
TEST_F(CdmLicenseTest, InitWithInvalidServiceCert) { TEST_F(CdmLicenseTest, InitWithInvalidServiceCert) {

View File

@@ -781,6 +781,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case SESSION_NOT_FOUND_21: case SESSION_NOT_FOUND_21:
*os << "SESSION_NOT_FOUND_21"; *os << "SESSION_NOT_FOUND_21";
break; break;
case SESSION_NOT_FOUND_22:
*os << "SESSION_NOT_FOUND_22";
break;
case INVALID_DECRYPT_HASH_FORMAT: case INVALID_DECRYPT_HASH_FORMAT:
*os << "INVALID_DECRYPT_HASH_FORMAT"; *os << "INVALID_DECRYPT_HASH_FORMAT";
break; break;

View File

@@ -231,6 +231,7 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
case wvcdm::SESSION_NOT_FOUND_19: case wvcdm::SESSION_NOT_FOUND_19:
case wvcdm::SESSION_NOT_FOUND_20: case wvcdm::SESSION_NOT_FOUND_20:
case wvcdm::SESSION_NOT_FOUND_21: case wvcdm::SESSION_NOT_FOUND_21:
case wvcdm::SESSION_NOT_FOUND_22:
return android::ERROR_DRM_SESSION_NOT_OPENED; return android::ERROR_DRM_SESSION_NOT_OPENED;
case wvcdm::SESSION_KEYS_NOT_FOUND: case wvcdm::SESSION_KEYS_NOT_FOUND:
return kSessionKeysNotFound; return kSessionKeysNotFound;

View File

@@ -65,6 +65,7 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) {
case wvcdm::SESSION_NOT_FOUND_19: case wvcdm::SESSION_NOT_FOUND_19:
case wvcdm::SESSION_NOT_FOUND_20: case wvcdm::SESSION_NOT_FOUND_20:
case wvcdm::SESSION_NOT_FOUND_21: case wvcdm::SESSION_NOT_FOUND_21:
case wvcdm::SESSION_NOT_FOUND_22:
return Status::ERROR_DRM_SESSION_NOT_OPENED; return Status::ERROR_DRM_SESSION_NOT_OPENED;
case wvcdm::DECRYPT_ERROR: case wvcdm::DECRYPT_ERROR: