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:
Jeff Tinker
2018-12-12 08:52:28 -08:00
parent 40bd0d5209
commit a00b50095c
16 changed files with 390 additions and 217 deletions

View File

@@ -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;
}
}
}