Enable SPOIDs in Treble Widevine Glue Layer

Adds code to the Widevine Glue Layer that drives the generation and use
of SPOIDs on platforms that support SPOIDs. (All devices whose first
release is Android O or later.) Note that this only applies to the new,
Treble-ized API. If the Widevine DRM Plugin is accessed through the old
API, it will not use SPOIDs. This is by design because the old API does
not provide an application package name, so SPOID generation is no
better than the existing, origin-based solution.

Bug: 27101531
Test: Unit tests
Test: GTS tests
Test: Google Play
Change-Id: I80f79fca84065105e218e9070a1d5299c8e33500
This commit is contained in:
John W. Bruce
2017-01-25 18:40:40 -08:00
parent 2dc53442e7
commit d9b90be205
4 changed files with 369 additions and 138 deletions

View File

@@ -9,18 +9,22 @@
#include "WVDrmPlugin.h"
#include "TypeConvert.h"
#include "cutils/properties.h"
#include "mapErrors-inl.h"
#include "media/stagefright/MediaErrors.h"
#include "openssl/sha.h"
#include "utils/List.h"
#include "wv_cdm_constants.h"
namespace {
static const char* const kResetSecurityLevel = "";
static const char* const kEnable = "enable";
static const char* const kDisable = "disable";
static const std::string kPsshTag = "pssh";
static const char* const kSpecialUnprovisionResponse = "unprovision";
}
static const char* const kResetSecurityLevel = "";
static const char* const kEnable = "enable";
static const char* const kDisable = "disable";
static const std::string kPsshTag = "pssh";
static const char* const kSpecialUnprovisionResponse = "unprovision";
} // namespace
namespace wvdrm {
namespace hardware {
@@ -102,11 +106,15 @@ KeyStatusType ConvertFromCdmKeyStatus(CdmKeyStatus keyStatus) {
WVDrmPlugin::WVDrmPlugin(const sp<WvContentDecryptionModule>& cdm,
const std::string& appPackageName,
WVGenericCryptoInterface* crypto)
: mAppPackageName(appPackageName),
mCDM(cdm),
mCdmIdentifier(kDefaultCdmIdentifier),
: mCDM(cdm),
mCrypto(crypto),
mCryptoSessions() {}
mCryptoSessions() {
mCdmIdentifierBuilder.set_app_package_name(appPackageName);
std::string deviceId;
queryProperty(wvcdm::QUERY_KEY_DEVICE_ID, deviceId);
mCdmIdentifierBuilder.set_device_id(deviceId);
}
WVDrmPlugin::~WVDrmPlugin() {
typedef map<CdmSessionId, CryptoSession>::iterator mapIterator;
@@ -127,7 +135,8 @@ Return<void> WVDrmPlugin::openSession(openSession_cb _hidl_cb) {
CdmSessionId cdmSessionId;
CdmResponseType res =
mCDM->OpenSession("com.widevine", &mPropertySet, mCdmIdentifier, this,
mCDM->OpenSession("com.widevine", &mPropertySet,
mCdmIdentifierBuilder.get_identifier(), this,
&cdmSessionId);
if (!isCdmResponseTypeSuccess(res)) {
@@ -269,8 +278,8 @@ Return<void> WVDrmPlugin::getKeyRequest(
CdmKeyRequest keyRequest;
CdmResponseType res = mCDM->GenerateKeyRequest(
cdmSessionId, cdmKeySetId, cdmInitDataType, processedInitData,
cdmLicenseType, cdmParameters, &mPropertySet, mCdmIdentifier,
&keyRequest);
cdmLicenseType, cdmParameters, &mPropertySet,
mCdmIdentifierBuilder.get_identifier(), &keyRequest);
requestType = ConvertFromCdmKeyRequestType(keyRequest.type);
@@ -412,11 +421,9 @@ Return<Status> WVDrmPlugin::restoreKeys(const hidl_vec<uint8_t>& sessionId,
std::string cdmCertAuthority = certificateAuthority;
CdmResponseType res = mCDM->GetProvisioningRequest(cdmCertType,
cdmCertAuthority,
mCdmIdentifier,
&cdmProvisionRequest,
&cdmDefaultUrl);
CdmResponseType res = mCDM->GetProvisioningRequest(
cdmCertType, cdmCertAuthority, mCdmIdentifierBuilder.get_identifier(),
&cdmProvisionRequest, &cdmDefaultUrl);
String8 defaultUrl;
Vector<uint8_t> request;
if (isCdmResponseTypeSuccess(res)) {
@@ -440,21 +447,21 @@ Return<void> WVDrmPlugin::provideProvisionResponse(
CdmProvisioningResponse cdmResponse(resp.begin(), resp.end());
if (cdmResponse == kSpecialUnprovisionResponse) {
if (mCdmIdentifier == kDefaultCdmIdentifier) {
if (mCdmIdentifierBuilder.get_identifier() == kDefaultCdmIdentifier) {
_hidl_cb(toStatus(kErrorNoOriginSpecified), toHidlVec(certificate),
toHidlVec(wrappedKey));
return Void();
}
_hidl_cb(toStatus(unprovision(mCdmIdentifier)), toHidlVec(certificate),
_hidl_cb(toStatus(unprovision(mCdmIdentifierBuilder.get_identifier())),
toHidlVec(certificate),
toHidlVec(wrappedKey));
return Void();
} else {
std::string cdmCertificate;
std::string cdmWrappedKey;
CdmResponseType res = mCDM->HandleProvisioningResponse(mCdmIdentifier,
cdmResponse,
&cdmCertificate,
&cdmWrappedKey);
CdmResponseType res = mCDM->HandleProvisioningResponse(
mCdmIdentifierBuilder.get_identifier(), cdmResponse, &cdmCertificate,
&cdmWrappedKey);
if (isCdmResponseTypeSuccess(res)) {
certificate = StrToVector(cdmCertificate);
wrappedKey = StrToVector(cdmWrappedKey);
@@ -594,7 +601,7 @@ Return<void> WVDrmPlugin::getPropertyString(const hidl_string& propertyName,
} else if (name == "appId") {
value = mPropertySet.app_id().c_str();
} else if (name == "origin") {
value = mCdmIdentifier.origin.c_str();
value = mCdmIdentifierBuilder.origin().c_str();
} else {
ALOGE("App requested unknown string property %s", name.string());
status = android::ERROR_DRM_CANNOT_HANDLE;
@@ -613,7 +620,7 @@ Return<void> WVDrmPlugin::getPropertyByteArray(
Vector<uint8_t> value;
if (name == "deviceUniqueId") {
status = queryProperty(wvcdm::QUERY_KEY_DEVICE_ID, value);
value = StrToVector(mCdmIdentifierBuilder.get_device_unique_id());
} else if (name == "provisioningUniqueId") {
status = queryProperty(wvcdm::QUERY_KEY_PROVISIONING_ID, value);
} else if (name == "serviceCertificate") {
@@ -696,7 +703,9 @@ Return<Status> WVDrmPlugin::setPropertyString(const hidl_string& propertyName,
ALOGE("App tried to set the origin while sessions are opened.");
return toStatus(kErrorSessionIsOpen);
} else {
mCdmIdentifier.origin = _value.string();
if (!mCdmIdentifierBuilder.set_origin(_value.string())) {
return Status::BAD_VALUE;
}
}
} else {
ALOGE("App set unknown string property %s", name.string());
@@ -1242,6 +1251,70 @@ status_t WVDrmPlugin::unprovision(const CdmIdentifier& identifier) {
}
}
// Implementation for the CdmIdentifierBuilder inner class
WVDrmPlugin::CdmIdentifierBuilder::CdmIdentifierBuilder()
: mCdmIdentifier(),
mIsIdentifierSealed(false),
mDeviceId(),
mAppPackageName() {
// Determine if this device supports SPOIDs.
int32_t firstApiLevel = property_get_int32("ro.product.first_api_level", 0);
if (firstApiLevel == 0) {
// First API Level is 0 on factory ROMs, but we can assume the current SDK
// version is the first if it's a factory ROM.
firstApiLevel = property_get_int32("ro.build.version.sdk", 0);
}
// TODO(juce): b/34548395 Make sure this API version is correct.
mUseSpoid = firstApiLevel >= 26; // Android O
}
const CdmIdentifier& WVDrmPlugin::CdmIdentifierBuilder::get_identifier() {
if (!mIsIdentifierSealed) calculateSpoid();
mIsIdentifierSealed = true;
return mCdmIdentifier;
}
const std::string& WVDrmPlugin::CdmIdentifierBuilder::get_device_unique_id() {
if (mUseSpoid) {
return get_identifier().spoid;
} else {
return mDeviceId;
}
}
bool WVDrmPlugin::CdmIdentifierBuilder::set_device_id(const std::string& id) {
if (mIsIdentifierSealed) return false;
mDeviceId = id;
return true;
}
bool WVDrmPlugin::CdmIdentifierBuilder::set_app_package_name(const std::string& id) {
if (mIsIdentifierSealed) return false;
mAppPackageName = id;
return true;
}
bool WVDrmPlugin::CdmIdentifierBuilder::set_origin(const std::string& id) {
if (mIsIdentifierSealed) return false;
mCdmIdentifier.origin = id;
return true;
}
void WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid() {
if (mUseSpoid) {
uint8_t hash[SHA256_DIGEST_LENGTH];
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, mDeviceId.data(), mDeviceId.length());
SHA256_Update(&ctx, mAppPackageName.data(), mAppPackageName.length());
SHA256_Update(&ctx, origin().data(), origin().length());
SHA256_Final(hash, &ctx);
mCdmIdentifier.spoid =
std::string(reinterpret_cast<char*>(hash), SHA256_DIGEST_LENGTH);
}
}
} // namespace widevine
} // namespace V1_0
} // namespace drm