Add additional error conditions to MediaDrm
Merge of http://go/wvgerrit/70163 New codes are being added to handle resource contention, lost session state, frame size too large and insufficient security level for decryption. Also cleans up inconsistent use of tamper detected error where invalid state error should have been used. bug:111504510 bug:111505796 test: cts and gts media tests, widevine integration tests Change-Id: I96ee441717d32ccbcabaa85c8f6a0013055ce16e
This commit is contained in:
@@ -9,13 +9,14 @@
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "WVCryptoPlugin.h"
|
||||
#include "TypeConvert.h"
|
||||
|
||||
#include <hidlmemory/mapping.h>
|
||||
|
||||
#include "HidlTypes.h"
|
||||
#include "mapErrors-inl.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "TypeConvert.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "WVErrors.h"
|
||||
|
||||
@@ -23,6 +24,17 @@ namespace {
|
||||
|
||||
static const size_t kAESBlockSize = 16;
|
||||
|
||||
inline Status toStatus_1_0(Status_V1_2 status) {
|
||||
switch (status) {
|
||||
case Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY:
|
||||
case Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE:
|
||||
case Status_V1_2::ERROR_DRM_SESSION_LOST_STATE:
|
||||
return Status::ERROR_DRM_UNKNOWN;
|
||||
default:
|
||||
return static_cast<Status>(status);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvdrm {
|
||||
@@ -31,10 +43,7 @@ namespace drm {
|
||||
namespace V1_2 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::drm::V1_0::BufferType;
|
||||
using ::android::hardware::drm::V1_2::widevine::toVector;
|
||||
using ::android::hardware::Void;
|
||||
|
||||
using android::hardware::drm::V1_2::widevine::toVector;
|
||||
using wvcdm::CdmDecryptionParameters;
|
||||
using wvcdm::CdmQueryMap;
|
||||
using wvcdm::CdmResponseType;
|
||||
@@ -116,8 +125,40 @@ Return<void> WVCryptoPlugin::decrypt(
|
||||
const DestinationBuffer& destination,
|
||||
decrypt_cb _hidl_cb) {
|
||||
|
||||
Status status = Status::ERROR_DRM_UNKNOWN;
|
||||
hidl_string detailedError;
|
||||
uint32_t bytesWritten = 0;
|
||||
|
||||
Return<void> hResult = decrypt_1_2(
|
||||
secure, keyId, iv, mode, pattern, subSamples, source, offset, destination,
|
||||
[&](Status_V1_2 hStatus, uint32_t hBytesWritten, hidl_string hDetailedError) {
|
||||
status = toStatus_1_0(hStatus);
|
||||
if (status == Status::OK) {
|
||||
bytesWritten = hBytesWritten;
|
||||
detailedError = hDetailedError;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
status = hResult.isOk() ? status : Status::ERROR_DRM_CANNOT_HANDLE;
|
||||
_hidl_cb(status, bytesWritten, detailedError);
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> WVCryptoPlugin::decrypt_1_2(
|
||||
bool secure,
|
||||
const hidl_array<uint8_t, 16>& keyId,
|
||||
const hidl_array<uint8_t, 16>& iv,
|
||||
Mode mode,
|
||||
const Pattern& pattern,
|
||||
const hidl_vec<SubSample>& subSamples,
|
||||
const SharedBuffer& source,
|
||||
uint64_t offset,
|
||||
const DestinationBuffer& destination,
|
||||
decrypt_1_2_cb _hidl_cb) {
|
||||
|
||||
if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) {
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
|
||||
_hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
|
||||
"source decrypt buffer base not set");
|
||||
return Void();
|
||||
}
|
||||
@@ -125,7 +166,7 @@ Return<void> WVCryptoPlugin::decrypt(
|
||||
if (destination.type == BufferType::SHARED_MEMORY) {
|
||||
const SharedBuffer& dest = destination.nonsecureMemory;
|
||||
if (mSharedBufferMap.find(dest.bufferId) == mSharedBufferMap.end()) {
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
|
||||
_hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
|
||||
"destination decrypt buffer base not set");
|
||||
return Void();
|
||||
}
|
||||
@@ -134,7 +175,7 @@ Return<void> WVCryptoPlugin::decrypt(
|
||||
if (mode != Mode::UNENCRYPTED &&
|
||||
mode != Mode::AES_CTR &&
|
||||
mode != Mode::AES_CBC) {
|
||||
_hidl_cb(Status::BAD_VALUE,
|
||||
_hidl_cb(Status_V1_2::BAD_VALUE,
|
||||
0, "Encryption mode is not supported by Widevine CDM.");
|
||||
return Void();
|
||||
}
|
||||
@@ -147,12 +188,12 @@ Return<void> WVCryptoPlugin::decrypt(
|
||||
std::string errorDetailMsg;
|
||||
sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId];
|
||||
if (sourceBase == nullptr) {
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source is a nullptr");
|
||||
_hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "source is a nullptr");
|
||||
return Void();
|
||||
}
|
||||
|
||||
if (source.offset + offset + source.size > sourceBase->getSize()) {
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
|
||||
_hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
|
||||
return Void();
|
||||
}
|
||||
|
||||
@@ -164,12 +205,12 @@ Return<void> WVCryptoPlugin::decrypt(
|
||||
const SharedBuffer& destBuffer = destination.nonsecureMemory;
|
||||
sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
|
||||
if (destBase == nullptr) {
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
|
||||
_hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
|
||||
return Void();
|
||||
}
|
||||
|
||||
if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
|
||||
_hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
|
||||
return Void();
|
||||
}
|
||||
destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
|
||||
@@ -218,7 +259,7 @@ Return<void> WVCryptoPlugin::decrypt(
|
||||
const SubSample& subSample = subSamples[i];
|
||||
|
||||
if (mode == Mode::UNENCRYPTED && subSample.numBytesOfEncryptedData != 0) {
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
|
||||
_hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
|
||||
"Encrypted subsamples found in allegedly unencrypted data.");
|
||||
return Void();
|
||||
}
|
||||
@@ -256,9 +297,9 @@ Return<void> WVCryptoPlugin::decrypt(
|
||||
params.decrypt_buffer_offset = bufferOffset;
|
||||
params.subsample_flags = clearFlags;
|
||||
|
||||
Status res = attemptDecrypt(params, haveEncryptedSubsamples,
|
||||
&errorDetailMsg);
|
||||
if (res != Status::OK) {
|
||||
Status_V1_2 res = attemptDecrypt(params, haveEncryptedSubsamples,
|
||||
&errorDetailMsg);
|
||||
if (res != Status_V1_2::OK) {
|
||||
_hidl_cb(res, 0, errorDetailMsg.c_str());
|
||||
return Void();
|
||||
}
|
||||
@@ -275,9 +316,9 @@ Return<void> WVCryptoPlugin::decrypt(
|
||||
params.decrypt_buffer_offset = bufferOffset;
|
||||
params.subsample_flags = encryptedFlags;
|
||||
|
||||
Status res = attemptDecrypt(params, haveEncryptedSubsamples,
|
||||
&errorDetailMsg);
|
||||
if (res != Status::OK) {
|
||||
Status_V1_2 res = attemptDecrypt(params, haveEncryptedSubsamples,
|
||||
&errorDetailMsg);
|
||||
if (res != Status_V1_2::OK) {
|
||||
_hidl_cb(res, 0, errorDetailMsg.c_str());
|
||||
return Void();
|
||||
}
|
||||
@@ -301,7 +342,7 @@ Return<void> WVCryptoPlugin::decrypt(
|
||||
subSample.numBytesOfEncryptedData, pattern, &increment);
|
||||
if (!isCdmResponseTypeSuccess(countRes)) {
|
||||
// Swallow the specifics of the error to obscure decrypt internals.
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
|
||||
_hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
|
||||
"Error decrypting data: unknown error");
|
||||
return Void();
|
||||
}
|
||||
@@ -325,18 +366,17 @@ Return<void> WVCryptoPlugin::decrypt(
|
||||
}
|
||||
}
|
||||
|
||||
_hidl_cb(Status::OK, bufferOffset, errorDetailMsg.c_str());
|
||||
_hidl_cb(Status_V1_2::OK, bufferOffset, errorDetailMsg.c_str());
|
||||
return Void();
|
||||
}
|
||||
|
||||
Status WVCryptoPlugin::attemptDecrypt(const CdmDecryptionParameters& params,
|
||||
bool haveEncryptedSubsamples,
|
||||
std::string* errorDetailMsg) {
|
||||
Status_V1_2 WVCryptoPlugin::attemptDecrypt(const CdmDecryptionParameters& params,
|
||||
bool haveEncryptedSubsamples, std::string* errorDetailMsg) {
|
||||
CdmResponseType res = mCDM->Decrypt(mSessionId, haveEncryptedSubsamples,
|
||||
params);
|
||||
|
||||
if (isCdmResponseTypeSuccess(res)) {
|
||||
return Status::OK;
|
||||
return Status_V1_2::OK;
|
||||
} else {
|
||||
ALOGE("Decrypt error result in session %s during %s block: %d",
|
||||
mSessionId.c_str(),
|
||||
@@ -381,10 +421,10 @@ Status WVCryptoPlugin::attemptDecrypt(const CdmDecryptionParameters& params,
|
||||
|
||||
if (actionableError) {
|
||||
// This error is actionable by the app and should be passed up.
|
||||
return mapCdmResponseType(res);
|
||||
return mapCdmResponseType_1_2(res);
|
||||
} else {
|
||||
// Swallow the specifics of other errors to obscure decrypt internals.
|
||||
return Status::ERROR_DRM_UNKNOWN;
|
||||
return Status_V1_2::ERROR_DRM_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user