Maxing Out Sessions Can Cause SPOID Failures
(This is a merge of http://go/wvgerrit/25581) To prevent dead DRM Plugins from being instantiated when there are no sessions available, the time at which the device ID is queried has been moved from instantiation-time to SPOID-calculation-time. SPOIDs can now fail to be generated. Which means anything that depends on a SPOID may fail because of this. However, this is a more actionable problem for apps than having them receive a dead or unusable DRM Plugin object. Bug: 36660726 Test: libwvdrmdrmplugin_hidl_test Change-Id: Ice6a8eabfee8d48bf2af02e2e7169aa95af9f2e4
This commit is contained in:
@@ -104,14 +104,10 @@ WVDrmPlugin::WVDrmPlugin(const sp<WvContentDecryptionModule>& cdm,
|
||||
const std::string& appPackageName,
|
||||
WVGenericCryptoInterface* crypto,
|
||||
bool useSpoid)
|
||||
: mCdmIdentifierBuilder(useSpoid, appPackageName),
|
||||
: mCdmIdentifierBuilder(useSpoid, *this, appPackageName),
|
||||
mCDM(cdm),
|
||||
mCrypto(crypto),
|
||||
mCryptoSessions() {
|
||||
std::string deviceId;
|
||||
queryProperty(wvcdm::QUERY_KEY_DEVICE_ID, deviceId);
|
||||
mCdmIdentifierBuilder.set_device_id(deviceId);
|
||||
}
|
||||
mCryptoSessions() {}
|
||||
|
||||
WVDrmPlugin::~WVDrmPlugin() {
|
||||
typedef map<CdmSessionId, CryptoSession>::iterator mapIterator;
|
||||
@@ -130,10 +126,16 @@ Return<void> WVDrmPlugin::openSession(openSession_cb _hidl_cb) {
|
||||
status_t status = android::OK;
|
||||
std::vector<uint8_t> sessionId;
|
||||
|
||||
CdmIdentifier identifier;
|
||||
status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier);
|
||||
if (status != android::OK) {
|
||||
_hidl_cb(toStatus(status), toHidlVec(sessionId));
|
||||
return Void();
|
||||
}
|
||||
|
||||
CdmSessionId cdmSessionId;
|
||||
CdmResponseType res =
|
||||
mCDM->OpenSession("com.widevine", &mPropertySet,
|
||||
mCdmIdentifierBuilder.get_identifier(), this,
|
||||
mCDM->OpenSession("com.widevine", &mPropertySet, identifier, this,
|
||||
&cdmSessionId);
|
||||
|
||||
if (!isCdmResponseTypeSuccess(res)) {
|
||||
@@ -213,6 +215,14 @@ Return<void> WVDrmPlugin::getKeyRequest(
|
||||
std::vector<uint8_t> request;
|
||||
const std::vector<uint8_t> scopeId = toVector(scope);
|
||||
|
||||
CdmIdentifier identifier;
|
||||
status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier);
|
||||
if (status != android::OK) {
|
||||
_hidl_cb(toStatus(status), toHidlVec(request), requestType,
|
||||
defaultUrl.c_str());
|
||||
return Void();
|
||||
}
|
||||
|
||||
CdmLicenseType cdmLicenseType;
|
||||
CdmSessionId cdmSessionId;
|
||||
CdmKeySetId cdmKeySetId;
|
||||
@@ -285,8 +295,7 @@ Return<void> WVDrmPlugin::getKeyRequest(
|
||||
CdmKeyRequest keyRequest;
|
||||
CdmResponseType res = mCDM->GenerateKeyRequest(
|
||||
cdmSessionId, cdmKeySetId, cdmInitDataType, processedInitData,
|
||||
cdmLicenseType, cdmParameters, &mPropertySet,
|
||||
mCdmIdentifierBuilder.get_identifier(), &keyRequest);
|
||||
cdmLicenseType, cdmParameters, &mPropertySet, identifier, &keyRequest);
|
||||
|
||||
requestType = ConvertFromCdmKeyRequestType(keyRequest.type);
|
||||
|
||||
@@ -431,6 +440,16 @@ Return<Status> WVDrmPlugin::restoreKeys(const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_string& certificateType,
|
||||
const hidl_string& certificateAuthority,
|
||||
getProvisionRequest_cb _hidl_cb) {
|
||||
status_t status = android::OK;
|
||||
std::string defaultUrl;
|
||||
std::vector<uint8_t> request;
|
||||
|
||||
CdmIdentifier identifier;
|
||||
status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier);
|
||||
if (status != android::OK) {
|
||||
_hidl_cb(toStatus(status), toHidlVec(request), hidl_string(defaultUrl));
|
||||
return Void();
|
||||
}
|
||||
|
||||
CdmProvisioningRequest cdmProvisionRequest;
|
||||
std::string cdmDefaultUrl;
|
||||
@@ -443,10 +462,8 @@ Return<Status> WVDrmPlugin::restoreKeys(const hidl_vec<uint8_t>& sessionId,
|
||||
std::string cdmCertAuthority = certificateAuthority;
|
||||
|
||||
CdmResponseType res = mCDM->GetProvisioningRequest(
|
||||
cdmCertType, cdmCertAuthority, mCdmIdentifierBuilder.get_identifier(),
|
||||
&cdmProvisionRequest, &cdmDefaultUrl);
|
||||
std::string defaultUrl;
|
||||
std::vector<uint8_t> request;
|
||||
cdmCertType, cdmCertAuthority, identifier, &cdmProvisionRequest,
|
||||
&cdmDefaultUrl);
|
||||
if (isCdmResponseTypeSuccess(res)) {
|
||||
request = StrToVector(cdmProvisionRequest);
|
||||
defaultUrl.clear();
|
||||
@@ -470,14 +487,20 @@ Return<void> WVDrmPlugin::provideProvisionResponse(
|
||||
std::vector<uint8_t> certificate;
|
||||
std::vector<uint8_t> wrappedKey;
|
||||
|
||||
CdmIdentifier identifier;
|
||||
status_t status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier);
|
||||
if (status != android::OK) {
|
||||
_hidl_cb(toStatus(status), toHidlVec(certificate), toHidlVec(wrappedKey));
|
||||
}
|
||||
|
||||
CdmProvisioningResponse cdmResponse(resp.begin(), resp.end());
|
||||
if (cdmResponse == kSpecialUnprovisionResponse) {
|
||||
if (mCdmIdentifierBuilder.get_identifier() == kDefaultCdmIdentifier) {
|
||||
if (identifier == kDefaultCdmIdentifier) {
|
||||
_hidl_cb(toStatus(kErrorNoOriginSpecified), toHidlVec(certificate),
|
||||
toHidlVec(wrappedKey));
|
||||
return Void();
|
||||
}
|
||||
_hidl_cb(toStatus(unprovision(mCdmIdentifierBuilder.get_identifier())),
|
||||
_hidl_cb(toStatus(unprovision(identifier)),
|
||||
toHidlVec(certificate),
|
||||
toHidlVec(wrappedKey));
|
||||
return Void();
|
||||
@@ -485,8 +508,7 @@ Return<void> WVDrmPlugin::provideProvisionResponse(
|
||||
std::string cdmCertificate;
|
||||
std::string cdmWrappedKey;
|
||||
CdmResponseType res = mCDM->HandleProvisioningResponse(
|
||||
mCdmIdentifierBuilder.get_identifier(), cdmResponse, &cdmCertificate,
|
||||
&cdmWrappedKey);
|
||||
identifier, cdmResponse, &cdmCertificate, &cdmWrappedKey);
|
||||
if (isCdmResponseTypeSuccess(res)) {
|
||||
certificate = StrToVector(cdmCertificate);
|
||||
wrappedKey = StrToVector(cdmWrappedKey);
|
||||
@@ -650,7 +672,11 @@ Return<void> WVDrmPlugin::getPropertyByteArray(
|
||||
std::vector<uint8_t> value;
|
||||
|
||||
if (name == "deviceUniqueId") {
|
||||
value = StrToVector(mCdmIdentifierBuilder.get_device_unique_id());
|
||||
std::string id;
|
||||
status = mCdmIdentifierBuilder.getDeviceUniqueId(&id);
|
||||
if (status == android::OK) {
|
||||
value = StrToVector(id);
|
||||
}
|
||||
} else if (name == "provisioningUniqueId") {
|
||||
status = queryProperty(wvcdm::QUERY_KEY_PROVISIONING_ID, value);
|
||||
} else if (name == "serviceCertificate") {
|
||||
@@ -1285,31 +1311,36 @@ status_t WVDrmPlugin::unprovision(const CdmIdentifier& identifier) {
|
||||
|
||||
// Implementation for the CdmIdentifierBuilder inner class
|
||||
WVDrmPlugin::CdmIdentifierBuilder::CdmIdentifierBuilder(
|
||||
bool useSpoid, const std::string& appPackageName)
|
||||
bool useSpoid, const WVDrmPlugin& parent, const std::string& appPackageName)
|
||||
: mCdmIdentifier(),
|
||||
mIsIdentifierSealed(false),
|
||||
mUseSpoid(useSpoid),
|
||||
mDeviceId(),
|
||||
mAppPackageName(appPackageName) {}
|
||||
mAppPackageName(appPackageName),
|
||||
mParent(parent) {}
|
||||
|
||||
const CdmIdentifier& WVDrmPlugin::CdmIdentifierBuilder::get_identifier() {
|
||||
if (!mIsIdentifierSealed) calculateSpoid();
|
||||
mIsIdentifierSealed = true;
|
||||
return mCdmIdentifier;
|
||||
}
|
||||
status_t WVDrmPlugin::CdmIdentifierBuilder::getCdmIdentifier(
|
||||
CdmIdentifier* identifier) {
|
||||
if (!mIsIdentifierSealed) {
|
||||
status_t res = calculateSpoid();
|
||||
if (res != android::OK) return res;
|
||||
|
||||
const std::string& WVDrmPlugin::CdmIdentifierBuilder::get_device_unique_id() {
|
||||
if (mUseSpoid) {
|
||||
return get_identifier().spoid;
|
||||
} else {
|
||||
return mDeviceId;
|
||||
mIsIdentifierSealed = true;
|
||||
}
|
||||
*identifier = mCdmIdentifier;
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
bool WVDrmPlugin::CdmIdentifierBuilder::set_device_id(const std::string& id) {
|
||||
if (mIsIdentifierSealed) return false;
|
||||
mDeviceId = id;
|
||||
return true;
|
||||
status_t WVDrmPlugin::CdmIdentifierBuilder::getDeviceUniqueId(std::string* id) {
|
||||
if (mUseSpoid) {
|
||||
CdmIdentifier identifier;
|
||||
status_t res = getCdmIdentifier(&identifier);
|
||||
if (res != android::OK) return res;
|
||||
|
||||
*id = identifier.spoid;
|
||||
return android::OK;
|
||||
} else {
|
||||
return getOemcryptoDeviceId(id);
|
||||
}
|
||||
}
|
||||
|
||||
bool WVDrmPlugin::CdmIdentifierBuilder::set_origin(const std::string& id) {
|
||||
@@ -1318,12 +1349,16 @@ bool WVDrmPlugin::CdmIdentifierBuilder::set_origin(const std::string& id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid() {
|
||||
status_t WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid() {
|
||||
if (mUseSpoid) {
|
||||
std::string deviceId;
|
||||
status_t res = getOemcryptoDeviceId(&deviceId);
|
||||
if (res != android::OK) return res;
|
||||
|
||||
uint8_t hash[SHA256_DIGEST_LENGTH];
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, mDeviceId.data(), mDeviceId.length());
|
||||
SHA256_Update(&ctx, deviceId.data(), deviceId.length());
|
||||
SHA256_Update(&ctx, mAppPackageName.data(), mAppPackageName.length());
|
||||
SHA256_Update(&ctx, origin().data(), origin().length());
|
||||
SHA256_Final(hash, &ctx);
|
||||
@@ -1331,6 +1366,12 @@ void WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid() {
|
||||
mCdmIdentifier.spoid =
|
||||
std::string(reinterpret_cast<char*>(hash), SHA256_DIGEST_LENGTH);
|
||||
}
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::CdmIdentifierBuilder::getOemcryptoDeviceId(
|
||||
std::string* id) {
|
||||
return mParent.queryProperty(wvcdm::QUERY_KEY_DEVICE_ID, *id);
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
Reference in New Issue
Block a user